1. /*
  2. * @(#)file SnmpRequestHandler.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.31
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. *
  10. */
  11. package com.sun.jmx.snmp.daemon;
  12. // java import
  13. //
  14. import java.util.Vector;
  15. import java.util.Enumeration;
  16. import java.util.Hashtable;
  17. import java.io.InterruptedIOException;
  18. import java.net.DatagramSocket;
  19. import java.net.DatagramPacket;
  20. import java.net.SocketException;
  21. // jmx imports
  22. //
  23. import javax.management.MBeanServer;
  24. import javax.management.ObjectName;
  25. import com.sun.jmx.snmp.SnmpMessage;
  26. import com.sun.jmx.snmp.SnmpPduFactory;
  27. import com.sun.jmx.snmp.SnmpPduBulk;
  28. import com.sun.jmx.snmp.SnmpPduPacket;
  29. import com.sun.jmx.snmp.SnmpPduRequest;
  30. import com.sun.jmx.snmp.SnmpPduTrap;
  31. import com.sun.jmx.snmp.SnmpValue;
  32. import com.sun.jmx.snmp.SnmpVarBind;
  33. import com.sun.jmx.snmp.SnmpVarBindList;
  34. import com.sun.jmx.snmp.SnmpDefinitions;
  35. import com.sun.jmx.snmp.SnmpStatusException;
  36. import com.sun.jmx.snmp.SnmpTooBigException;
  37. import com.sun.jmx.snmp.SnmpDataTypeEnums;
  38. // RI imports
  39. //
  40. import com.sun.jmx.trace.Trace;
  41. // SNMP runtime import
  42. //
  43. import com.sun.jmx.snmp.agent.SnmpMibAgent;
  44. import com.sun.jmx.snmp.agent.SnmpUserDataFactory;
  45. //import com.sun.jmx.snmp.IPAcl.IPAcl;
  46. import com.sun.jmx.snmp.InetAddressAcl;
  47. class SnmpRequestHandler extends ClientHandler implements SnmpDefinitions {
  48. private transient DatagramSocket socket = null ;
  49. private transient DatagramPacket packet = null ;
  50. private transient Vector mibs = null ;
  51. /**
  52. * Contains the list of sub-requests associated to the current request.
  53. */
  54. private transient Hashtable subs = null ;
  55. /**
  56. * Reference on the MIBS
  57. */
  58. private transient SnmpMibTree root;
  59. private transient Object ipacl = null ;
  60. private transient SnmpPduFactory pduFactory = null ;
  61. private transient SnmpUserDataFactory userDataFactory = null ;
  62. private transient SnmpAdaptorServer adaptor = null;
  63. /**
  64. * Full constructor
  65. */
  66. public SnmpRequestHandler(SnmpAdaptorServer server, int id,
  67. DatagramSocket s, DatagramPacket p,
  68. SnmpMibTree tree, Vector m, Object a,
  69. SnmpPduFactory factory,
  70. SnmpUserDataFactory dataFactory,
  71. MBeanServer f, ObjectName n)
  72. {
  73. super(server, id, f, n);
  74. // Need a reference on SnmpAdaptorServer for getNext & getBulk,
  75. // in case of oid equality (mib overlapping).
  76. //
  77. adaptor = server;
  78. socket = s;
  79. packet = p;
  80. root= tree;
  81. mibs = (Vector) m.clone();
  82. subs= new Hashtable(mibs.size());
  83. ipacl = a;
  84. pduFactory = factory ;
  85. userDataFactory = dataFactory ;
  86. //thread.start();
  87. }
  88. /**
  89. * Treat the request available in 'packet' and send the result
  90. * back to the client.
  91. * Note: we overwrite 'packet' with the response bytes.
  92. */
  93. public void doRun() {
  94. // Trace the input packet
  95. //
  96. if (isTraceOn()) {
  97. trace("doRun", "Packet received:\n" + SnmpMessage.dumpHexBuffer(packet.getData(), 0, packet.getLength()));
  98. }
  99. // Let's build the response packet
  100. //
  101. DatagramPacket respPacket = makeResponsePacket(packet) ;
  102. // Trace the output packet
  103. //
  104. if (isTraceOn() && (respPacket != null)) {
  105. trace("doRun", "Packet to be sent:\n" + SnmpMessage.dumpHexBuffer(respPacket.getData(), 0, respPacket.getLength()));
  106. }
  107. // Send the response packet if any
  108. //
  109. if (respPacket != null) {
  110. try {
  111. socket.send(respPacket) ;
  112. }
  113. catch (SocketException e) {
  114. if (isDebugOn()) {
  115. if (e.getMessage().equals(InterruptSysCallMsg))
  116. debug("doRun", "interrupted");
  117. else {
  118. debug("doRun", "i/o exception");
  119. debug("doRun", e);
  120. }
  121. }
  122. }
  123. catch(InterruptedIOException e) {
  124. if (isDebugOn()) {
  125. debug("doRun", "interrupted");
  126. }
  127. }
  128. catch(Exception e) {
  129. if (isDebugOn()) {
  130. debug("doRun", "failure when sending response");
  131. debug("doRun", e);
  132. }
  133. }
  134. }
  135. }
  136. /**
  137. * Here we make a response packet from a request packet.
  138. * We return null if there no response packet to sent.
  139. */
  140. private DatagramPacket makeResponsePacket(DatagramPacket reqPacket) {
  141. DatagramPacket respPacket = null ;
  142. // Transform the request packet into a request SnmpMessage
  143. //
  144. SnmpMessage reqMsg = new SnmpMessage() ;
  145. try {
  146. reqMsg.decodeMessage(reqPacket.getData(), reqPacket.getLength()) ;
  147. reqMsg.address = reqPacket.getAddress() ;
  148. reqMsg.port = reqPacket.getPort() ;
  149. }
  150. catch(SnmpStatusException x) {
  151. if (isDebugOn()) {
  152. debug("makeResponsePacket", "packet decoding failed");
  153. debug("makeResponsePacket", x);
  154. }
  155. reqMsg = null ;
  156. ((SnmpAdaptorServer)adaptorServer).incSnmpInASNParseErrs(1) ;
  157. }
  158. // Make the response SnmpMessage if any
  159. //
  160. SnmpMessage respMsg = null ;
  161. if (reqMsg != null) {
  162. respMsg = makeResponseMessage(reqMsg) ;
  163. }
  164. // Try to transform the response SnmpMessage into response packet.
  165. // NOTE: we overwrite the request packet.
  166. //
  167. if (respMsg != null) {
  168. try {
  169. reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
  170. respPacket = reqPacket ;
  171. }
  172. catch(SnmpTooBigException x) {
  173. if (isDebugOn()) {
  174. debug("makeResponsePacket", "response message is too big");
  175. }
  176. try {
  177. respMsg = newTooBigMessage(reqMsg) ;
  178. reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ;
  179. respPacket = reqPacket ;
  180. }
  181. catch(SnmpTooBigException xx) {
  182. if (isDebugOn()) {
  183. debug("makeResponsePacket", "'too big' is 'too big' !!!");
  184. }
  185. adaptor.incSnmpSilentDrops(1);
  186. }
  187. }
  188. }
  189. return respPacket ;
  190. }
  191. /**
  192. * Here we make a response message from a request message.
  193. * We return null if there is no message to reply.
  194. */
  195. private SnmpMessage makeResponseMessage(SnmpMessage reqMsg) {
  196. SnmpMessage respMsg = null ;
  197. // Transform the request message into a request pdu
  198. //
  199. SnmpPduPacket reqPdu = null ;
  200. Object userData = null;
  201. try {
  202. reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
  203. if (reqPdu != null && userDataFactory != null)
  204. userData = userDataFactory.allocateUserData(reqPdu);
  205. }
  206. catch(SnmpStatusException x) {
  207. reqPdu = null ;
  208. SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
  209. snmpServer.incSnmpInASNParseErrs(1) ;
  210. if (x.getStatus()== SnmpDefinitions.snmpWrongSnmpVersion)
  211. snmpServer.incSnmpInBadVersions(1) ;
  212. if (isDebugOn()) {
  213. debug("makeResponseMessage", "message decoding failed");
  214. debug("makeResponseMessage",x);
  215. }
  216. }
  217. // Make the response pdu if any
  218. //
  219. SnmpPduPacket respPdu = null ;
  220. if (reqPdu != null) {
  221. respPdu = makeResponsePdu(reqPdu,userData) ;
  222. try {
  223. if (userDataFactory != null)
  224. userDataFactory.releaseUserData(userData,respPdu);
  225. } catch (SnmpStatusException x) {
  226. respPdu = null;
  227. }
  228. }
  229. // Try to transform the response pdu into a response message if any
  230. //
  231. if (respPdu != null) {
  232. try {
  233. respMsg = (SnmpMessage)pduFactory.
  234. encodeSnmpPdu(respPdu, packet.getData().length) ;
  235. }
  236. catch(SnmpStatusException x) {
  237. respMsg = null ;
  238. if (isDebugOn()) {
  239. debug("makeResponseMessage",
  240. "failure when encoding the response message");
  241. debug("makeResponseMessage", x);
  242. }
  243. }
  244. catch(SnmpTooBigException x) {
  245. if (isDebugOn()) {
  246. debug("makeResponseMessage",
  247. "response message is too big");
  248. }
  249. try {
  250. // if the PDU is too small, why should we try to do
  251. // recovery ?
  252. //
  253. if (packet.getData().length <=32)
  254. throw x;
  255. int pos= x.getVarBindCount();
  256. if (isDebugOn()) {
  257. debug("makeResponseMessage", "fail on element" + pos);
  258. }
  259. int old= 0;
  260. while (true) {
  261. try {
  262. respPdu = reduceResponsePdu(reqPdu, respPdu, pos) ;
  263. respMsg = (SnmpMessage)pduFactory.
  264. encodeSnmpPdu(respPdu,
  265. packet.getData().length -32) ;
  266. break;
  267. } catch (SnmpTooBigException xx) {
  268. if (isDebugOn()) {
  269. debug("makeResponseMessage",
  270. "response message is still too big");
  271. }
  272. old= pos;
  273. pos= xx.getVarBindCount();
  274. if (isDebugOn()) {
  275. debug("makeResponseMessage",
  276. "fail on element" + pos);
  277. }
  278. if (pos == old) {
  279. // we can not go any further in trying to
  280. // reduce the message !
  281. //
  282. throw xx;
  283. }
  284. }
  285. }// end of loop
  286. } catch(SnmpStatusException xx) {
  287. respMsg = null ;
  288. if (isDebugOn()) {
  289. debug("makeResponseMessage",
  290. "failure when encoding the response message");
  291. debug("makeResponseMessage", xx);
  292. }
  293. }
  294. catch(SnmpTooBigException xx) {
  295. try {
  296. respPdu = newTooBigPdu(reqPdu) ;
  297. respMsg = (SnmpMessage)pduFactory.
  298. encodeSnmpPdu(respPdu, packet.getData().length) ;
  299. }
  300. catch(SnmpTooBigException xxx) {
  301. respMsg = null ;
  302. if (isDebugOn()) {
  303. debug("makeResponseMessage",
  304. "'too big' is 'too big' !!!");
  305. }
  306. adaptor.incSnmpSilentDrops(1);
  307. }
  308. catch(Exception xxx) {
  309. debug("makeResponseMessage", xxx);
  310. respMsg = null ;
  311. }
  312. }
  313. catch(Exception xx) {
  314. debug("makeResponseMessage", xx);
  315. respMsg = null ;
  316. }
  317. }
  318. }
  319. return respMsg ;
  320. }
  321. /**
  322. * Here we make a response pdu from a request pdu.
  323. * We return null if there is no pdu to reply.
  324. */
  325. private SnmpPduPacket makeResponsePdu(SnmpPduPacket reqPdu,
  326. Object userData) {
  327. SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
  328. SnmpPduPacket respPdu = null ;
  329. snmpServer.updateRequestCounters(reqPdu.type) ;
  330. if (reqPdu.varBindList != null)
  331. snmpServer.updateVarCounters(reqPdu.type,
  332. reqPdu.varBindList.length) ;
  333. if (checkPduType(reqPdu)) {
  334. respPdu = checkAcl(reqPdu) ;
  335. if (respPdu == null) { // reqPdu is accepted by ACLs
  336. if (mibs.size() < 1) {
  337. if (isTraceOn()) {
  338. trace("makeResponsePdu", "Request " +
  339. reqPdu.requestId +
  340. " received but no MIB registered.");
  341. }
  342. return makeNoMibErrorPdu((SnmpPduRequest)reqPdu, userData);
  343. }
  344. switch(reqPdu.type) {
  345. case SnmpPduPacket.pduGetRequestPdu:
  346. case SnmpPduPacket.pduGetNextRequestPdu:
  347. case SnmpPduPacket.pduSetRequestPdu:
  348. respPdu = makeGetSetResponsePdu((SnmpPduRequest)reqPdu,
  349. userData) ;
  350. break ;
  351. case SnmpPduPacket.pduGetBulkRequestPdu:
  352. respPdu = makeGetBulkResponsePdu((SnmpPduBulk)reqPdu,
  353. userData) ;
  354. break ;
  355. }
  356. }
  357. else { // reqPdu is rejected by ACLs
  358. // respPdu contains the error response to be sent.
  359. // We send this response only if authResEnabled is true.
  360. if (!snmpServer.getAuthRespEnabled()) { // No response should be sent
  361. respPdu = null ;
  362. }
  363. if (snmpServer.getAuthTrapEnabled()) { // A trap must be sent
  364. try {
  365. snmpServer.snmpV1Trap(SnmpPduTrap.
  366. trapAuthenticationFailure, 0,
  367. new SnmpVarBindList()) ;
  368. }
  369. catch(Exception x) {
  370. if (isDebugOn()) {
  371. debug("makeResponsePdu",
  372. "failure when sending authentication trap");
  373. debug("makeResponsePdu", x);
  374. }
  375. }
  376. }
  377. }
  378. }
  379. return respPdu ;
  380. }
  381. //
  382. // Generates a response packet, filling the values in the
  383. // varbindlist with one of endOfMibView, noSuchObject, noSuchInstance
  384. // according to the value of <code>status</code>
  385. //
  386. // @param statusTag should be one of:
  387. // <li>SnmpDataTypeEnums.errEndOfMibViewTag</li>
  388. // <li>SnmpDataTypeEnums.errNoSuchObjectTag</li>
  389. // <li>SnmpDataTypeEnums.errNoSuchInstanceTag</li>
  390. //
  391. SnmpPduPacket makeErrorVarbindPdu(SnmpPduPacket req, int statusTag) {
  392. final SnmpVarBind[] vblist = req.varBindList;
  393. final int length = vblist.length;
  394. switch (statusTag) {
  395. case SnmpDataTypeEnums.errEndOfMibViewTag:
  396. for (int i=0 ; i<length ; i++)
  397. vblist[i].value = SnmpVarBind.endOfMibView;
  398. break;
  399. case SnmpDataTypeEnums.errNoSuchObjectTag:
  400. for (int i=0 ; i<length ; i++)
  401. vblist[i].value = SnmpVarBind.noSuchObject;
  402. break;
  403. case SnmpDataTypeEnums.errNoSuchInstanceTag:
  404. for (int i=0 ; i<length ; i++)
  405. vblist[i].value = SnmpVarBind.noSuchInstance;
  406. break;
  407. default:
  408. return newErrorResponsePdu(req,snmpRspGenErr,1);
  409. }
  410. return newValidResponsePdu(req,vblist);
  411. }
  412. // Generates an appropriate response when no mib is registered in
  413. // the adaptor.
  414. //
  415. // <li>If the version is V1:</li>
  416. // <ul><li>Generates a NoSuchName error V1 response PDU</li></ul>
  417. // <li>If the version is V2:</li>
  418. // <ul><li>If the request is a GET, fills the varbind list with
  419. // NoSuchObject's</li>
  420. // <li>If the request is a GET-NEXT/GET-BULK, fills the varbind
  421. // list with EndOfMibView's</li>
  422. // <li>If the request is a SET, generates a NoAccess error V2
  423. // response PDU</li>
  424. // </ul>
  425. //
  426. //
  427. SnmpPduPacket makeNoMibErrorPdu(SnmpPduRequest req, Object userData) {
  428. // There is no agent registered
  429. //
  430. if (req.version == SnmpDefinitions.snmpVersionOne) {
  431. // Version 1: => NoSuchName
  432. return
  433. newErrorResponsePdu(req,snmpRspNoSuchName,1);
  434. } else if (req.version == SnmpDefinitions.snmpVersionTwo) {
  435. // Version 2: => depends on PDU type
  436. switch (req.type) {
  437. case pduSetRequestPdu :
  438. case pduWalkRequest :
  439. // SET request => NoAccess
  440. return
  441. newErrorResponsePdu(req,snmpRspNoAccess,1);
  442. case pduGetRequestPdu :
  443. // GET request => NoSuchObject
  444. return
  445. makeErrorVarbindPdu(req,SnmpDataTypeEnums.
  446. errNoSuchObjectTag);
  447. case pduGetNextRequestPdu :
  448. case pduGetBulkRequestPdu :
  449. // GET-NEXT or GET-BULK => EndOfMibView
  450. return
  451. makeErrorVarbindPdu(req,SnmpDataTypeEnums.
  452. errEndOfMibViewTag);
  453. default:
  454. }
  455. }
  456. // Something wrong here: => snmpRspGenErr
  457. return newErrorResponsePdu(req,snmpRspGenErr,1);
  458. }
  459. /**
  460. * Here we make the response pdu from a get/set request pdu.
  461. * At this level, the result is never null.
  462. */
  463. private SnmpPduPacket makeGetSetResponsePdu(SnmpPduRequest req,
  464. Object userData) {
  465. // Create the trhead group specific for handling sub-requests
  466. // associated to the current request. Use the invoke id
  467. //
  468. // Nice idea to use a thread group on a request basis.
  469. // However the impact on performance is terrible !
  470. // theGroup= new ThreadGroup(thread.getThreadGroup(),
  471. // "request " + String.valueOf(req.requestId));
  472. // Let's build the varBindList for the response pdu
  473. //
  474. if (req.varBindList == null) {
  475. // Good ! Let's make a full response pdu.
  476. //
  477. return newValidResponsePdu(req, null) ;
  478. }
  479. // First we need to split the request into subrequests
  480. //
  481. splitRequest(req);
  482. int nbSubRequest= subs.size();
  483. if (nbSubRequest == 1)
  484. return turboProcessingGetSet(req,userData);
  485. // Execute all the subrequests resulting from the split of the
  486. // varbind list.
  487. //
  488. SnmpPduPacket result= executeSubRequest(req,userData);
  489. if (result != null)
  490. // It means that an error occured. The error is already
  491. // formatted by the executeSubRequest
  492. // method.
  493. return result;
  494. // So far so good. So we need to concatenate all the answers.
  495. //
  496. if (isTraceOn()) {
  497. trace("makeGetSetResponsePdu",
  498. "Build the unified response for request " + req.requestId);
  499. }
  500. return mergeResponses(req);
  501. }
  502. /**
  503. * The method runs all the sub-requests associated to the current
  504. * instance of SnmpRequestHandler.
  505. */
  506. private SnmpPduPacket executeSubRequest(SnmpPduPacket req,
  507. Object userData) {
  508. int errorStatus = SnmpDefinitions.snmpRspNoError ;
  509. int nbSubRequest= subs.size();
  510. int i=0;
  511. // If it's a set request, we must first check any varBind
  512. //
  513. if (req.type == pduSetRequestPdu) {
  514. i=0;
  515. for(Enumeration e= subs.elements(); e.hasMoreElements() ; i++) {
  516. // Indicate to the sub request that a check must be invoked ...
  517. // OK we should have defined out own tag for that !
  518. //
  519. SnmpSubRequestHandler sub= (SnmpSubRequestHandler)
  520. e.nextElement();
  521. sub.setUserData(userData);
  522. sub.type= pduWalkRequest;
  523. sub.run();
  524. sub.type= pduSetRequestPdu;
  525. if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
  526. // No point to go any further.
  527. //
  528. if (isDebugOn()) {
  529. debug("executeSubRequest", "an error occurs");
  530. }
  531. return newErrorResponsePdu(req, errorStatus,
  532. sub.getErrorIndex() + 1) ;
  533. }
  534. }
  535. }// end processing check operation for a set PDU.
  536. // Let's start the sub-requests.
  537. //
  538. i=0;
  539. for(Enumeration e= subs.elements(); e.hasMoreElements() ;i++) {
  540. SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
  541. /* NPCTE fix for bugId 4492741, esc 0, 16-August 2001 */
  542. sub.setUserData(userData);
  543. /* end of NPCTE fix for bugId 4492741 */
  544. sub.run();
  545. if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) {
  546. // No point to go any further.
  547. //
  548. if (isDebugOn()) {
  549. debug("executeSubRequest", "an error occurs");
  550. }
  551. return newErrorResponsePdu(req, errorStatus,
  552. sub.getErrorIndex() + 1) ;
  553. }
  554. }
  555. // everything is ok
  556. //
  557. return null;
  558. }
  559. /**
  560. * Optimize when there is only one sub request
  561. */
  562. private SnmpPduPacket turboProcessingGetSet(SnmpPduRequest req,
  563. Object userData) {
  564. int errorStatus = SnmpDefinitions.snmpRspNoError ;
  565. SnmpSubRequestHandler sub= (SnmpSubRequestHandler)
  566. subs.elements().nextElement();
  567. sub.setUserData(userData);
  568. // Indicate to the sub request that a check must be invoked ...
  569. // OK we should have defined out own tag for that !
  570. //
  571. if (req.type == SnmpDefinitions.pduSetRequestPdu) {
  572. sub.type= pduWalkRequest;
  573. sub.run();
  574. sub.type= pduSetRequestPdu;
  575. // Check the error status.
  576. //
  577. errorStatus= sub.getErrorStatus();
  578. if (errorStatus != SnmpDefinitions.snmpRspNoError) {
  579. // No point to go any further.
  580. //
  581. return newErrorResponsePdu(req, errorStatus,
  582. sub.getErrorIndex() + 1) ;
  583. }
  584. }
  585. // process the operation
  586. //
  587. sub.run();
  588. errorStatus= sub.getErrorStatus();
  589. if (errorStatus != SnmpDefinitions.snmpRspNoError) {
  590. // No point to go any further.
  591. //
  592. if (isDebugOn()) {
  593. debug("turboProcessingGetSet", "an error occurs");
  594. }
  595. int realIndex= sub.getErrorIndex() + 1;
  596. return newErrorResponsePdu(req, errorStatus, realIndex) ;
  597. }
  598. // So far so good. So we need to concatenate all the answers.
  599. //
  600. if (isTraceOn()) {
  601. trace("turboProcessingGetSet",
  602. "build the unified response for request " + req.requestId);
  603. }
  604. return mergeResponses(req);
  605. }
  606. /**
  607. * Here we make the response pdu for a bulk request.
  608. * At this level, the result is never null.
  609. */
  610. private SnmpPduPacket makeGetBulkResponsePdu(SnmpPduBulk req,
  611. Object userData) {
  612. SnmpVarBind[] respVarBindList = null ;
  613. // RFC 1905, Section 4.2.3, p14
  614. int L = req.varBindList.length ;
  615. int N = Math.max(Math.min(req.nonRepeaters, L), 0) ;
  616. int M = Math.max(req.maxRepetitions, 0) ;
  617. int R = L - N ;
  618. if (req.varBindList == null) {
  619. // Good ! Let's make a full response pdu.
  620. //
  621. return newValidResponsePdu(req, null) ;
  622. }
  623. // Split the request into subrequests.
  624. //
  625. splitBulkRequest(req, N, M, R);
  626. SnmpPduPacket result= executeSubRequest(req,userData);
  627. if (result != null)
  628. return result;
  629. respVarBindList= mergeBulkResponses(N + (M * R));
  630. // Now we remove useless trailing endOfMibView.
  631. //
  632. int m2 ; // respVarBindList[m2] item and next are going to be removed
  633. int t = respVarBindList.length ;
  634. while ((t > N) && (respVarBindList[t-1].
  635. value.equals(SnmpVarBind.endOfMibView))) {
  636. t-- ;
  637. }
  638. if (t == N)
  639. m2 = N + R ;
  640. else
  641. m2 = N + ((t -1 -N) / R + 2) * R ; // Trivial, of course...
  642. if (m2 < respVarBindList.length) {
  643. SnmpVarBind[] truncatedList = new SnmpVarBind[m2] ;
  644. for (int i = 0 ; i < m2 ; i++) {
  645. truncatedList[i] = respVarBindList[i] ;
  646. }
  647. respVarBindList = truncatedList ;
  648. }
  649. // Good ! Let's make a full response pdu.
  650. //
  651. return newValidResponsePdu(req, respVarBindList) ;
  652. }
  653. /**
  654. * Check the type of the pdu: only the get/set/bulk request
  655. * are accepted.
  656. */
  657. private boolean checkPduType(SnmpPduPacket pdu) {
  658. boolean result = true ;
  659. switch(pdu.type) {
  660. case SnmpDefinitions.pduGetRequestPdu:
  661. case SnmpDefinitions.pduGetNextRequestPdu:
  662. case SnmpDefinitions.pduSetRequestPdu:
  663. case SnmpDefinitions.pduGetBulkRequestPdu:
  664. result = true ;
  665. break;
  666. default:
  667. if (isDebugOn()) {
  668. debug("checkPduType", "cannot respond to this kind of PDU");
  669. }
  670. result = false ;
  671. break;
  672. }
  673. return result ;
  674. }
  675. /**
  676. * Check if the specified pdu is conform to the ACL.
  677. * This method returns null if the pdu is ok. If not, it returns
  678. * the response pdu to be replied.
  679. */
  680. private SnmpPduPacket checkAcl(SnmpPduPacket pdu) {
  681. SnmpPduPacket response = null ;
  682. String community = new String(pdu.community) ;
  683. // We check the pdu type and create an error response if
  684. // the check failed.
  685. //
  686. if (ipacl != null) {
  687. if (pdu.type == SnmpDefinitions.pduSetRequestPdu) {
  688. if (!((InetAddressAcl)ipacl).
  689. checkWritePermission(pdu.address, community)) {
  690. if (isTraceOn()) {
  691. trace("checkAcl", "sender is " + pdu.address +
  692. " with " + community);
  693. trace("checkAcl", "sender has no write permission");
  694. }
  695. int err = SnmpSubRequestHandler.
  696. mapErrorStatus(SnmpDefinitions.
  697. snmpRspAuthorizationError,
  698. pdu.version, pdu.type);
  699. response = newErrorResponsePdu(pdu, err, 0) ;
  700. }
  701. else {
  702. if (isTraceOn()) {
  703. trace("checkAcl", "sender is " + pdu.address +
  704. " with " + community);
  705. trace("checkAcl", "sender has write permission");
  706. }
  707. }
  708. }
  709. else {
  710. if (!((InetAddressAcl)ipacl).checkReadPermission(pdu.address, community)) {
  711. if (isTraceOn()) {
  712. trace("checkAcl", "sender is " + pdu.address +
  713. " with " + community);
  714. trace("checkAcl", "sender has no read permission");
  715. }
  716. int err = SnmpSubRequestHandler.
  717. mapErrorStatus(SnmpDefinitions.
  718. snmpRspAuthorizationError,
  719. pdu.version, pdu.type);
  720. response = newErrorResponsePdu(pdu,
  721. err,
  722. 0);
  723. SnmpAdaptorServer snmpServer =
  724. (SnmpAdaptorServer)adaptorServer;
  725. snmpServer.updateErrorCounters(SnmpDefinitions.
  726. snmpRspNoSuchName);
  727. }
  728. else {
  729. if (isTraceOn()) {
  730. trace("checkAcl", "sender is " + pdu.address +
  731. " with " + community);
  732. trace("checkAcl", "sender has read permission");
  733. }
  734. }
  735. }
  736. }
  737. // If the response is not null, this means the pdu is rejected.
  738. // So let's update the statistics.
  739. //
  740. if (response != null) {
  741. SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ;
  742. snmpServer.incSnmpInBadCommunityUses(1) ;
  743. if (((InetAddressAcl)ipacl).checkCommunity(community) == false)
  744. snmpServer.incSnmpInBadCommunityNames(1) ;
  745. }
  746. return response ;
  747. }
  748. /**
  749. * Make a response pdu with the specified error status and index.
  750. * NOTE: the response pdu share its varBindList with the request pdu.
  751. */
  752. private SnmpPduRequest newValidResponsePdu(SnmpPduPacket reqPdu,
  753. SnmpVarBind[] varBindList) {
  754. SnmpPduRequest result = new SnmpPduRequest() ;
  755. result.address = reqPdu.address ;
  756. result.port = reqPdu.port ;
  757. result.version = reqPdu.version ;
  758. result.community = reqPdu.community ;
  759. result.type = result.pduGetResponsePdu ;
  760. result.requestId = reqPdu.requestId ;
  761. result.errorStatus = SnmpDefinitions.snmpRspNoError ;
  762. result.errorIndex = 0 ;
  763. result.varBindList = varBindList ;
  764. ((SnmpAdaptorServer)adaptorServer).
  765. updateErrorCounters(result.errorStatus) ;
  766. return result ;
  767. }
  768. /**
  769. * Make a response pdu with the specified error status and index.
  770. * NOTE: the response pdu share its varBindList with the request pdu.
  771. */
  772. private SnmpPduRequest newErrorResponsePdu(SnmpPduPacket req,int s,int i) {
  773. SnmpPduRequest result = newValidResponsePdu(req, null) ;
  774. result.errorStatus = s ;
  775. result.errorIndex = i ;
  776. result.varBindList = req.varBindList ;
  777. ((SnmpAdaptorServer)adaptorServer).
  778. updateErrorCounters(result.errorStatus) ;
  779. return result ;
  780. }
  781. private SnmpMessage newTooBigMessage(SnmpMessage reqMsg)
  782. throws SnmpTooBigException {
  783. SnmpMessage result = null ;
  784. SnmpPduPacket reqPdu = null ;
  785. try {
  786. reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ;
  787. if (reqPdu != null) {
  788. SnmpPduPacket respPdu = newTooBigPdu(reqPdu) ;
  789. result = (SnmpMessage)pduFactory.
  790. encodeSnmpPdu(respPdu, packet.getData().length) ;
  791. }
  792. }
  793. catch(SnmpStatusException x) {
  794. // This should not occur because decodeIncomingRequest has normally
  795. // been successfully called before.
  796. debug("InternalError: ", x);
  797. throw new InternalError() ;
  798. }
  799. return result ;
  800. }
  801. private SnmpPduPacket newTooBigPdu(SnmpPduPacket req) {
  802. SnmpPduRequest result =
  803. newErrorResponsePdu(req, SnmpDefinitions.snmpRspTooBig, 0) ;
  804. result.varBindList = null ;
  805. return result ;
  806. }
  807. private SnmpPduPacket reduceResponsePdu(SnmpPduPacket req,
  808. SnmpPduPacket resp,
  809. int acceptedVbCount)
  810. throws SnmpTooBigException {
  811. // Reduction can be attempted only on bulk response
  812. //
  813. if (req.type != req.pduGetBulkRequestPdu) {
  814. if (isDebugOn()) {
  815. debug("reduceResponsePdu", "cannot remove anything");
  816. }
  817. throw new SnmpTooBigException(acceptedVbCount) ;
  818. }
  819. // We're going to reduce the varbind list.
  820. // First determine which items should be removed.
  821. // Next duplicate and replace the existing list by the reduced one.
  822. //
  823. // acceptedVbCount is the number of varbind which have been
  824. // successfully encoded before reaching bufferSize:
  825. // * when it is >= 2, we split the varbindlist at this
  826. // position (-1 to be safe),
  827. // * when it is 1, we only put one (big?) item in the varbindlist
  828. // * when it is 0 (in fact, acceptedVbCount is not available),
  829. // we split the varbindlist by 2.
  830. //
  831. int vbCount = resp.varBindList.length ;
  832. if (acceptedVbCount >= 3)
  833. vbCount = Math.min(acceptedVbCount - 1, resp.varBindList.length) ;
  834. else if (acceptedVbCount == 1)
  835. vbCount = 1 ;
  836. else // acceptedCount == 0 ie it is unknown
  837. vbCount = resp.varBindList.length / 2 ;
  838. if (vbCount < 1) {
  839. if (isDebugOn()) {
  840. debug("reduceResponsePdu", "cannot remove anything");
  841. }
  842. throw new SnmpTooBigException(acceptedVbCount) ;
  843. }
  844. else {
  845. SnmpVarBind[] newVbList = new SnmpVarBind[vbCount] ;
  846. for (int i = 0 ; i < vbCount ; i++) {
  847. newVbList[i] = resp.varBindList[i] ;
  848. }
  849. if (isDebugOn()) {
  850. debug("reduceResponsePdu",
  851. (resp.varBindList.length - newVbList.length) +
  852. " items have been removed");
  853. }
  854. resp.varBindList = newVbList ;
  855. }
  856. return resp ;
  857. }
  858. /**
  859. * The method takes the incoming requests and split it into subrequests.
  860. */
  861. private void splitRequest(SnmpPduRequest req) {
  862. int nbAgents= mibs.size();
  863. SnmpMibAgent agent= (SnmpMibAgent) mibs.firstElement();
  864. if (nbAgents == 1) {
  865. // Take all the oids contained in the request and
  866. //
  867. subs.put(agent, new SnmpSubRequestHandler(agent, req, true));
  868. return;
  869. }
  870. // For the get next operation we are going to send the varbind list
  871. // to all agents
  872. //
  873. if (req.type == pduGetNextRequestPdu) {
  874. for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) {
  875. SnmpMibAgent ag= (SnmpMibAgent) e.nextElement();
  876. subs.put(ag, new SnmpSubNextRequestHandler(adaptor, ag, req));
  877. }
  878. return;
  879. }
  880. int nbReqs= req.varBindList.length;
  881. SnmpVarBind[] vars= req.varBindList;
  882. SnmpSubRequestHandler sub;
  883. for(int i=0; i < nbReqs; i++) {
  884. agent= root.getAgentMib(vars[i].oid);
  885. sub= (SnmpSubRequestHandler) subs.get(agent);
  886. if (sub == null) {
  887. // We need to create the sub request handler and update
  888. // the hashtable
  889. //
  890. sub= new SnmpSubRequestHandler(agent, req);
  891. subs.put(agent, sub);
  892. }
  893. // Update the translation table within the subrequest
  894. //
  895. sub.updateRequest(vars[i], i);
  896. }
  897. }
  898. /**
  899. * The method takes the incoming get bulk requests and split it into
  900. * subrequests.
  901. */
  902. private void splitBulkRequest(SnmpPduBulk req,
  903. int nonRepeaters,
  904. int maxRepetitions,
  905. int R) {
  906. // Send the getBulk to all agents
  907. //
  908. for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) {
  909. SnmpMibAgent agent = (SnmpMibAgent) e.nextElement();
  910. if(isDebugOn())
  911. trace("splitBulkRequest", "Create a sub with : " +
  912. agent + " " + nonRepeaters + " " +
  913. maxRepetitions + " " + R);
  914. subs.put(agent,
  915. new SnmpSubBulkRequestHandler(adaptor,
  916. agent,
  917. req,
  918. nonRepeaters,
  919. maxRepetitions,
  920. R));
  921. }
  922. return;
  923. }
  924. private SnmpPduPacket mergeResponses(SnmpPduRequest req) {
  925. if (req.type == pduGetNextRequestPdu) {
  926. return mergeNextResponses(req);
  927. }
  928. SnmpVarBind[] result= req.varBindList;
  929. // Go through the list of subrequests and concatenate.
  930. // Hopefully, by now all the sub-requests should be finished
  931. //
  932. for(Enumeration e= subs.elements(); e.hasMoreElements();) {
  933. SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
  934. sub.updateResult(result);
  935. }
  936. return newValidResponsePdu(req,result);
  937. }
  938. private SnmpPduPacket mergeNextResponses(SnmpPduRequest req) {
  939. int max= req.varBindList.length;
  940. SnmpVarBind[] result= new SnmpVarBind[max];
  941. // Go through the list of subrequests and concatenate.
  942. // Hopefully, by now all the sub-requests should be finished
  943. //
  944. for(Enumeration e= subs.elements(); e.hasMoreElements();) {
  945. SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
  946. sub.updateResult(result);
  947. }
  948. if (req.version == snmpVersionTwo) {
  949. return newValidResponsePdu(req,result);
  950. }
  951. // In v1 make sure there is no endOfMibView ...
  952. //
  953. for(int i=0; i < max; i++) {
  954. SnmpValue val= result[i].value;
  955. if (val == SnmpVarBind.endOfMibView)
  956. return newErrorResponsePdu(req,
  957. SnmpDefinitions.snmpRspNoSuchName, i+1);
  958. }
  959. // So far so good ...
  960. //
  961. return newValidResponsePdu(req,result);
  962. }
  963. private SnmpVarBind[] mergeBulkResponses(int size) {
  964. // Let's allocate the array for storing the result
  965. //
  966. SnmpVarBind[] result= new SnmpVarBind[size];
  967. for(int i= size-1; i >=0; --i) {
  968. result[i]= new SnmpVarBind();
  969. result[i].value= SnmpVarBind.endOfMibView;
  970. }
  971. // Go through the list of subrequests and concatenate.
  972. // Hopefully, by now all the sub-requests should be finished
  973. //
  974. for(Enumeration e= subs.elements(); e.hasMoreElements();) {
  975. SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement();
  976. sub.updateResult(result);
  977. }
  978. return result;
  979. }
  980. protected boolean isTraceOn() {
  981. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
  982. }
  983. protected void trace(String clz, String func, String info) {
  984. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz,func,info);
  985. }
  986. protected void trace(String func, String info) {
  987. trace(dbgTag, func, info);
  988. }
  989. protected boolean isDebugOn() {
  990. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
  991. }
  992. protected void debug(String clz, String func, String info) {
  993. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz,func,info);
  994. }
  995. protected void debug(String clz, String func, Throwable exception) {
  996. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func,
  997. exception);
  998. }
  999. protected void debug(String func, String info) {
  1000. debug(dbgTag, func, info);
  1001. }
  1002. protected void debug(String func, Throwable exception) {
  1003. debug(dbgTag, func, exception);
  1004. }
  1005. protected String makeDebugTag() {
  1006. return "SnmpRequestHandler[" + adaptorServer.getProtocol() + ":" +
  1007. adaptorServer.getPort() + "]";
  1008. }
  1009. Thread createThread(Runnable r) {
  1010. return null;
  1011. }
  1012. static final private String InterruptSysCallMsg =
  1013. "Interrupted system call";
  1014. static final private SnmpStatusException noSuchNameException =
  1015. new SnmpStatusException(SnmpDefinitions.snmpRspNoSuchName) ;
  1016. }