mp_v3.cpp
上传用户:ets1996
上传日期:2014-09-30
资源大小:353k
文件大小:43k
源码类别:

SNMP编程

开发平台:

Visual C++

  1. /*_############################################################################
  2.   _## 
  3.   _##  mp_v3.cpp  
  4.   _##
  5.   _##  SNMP++v3.2.22
  6.   _##  -----------------------------------------------
  7.   _##  Copyright (c) 2001-2007 Jochen Katz, Frank Fock
  8.   _##
  9.   _##  This software is based on SNMP++2.6 from Hewlett Packard:
  10.   _##  
  11.   _##    Copyright (c) 1996
  12.   _##    Hewlett-Packard Company
  13.   _##  
  14.   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  15.   _##  Permission to use, copy, modify, distribute and/or sell this software 
  16.   _##  and/or its documentation is hereby granted without fee. User agrees 
  17.   _##  to display the above copyright notice and this license notice in all 
  18.   _##  copies of the software and any documentation of the software. User 
  19.   _##  agrees to assume all liability for the use of the software; 
  20.   _##  Hewlett-Packard and Jochen Katz make no representations about the 
  21.   _##  suitability of this software for any purpose. It is provided 
  22.   _##  "AS-IS" without warranty of any kind, either express or implied. User 
  23.   _##  hereby grants a royalty-free license to any and all derivatives based
  24.   _##  upon this software code base. 
  25.   _##  
  26.   _##  Stuttgart, Germany, Wed May  2 23:22:30 CEST 2007 
  27.   _##  
  28.   _##########################################################################*/
  29. char mp_v3_cpp_version[]="@(#) SNMP++ $Id: mp_v3.cpp 291 2007-04-20 17:24:05Z katz $";
  30. #include <stdlib.h>
  31. #include "snmp_pp/config_snmp_pp.h"
  32. #ifdef _SNMPv3
  33. #include "snmp_pp/v3.h"
  34. #include "snmp_pp/mp_v3.h"
  35. #include "snmp_pp/usm_v3.h"
  36. #include "snmp_pp/notifyqueue.h"
  37. #include "snmp_pp/snmpmsg.h"
  38. #include "snmp_pp/uxsnmp.h"
  39. #include "snmp_pp/eventlistholder.h"
  40. #include "snmp_pp/asn1.h"
  41. #include "snmp_pp/vb.h"
  42. #include "snmp_pp/log.h"
  43. #ifdef SNMP_PP_NAMESPACE
  44. namespace Snmp_pp {
  45. #endif
  46. #define MAX_MPMSGID 2147483647
  47. #define ASN_UNI_PRIV (ASN_UNIVERSAL | ASN_PRIMITIVE)
  48. #define ASN_SEQ_CON (ASN_SEQUENCE | ASN_CONSTRUCTOR)
  49. #define CACHE_LOCAL_REQ true
  50. #define CACHE_REMOTE_REQ false
  51. v3MP *v3MP::I = 0;
  52. // Use locking on access methods in an multithreading enviroment.
  53. #ifdef _THREADS
  54. #define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(lock)
  55. #define BEGIN_REENTRANT_CODE_BLOCK_CONST  
  56.           SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, &lock)))
  57. #else
  58. #define BEGIN_REENTRANT_CODE_BLOCK
  59. #define BEGIN_REENTRANT_CODE_BLOCK_CONST
  60. #endif
  61. // ========================[ Engine id table ]=============================
  62. // Construct engine id table
  63. v3MP::EngineIdTable::EngineIdTable(int initial_size)
  64. {
  65.   if (initial_size < 1)
  66.     initial_size = 10;
  67.   if (!initialize_table(initial_size))
  68.   {
  69.     LOG_BEGIN(ERROR_LOG | 0);
  70.     LOG("v3MP::EngineIdTable: Error creating empty table.");
  71.     LOG_END;
  72.   }
  73. }
  74. // Denstruct enigne id table
  75. v3MP::EngineIdTable::~EngineIdTable()
  76. {
  77.   if (table)
  78.     delete [] table;
  79.   table = 0;
  80. }
  81. // Add an entry to the table.
  82. int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
  83.                                    const OctetStr &host, int port)
  84. {
  85.   if (!table)
  86.     return SNMPv3_MP_NOT_INITIALIZED;
  87.   LOG_BEGIN(INFO_LOG | 9);
  88.   LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
  89.   LOG(engine_id.get_printable());
  90.   LOG(host.get_printable());
  91.   LOG(port);
  92.   LOG_END;
  93.   BEGIN_REENTRANT_CODE_BLOCK;
  94.   for (int i = 0; i < entries; i++)
  95.     if (((table[i].port == port) &&
  96.          (table[i].host == host)) ||
  97. (table[i].engine_id == engine_id))
  98.     {
  99.       LOG_BEGIN(INFO_LOG | 2);
  100.       LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
  101.       LOG(table[i].engine_id.get_printable());
  102.       LOG(table[i].host.get_printable());
  103.       LOG(table[i].port);
  104.       LOG(engine_id.get_printable());
  105.       LOG(host.get_printable());
  106.       LOG(port);
  107.       LOG_END;
  108.       table[i].engine_id = engine_id;
  109.       table[i].host = host;
  110.       table[i].port = port;
  111.       return SNMPv3_MP_OK;         // host is in table
  112.     }
  113.   table[entries].engine_id = engine_id;
  114.   table[entries].host = host;
  115.   table[entries].port = port;
  116.   entries++;
  117.   if (entries == max_entries)
  118.   {
  119.     // resize Table
  120.     struct Entry_T *tmp;
  121.     tmp = new struct Entry_T[2 * max_entries];
  122.     if (!tmp)
  123.     {
  124.       entries--;
  125.       return SNMPv3_MP_ERROR;
  126.     }
  127.     for (int i = 0; i < entries; i++)
  128.       tmp[i] = table[i];
  129.     delete [] table;
  130.     table = tmp;
  131.     max_entries *= 2;
  132.   }
  133.   return SNMPv3_MP_OK;
  134. }
  135. // Get the engine_id of the SNMP entity at the given host/port.
  136. int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
  137.                                    const OctetStr &hostport) const
  138. {
  139.   int port;
  140.   char host[MAX_HOST_NAME_LENGTH + 1];
  141.   char *ptr;
  142.   /* Check length */
  143.   if (hostport.len() > MAX_HOST_NAME_LENGTH)
  144.     return SNMPv3_MP_ERROR;
  145.   /* split up port from hostport */
  146.   strcpy(host, hostport.get_printable());
  147.   ptr = strstr((char*)host,"/");
  148.   if (!ptr)
  149.     return SNMPv3_MP_ERROR;
  150.   *ptr = '';
  151.   port = atol(ptr + 1);
  152.   /* Check for IPv6 address with [] */
  153.   if (host[0] == '[')
  154.   {
  155.     if (*(ptr -1) == ']')
  156.     {
  157.       *(ptr-1) = '';
  158.       return get_entry(engine_id, &(host[1]), port);
  159.     }
  160.     else
  161.       return SNMPv3_MP_ERROR;
  162.   }
  163.   return get_entry(engine_id, host, port);
  164. }
  165. // Get the engineID of the SNMP entity at the given host/port.
  166. int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
  167.                                    const OctetStr &host, int port) const
  168. {
  169.   if (!table)
  170.     return SNMPv3_MP_NOT_INITIALIZED;
  171.   BEGIN_REENTRANT_CODE_BLOCK_CONST;
  172.   int i, found = 0;
  173.   for (i = 0; i < entries; i++)
  174.     if ((table[i].port == port) &&
  175.         (table[i].host == host))
  176.     {
  177.       found=1;
  178.       break;
  179.     }
  180.   if (!found)
  181.   {
  182.     LOG_BEGIN(INFO_LOG | 4);
  183.     LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
  184.     LOG(host.get_printable());
  185.     LOG(port);
  186.     LOG_END;
  187.     return SNMPv3_MP_ERROR;
  188.   }
  189.   engine_id = table[i].engine_id;
  190.   return SNMPv3_MP_OK;
  191. }
  192. // Remove all entries from the engine id table.
  193. int v3MP::EngineIdTable::reset()
  194. {
  195.   if (!table)
  196.     return SNMPv3_MP_NOT_INITIALIZED;
  197.   LOG_BEGIN(INFO_LOG | 1);
  198.   LOG("v3MP::EngineIdTable: Resetting table.");
  199.   LOG_END;
  200.   BEGIN_REENTRANT_CODE_BLOCK;
  201.   entries = 0;
  202.   return SNMPv3_MP_OK;
  203. }
  204. // Remove the given engine id from the table.
  205. int v3MP::EngineIdTable::delete_entry(const OctetStr &engine_id)
  206. {
  207.   if (!table)
  208.     return SNMPv3_MP_NOT_INITIALIZED;
  209.   int i, found = 0;
  210.   BEGIN_REENTRANT_CODE_BLOCK;
  211.   for (i = 0; i < entries; i++)
  212.     if (table[i].engine_id == engine_id)
  213.     {
  214.       found=1;
  215.       break;
  216.     }
  217.   if (!found)
  218.   {
  219.     LOG_BEGIN(WARNING_LOG | 4);
  220.     LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (engine id)");
  221.     LOG(engine_id.get_printable());
  222.     LOG_END;
  223.     return SNMPv3_MP_ERROR;
  224.   }
  225.   /* i is the entry to remove */
  226.   if (i != entries - 1)
  227.     table[i] = table[entries-1];
  228.   entries--;
  229.   return SNMPv3_MP_OK;
  230. }
  231. // Remove the entry for the given address/port from the table.
  232. int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
  233. {
  234.   if (!table)
  235.     return SNMPv3_MP_NOT_INITIALIZED;
  236.   int i, found = 0;
  237.   BEGIN_REENTRANT_CODE_BLOCK;
  238.   for (i = 0; i < entries; i++)
  239.     if ((table[i].port == port) &&
  240.         (table[i].host == host))
  241.     {
  242.       found=1;
  243.       break;
  244.     }
  245.   if (!found)
  246.   {
  247.     LOG_BEGIN(WARNING_LOG | 4);
  248.     LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
  249.     LOG(host.get_printable());
  250.     LOG(port);
  251.     LOG_END;
  252.     return SNMPv3_MP_ERROR;
  253.   }
  254.   /* i is the entry to remove */
  255.   if (i != entries - 1)
  256.     table[i] = table[entries-1];
  257.   entries--;
  258.   return SNMPv3_MP_OK;
  259. }
  260. int v3MP::EngineIdTable::initialize_table(const int size)
  261. {
  262.   table = new struct Entry_T[size];
  263.   entries = 0;
  264.   if (!table)
  265.   {
  266.     max_entries = 0;
  267.     return FALSE;
  268.   }
  269.   max_entries = size;
  270.   return TRUE;
  271. }
  272. // ===============================[ Cache ]==================================
  273. v3MP::Cache::Cache()
  274. {
  275.   // init cache
  276.   table = new struct Entry_T[5];
  277.   if (!table)
  278.   {
  279.     LOG_BEGIN(ERROR_LOG | 1);
  280.     LOG("v3MP::Cache: could not create empty table.");
  281.     LOG_END;
  282.     max_entries = 0;
  283.   }
  284.   else
  285.     max_entries = 5;
  286.   entries = 0;
  287. }
  288. v3MP::Cache::~Cache()
  289. {
  290.   if (table)
  291.   {
  292.     for (int i = 0; i < entries; i++)
  293.       usm->delete_sec_state_reference(table[i].sec_state_ref);
  294.     entries = 0;
  295.     delete [] table;
  296.     table = 0;
  297.     max_entries = 0;
  298.   }
  299. }
  300. // Add an entry to the cache.
  301. int v3MP::Cache::add_entry(int msg_id, unsigned long req_id,
  302.                            const OctetStr &sec_engine_id,
  303.                            int sec_model,
  304.                            const OctetStr &sec_name,
  305.                            int sec_level,
  306.                            const OctetStr &context_engine_id,
  307.                            const OctetStr &context_name,
  308.                            struct SecurityStateReference *sec_state_ref,
  309.                            int error_code, bool local_request)
  310. {
  311.   if (!table)
  312.     return SNMPv3_MP_ERROR;
  313.   LOG_BEGIN(INFO_LOG | 8);
  314.   LOG("v3MP::Cache: adding new entry (n) (msg id) (req id) (type)");
  315.   LOG(entries);
  316.   LOG(msg_id);
  317.   LOG(req_id);
  318.   LOG(local_request ? "local" : "remote");
  319.   LOG_END;
  320.   BEGIN_REENTRANT_CODE_BLOCK;
  321.   for (int i = 0; i < entries; i++)
  322.     if ((table[i].msg_id == msg_id) &&
  323.         (table[i].req_id == req_id) &&
  324.         (table[i].local_request == local_request) &&
  325.         (table[i].sec_engine_id == sec_engine_id) &&
  326.         (table[i].sec_model == sec_model) &&
  327.         (table[i].sec_name == sec_name) &&
  328.         (table[i].sec_level == sec_level) &&
  329.         (table[i].context_engine_id == context_engine_id) &&
  330.         (table[i].context_name == context_name))
  331.     {
  332.       LOG_BEGIN(WARNING_LOG | 3);
  333.       LOG("v3MP::Cache: Dont add doubled entry (msg id) (req id)");
  334.       LOG(msg_id);
  335.       LOG(req_id);
  336.       LOG_END;
  337.       return SNMPv3_MP_DOUBLED_MESSAGE;
  338.     }
  339.   table[entries].msg_id            = msg_id;
  340.   table[entries].req_id            = req_id;
  341.   table[entries].local_request     = local_request;
  342.   table[entries].sec_engine_id     = sec_engine_id;
  343.   table[entries].sec_model         = sec_model;
  344.   table[entries].sec_name          = sec_name;
  345.   table[entries].sec_level         = sec_level;
  346.   table[entries].context_engine_id = context_engine_id;
  347.   table[entries].context_name      = context_name;
  348.   table[entries].sec_state_ref     = sec_state_ref;
  349.   table[entries].error_code        = error_code;
  350.   entries++;
  351.   if (entries == max_entries)
  352.   {
  353.     // resize Table
  354.     struct Entry_T *tmp;
  355.     tmp = new struct Entry_T[2 * max_entries];
  356.     if (!tmp)
  357.     {
  358.       entries--;
  359.       return SNMPv3_MP_ERROR;
  360.     }
  361.     for (int i=0; i<entries;i++)
  362.       tmp[i] = table[i];
  363.     delete [] table;
  364.     table = tmp;
  365.     max_entries *= 2;
  366.   }
  367.   return SNMPv3_MP_OK;
  368. }
  369. // Search the cache for a message id, return the error code and
  370. int v3MP::Cache::get_entry(int msg_id, bool local_request, int *error_code,
  371.                            struct SecurityStateReference **sec_state_ref)
  372. {
  373.   if (!table) return SNMPv3_MP_ERROR;
  374.   BEGIN_REENTRANT_CODE_BLOCK;
  375.   for (int i=0; i < entries; i++)
  376.   {
  377.     if ((msg_id == table[i].msg_id) &&
  378.         (local_request == table[i].local_request))
  379.     {
  380.       *error_code = table[i].error_code;
  381.       *sec_state_ref = table[i].sec_state_ref;
  382.       entries--;
  383.       LOG_BEGIN(INFO_LOG | 8);
  384.       LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
  385.       LOG(i);
  386.       LOG(msg_id);
  387.       LOG(local_request ? "local" : "remote");
  388.       LOG_END;
  389.       if (entries > i)
  390.       {
  391.         table[i] = table[entries];
  392. LOG_BEGIN(INFO_LOG | 10);
  393. LOG("v3MP::Cache: Moving entry (from) (to)");
  394. LOG(entries);
  395. LOG(i);
  396. LOG_END;
  397.       }
  398.       return SNMPv3_MP_OK;
  399.     }
  400.   }
  401.   LOG_BEGIN(WARNING_LOG | 5);
  402.   LOG("v3MP::Cache: Entry not found (msg id) (type)");
  403.   LOG(msg_id);
  404.   LOG(local_request ? "local" : "remote");
  405.   LOG_END;
  406.   return SNMPv3_MP_ERROR;
  407. }
  408. // Delete the entry with the given request id from the cache.
  409. void v3MP::Cache::delete_entry(unsigned long req_id, bool local_request)
  410. {
  411.   if (!table) return;
  412.   BEGIN_REENTRANT_CODE_BLOCK;
  413.   for (int i=0; i<entries; i++)
  414.     if ((table[i].req_id == req_id) &&
  415.         (table[i].local_request == local_request))
  416.     {
  417.       LOG_BEGIN(INFO_LOG | 8);
  418.       LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (type)");
  419.       LOG(i);
  420.       LOG(req_id);
  421.       LOG(local_request ? "local" : "remote");
  422.       LOG_END;
  423.       usm->delete_sec_state_reference(table[i].sec_state_ref);
  424.       entries--;
  425.       if (entries > i)
  426.       {
  427.         table[i] = table[entries];
  428. LOG_BEGIN(INFO_LOG | 10);
  429. LOG("v3MP::Cache: Moving entry (from) (to)");
  430. LOG(entries);
  431. LOG(i);
  432. LOG_END;
  433.       }
  434.       return;
  435.     }
  436.   LOG_BEGIN(INFO_LOG | 8);
  437.   LOG("v3MP::Cache: Entry to delete not found (req id) (type)");
  438.   LOG(req_id);
  439.   LOG(local_request ? "local" : "remote");
  440.   LOG_END;
  441.   return;
  442. }
  443. // Delete the entry with the given request ans message id from the cache.
  444. void v3MP::Cache::delete_entry(unsigned long req_id, int msg_id,
  445.        bool local_request)
  446. {
  447.   if (!table) return;
  448.   BEGIN_REENTRANT_CODE_BLOCK;
  449.   for (int i=0; i<entries; i++)
  450.     if ((table[i].req_id == req_id) &&
  451. (table[i].msg_id == msg_id) &&
  452.         (table[i].local_request == local_request))
  453.     {
  454.       LOG_BEGIN(INFO_LOG | 8);
  455.       LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (msg id) (type)");
  456.       LOG(i);
  457.       LOG(req_id);
  458.       LOG(msg_id);
  459.       LOG(local_request ? "local" : "remote");
  460.       LOG_END;
  461.       usm->delete_sec_state_reference(table[i].sec_state_ref);
  462.       entries--;
  463.       if (entries > i)
  464.       {
  465.         table[i] = table[entries];
  466. LOG_BEGIN(INFO_LOG | 10);
  467. LOG("v3MP::Cache: Moving entry (from) (to)");
  468. LOG(entries);
  469. LOG(i);
  470. LOG_END;
  471.       }
  472.       return;
  473.     }
  474.   LOG_BEGIN(INFO_LOG | 8);
  475.   LOG("v3MP::Cache: Entry to delete not found (req id) (msg id) (type)");
  476.   LOG(req_id);
  477.   LOG(msg_id);
  478.   LOG(local_request ? "local" : "remote");
  479.   LOG_END;
  480.   return;
  481. }
  482. // Search the cache for a message id, return it and remove it from the cache
  483. int v3MP::Cache::get_entry(int searchedID, bool local_request,
  484.                            struct Cache::Entry_T *res)
  485. {
  486.   if ((!table) || (!res)) return SNMPv3_MP_ERROR;
  487.   BEGIN_REENTRANT_CODE_BLOCK;
  488.   for (int i=0; i < entries; i++)
  489.     if ((table[i].msg_id == searchedID) &&
  490.         (table[i].local_request == local_request))
  491.     {
  492.       res->msg_id            = table[i].msg_id;
  493.       res->req_id            = table[i].req_id;
  494.       res->local_request     = table[i].local_request;
  495.       res->sec_engine_id     = table[i].sec_engine_id;
  496.       res->sec_model         = table[i].sec_model;
  497.       res->sec_name          = table[i].sec_name;
  498.       res->sec_level         = table[i].sec_level;
  499.       res->context_engine_id = table[i].context_engine_id;
  500.       res->context_name      = table[i].context_name;
  501.       res->sec_state_ref     = table[i].sec_state_ref;
  502.       res->error_code        = table[i].error_code;
  503.       LOG_BEGIN(INFO_LOG | 8);
  504.       LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
  505.       LOG(i);
  506.       LOG(searchedID);
  507.       LOG(local_request ? "local" : "remote");
  508.       LOG_END;
  509.       entries--;
  510.       if (entries > i)
  511.       {
  512.         table[i] = table[entries];
  513. LOG_BEGIN(INFO_LOG | 10);
  514. LOG("v3MP::Cache: Moving entry (from) (to)");
  515. LOG(entries);
  516. LOG(i);
  517. LOG_END;
  518.       }
  519.       return SNMPv3_MP_OK;
  520.     }
  521.   LOG_BEGIN(WARNING_LOG | 5);
  522.   LOG("v3MP::Cache: Entry not found (msg id) (type)");
  523.   LOG(searchedID);
  524.   LOG(local_request ? "local" : "remote");
  525.   LOG_END;
  526.   return SNMPv3_MP_ERROR;
  527. }
  528. void v3MP::Cache::delete_content(struct v3MP::Cache::Entry_T &ce)
  529. {
  530.   if (ce.sec_state_ref)
  531.     usm->delete_sec_state_reference(ce.sec_state_ref);
  532. }
  533. // ==========================[ class v3MP ]===============================
  534. // Initialize the v3MP.
  535. v3MP::v3MP(const OctetStr& snmpEngineID,
  536.            unsigned int engineBoots, int &construct_status)
  537.   : own_engine_id(0), usm(0)
  538. {
  539.   if (I)
  540.   {
  541.     debugprintf(0, "v3MP: You must not create two object of this class!");
  542.     construct_status = SNMPv3_MP_ERROR;
  543.     return;
  544.   }
  545.   I = this;
  546.   snmpUnknownSecurityModels = 0;
  547.   snmpInvalidMsgs = 0;
  548.   snmpUnknownPDUHandlers = 0;
  549.   int length = snmpEngineID.len();
  550.   if (length > MAXLENGTH_ENGINEID)
  551.     length = MAXLENGTH_ENGINEID;
  552.   own_engine_id = v3strcpy(snmpEngineID.data(), length);
  553.   own_engine_id_len = length;
  554.   own_engine_id_oct = snmpEngineID;
  555.   int result;
  556.   usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);
  557.   if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
  558.   {
  559.     construct_status = SNMPv3_MP_ERROR;
  560.     return;
  561.   }
  562.   cache.set_usm(usm);
  563.   construct_status = SNMPv3_MP_OK;
  564. }
  565. // Free all allocated ressources of the v3MP.
  566. v3MP::~v3MP()
  567. {
  568.   if (own_engine_id)
  569.     delete [] own_engine_id;
  570.   own_engine_id = 0;
  571.   if (usm)
  572.   {
  573.     delete usm;
  574.     usm = 0;
  575.   }
  576.   I = 0;
  577. }
  578. // Remove all occurences of this engine id from v3MP and USM.
  579. int v3MP::remove_engine_id(const OctetStr &engine_id)
  580. {
  581.   int retval1, retval2;
  582.   retval1 = engine_id_table.delete_entry(engine_id);
  583.   retval2 = usm->remove_engine_id(engine_id);
  584.   if ((retval1 == SNMPv3_MP_NOT_INITIALIZED) ||
  585.       (retval2 == SNMPv3_USM_ERROR))
  586.     return SNMPv3_MP_NOT_INITIALIZED;
  587.   return SNMPv3_MP_OK;
  588. }
  589. // Send a report message.
  590. int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
  591.       struct snmp_pdu *pdu, int errorCode, int sLevel,
  592.       int sModel, OctetStr &sName,
  593.       UdpAddress &destination, Snmp *snmp_session)
  594. {
  595.   debugprintf(2, "v3MP::send_report: Sending report message.");
  596.   unsigned char *data;
  597.   int dataLength;
  598.   int pdu_type = 0;
  599.   unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
  600.   unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
  601.   int cEngineIDLength = MAXLENGTH_ENGINEID+1;
  602.   int cNameLength = MAXLENGTH_CONTEXT_NAME+1;
  603.   if (scopedPDULength != MAX_SNMP_PACKET)
  604.   {
  605.     // try to get scopedPDU and PDU
  606.     data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
  607.  cEngineID, &cEngineIDLength,
  608.  cName, &cNameLength);
  609.     if (data == NULL) {
  610.       debugprintf(1, "mp: Error while trying to parse  scopedPDU!");
  611.       cEngineID[0] = '';
  612.       cEngineIDLength = 0;
  613.       cName[0] = '';
  614.       cNameLength = 0;
  615.       // Dont send encrypted report if decryption failed:
  616.       if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
  617.         sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
  618.     }
  619.     else { // data != NULL
  620.       dataLength = scopedPDULength;
  621.       // parse data of scopedPDU
  622.       snmp_parse_data_pdu(pdu, data, dataLength);
  623.       pdu_type = pdu->command;
  624.       if (!data) {
  625.         debugprintf(0, "mp: Error while trying to parse PDU!");
  626.       }
  627.     } // end of: if (data == NULL)
  628.   } // end if (scopedPDULength != MAX_SNMP_PACKET)
  629.   else { // scopedPDULength == MAX_SNMP_PACKET
  630.     cEngineID[0] = '';
  631.     cEngineIDLength = 0;
  632.     cName[0] = '';
  633.     cNameLength = 0;
  634.     pdu->reqid = 0;
  635.   }
  636.   clear_pdu(pdu);   // Clear pdu and free all content
  637.   debugprintf(4, "pdu->reqid = 0x%lx",pdu->reqid);
  638.   pdu->errstat = 0;
  639.   pdu->errindex = 0;
  640.   pdu->command = REPORT_MSG;
  641.   Vb counterVb;
  642.   Oid counterOid;
  643.   SmiLPOID smioid;
  644.   SmiVALUE smival;
  645.   switch (errorCode) {
  646.     case SNMPv3_MP_INVALID_MESSAGE:
  647.     case SNMPv3_USM_PARSE_ERROR: {
  648.       counterVb.set_oid(oidSnmpInvalidMsgs);
  649.       counterVb.set_value(Counter32(get_stats_invalid_msgs()));
  650.       break;
  651.     }
  652.     case SNMPv3_USM_NOT_IN_TIME_WINDOW:
  653.     case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
  654.       counterVb.set_oid(oidUsmStatsNotInTimeWindows);
  655.       counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
  656.       break;
  657.     }
  658.     case SNMPv3_USM_DECRYPTION_ERROR: {
  659.       counterVb.set_oid(oidUsmStatsDecryptionErrors);
  660.       counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
  661.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  662.       break;
  663.     }
  664.     case SNMPv3_USM_AUTHENTICATION_ERROR:
  665.     case SNMPv3_USM_AUTHENTICATION_FAILURE: {
  666.       counterVb.set_oid(oidUsmStatsWrongDigests);
  667.       counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
  668.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  669.       break;
  670.     }
  671.     case SNMPv3_USM_UNKNOWN_ENGINEID:
  672.     case SNMPv3_MP_INVALID_ENGINEID: {
  673.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  674.       counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
  675.       counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
  676.       break;
  677.     }
  678.     case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
  679.       counterVb.set_oid(oidSnmpUnknownSecurityModels);
  680.       counterVb.set_value(Counter32(get_stats_unknown_security_models()));
  681.       sModel = SecurityModel_USM;
  682.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  683.     break;
  684.     }
  685.     case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
  686.       counterVb.set_oid(oidUsmStatsUnknownUserNames);
  687.       counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
  688.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  689.       debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
  690.       break;
  691.     }
  692.     case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
  693.       counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
  694.       counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
  695.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  696.       break;
  697.     }
  698.     default: {
  699.       counterVb.set_oid(oidSnmpInvalidMsgs);
  700.       counterVb.set_value(Counter32(get_stats_invalid_msgs()));
  701.       sModel = SecurityModel_USM;
  702.       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  703.       sName.set_data(0, 0);
  704.       debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
  705.     }
  706.   } // end switch
  707.   counterVb.get_oid(counterOid);
  708.   smioid = counterOid.oidval();
  709.   int status = convertVbToSmival(counterVb, &smival);
  710.   if (status != SNMP_CLASS_SUCCESS) {
  711.     return SNMPv3_MP_ERROR;
  712.   }
  713.   snmp_add_var(pdu, smioid->ptr,
  714.                (int) smioid->len, &smival);
  715.   freeSmivalDescriptor(&smival);
  716.   Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
  717.   int sendbufferlen= MAX_SNMP_PACKET;
  718.   status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
  719.        own_engine_id_oct, sName, sModel, sLevel,
  720.        OctetStr(cEngineID, cEngineIDLength),
  721.        OctetStr(cName, cNameLength));
  722.   if (status != SNMPv3_MP_OK) {
  723.     debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
  724.     return SNMPv3_MP_ERROR;
  725.   }
  726.   SnmpSocket send_fd = INVALID_SOCKET;
  727.   if (pdu_type == sNMP_PDU_INFORM)
  728.   {
  729.     debugprintf(4, "Received a snmpInform pdu.");
  730.     if (snmp_session->eventListHolder->notifyEventList())
  731.       send_fd = snmp_session->eventListHolder->notifyEventList()->get_notify_fd();
  732.   }
  733.   status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
  734.                                        (size_t)sendbufferlen,// pdu to send
  735.                destination,          // target address
  736.                send_fd);             // the fd to use
  737.   if ( status != 0)
  738.   {
  739.     debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
  740.     return SNMPv3_MP_ERROR;
  741.   }
  742.   debugprintf(3, "v3MP::send_report: Report sent.");
  743.   return SNMPv3_MP_OK;
  744. }
  745. // Parse the given buffer as a SNMPv3-Message.
  746. int v3MP::snmp_parse(Snmp *snmp_session,
  747.                      struct snmp_pdu *pdu,
  748.                      unsigned char *inBuf,
  749.                      int inBufLength,
  750.                      OctetStr &securityEngineID,
  751.                      OctetStr &securityName,
  752.                      OctetStr &contextEngineID,
  753.                      OctetStr &contextName,
  754.                      long     &securityLevel,
  755.                      long     &msgSecurityModel,
  756.                      snmp_version &spp_version,
  757.                      UdpAddress from_address)
  758. {
  759.   debugprintf(3, "mp is parsing incoming message:");
  760.   debughexprintf(25, inBuf, inBufLength);
  761.   if (inBufLength > MAX_SNMP_PACKET)
  762.     return  SNMPv3_MP_ERROR;
  763.   unsigned char type;
  764.   long version;
  765.   int origLength = inBufLength;
  766.   unsigned char *inBufPtr = inBuf;
  767.   long msgID, msgMaxSize;
  768.   unsigned char msgFlags;
  769.   Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
  770.   Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
  771.   int msgSecurityParametersLength = inBufLength,   msgDataLength = inBufLength;
  772.   Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
  773.   int scopedPDULength = MAX_SNMP_PACKET;
  774.   long  maxSizeResponseScopedPDU = 0;
  775.   struct SecurityStateReference *securityStateReference = NULL;
  776.   int securityParametersPosition;
  777.   int rc;
  778.   int errorCode = 0;
  779.   // get the type
  780.   inBuf = asn_parse_header( inBuf, &inBufLength, &type);
  781.   if (inBuf == NULL){
  782.     debugprintf(0, "snmp_parse: bad header");
  783.     return SNMPv3_MP_PARSE_ERROR;
  784.   }
  785.   if (type != (ASN_SEQ_CON)){
  786.     debugprintf(0, "snmp_parse: wrong auth header type");
  787.     return SNMPv3_MP_PARSE_ERROR;
  788.   }
  789.   if (origLength != inBufLength + (inBuf - inBufPtr)) {
  790.     debugprintf(0, "snmp_parse: wrong length of received packet");
  791.     return SNMPv3_MP_PARSE_ERROR;
  792.   }
  793.   // get the version
  794.   inBuf = asn_parse_int(inBuf, &inBufLength,
  795.                         &type, &version, sizeof(version));
  796.   if (inBuf == NULL){
  797.     debugprintf(0, "snmp_parse: bad parse of version");
  798.     return SNMPv3_MP_PARSE_ERROR;
  799.   }
  800.   debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);
  801.   if ( version != SNMP_VERSION_3 )
  802.     return SNMPv3_MP_PARSE_ERROR;
  803.   spp_version = (snmp_version) version;
  804.   inBuf = asn1_parse_header_data(inBuf, &inBufLength,
  805.  &msgID, &msgMaxSize,
  806.  &msgFlags, &msgSecurityModel);
  807.   if (inBuf == NULL){
  808.     debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
  809.     return SNMPv3_MP_PARSE_ERROR;
  810.   }
  811.   pdu->msgid = msgID;
  812.   if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
  813.     debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
  814.     return SNMPv3_MP_PARSE_ERROR;
  815.   }
  816.   // do not allow larger messages than this entity can handle
  817.   if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
  818.   pdu->maxsize_scopedpdu = msgMaxSize;
  819.   inBuf = asn_parse_string( inBuf, &inBufLength, &type,
  820.                             msgSecurityParameters.get_ptr(),
  821.                             &msgSecurityParametersLength);
  822.   if (inBuf == NULL){
  823.     debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
  824.     return SNMPv3_MP_PARSE_ERROR;
  825.   }
  826.   securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;
  827.   // the rest of the message is passed directly to the security module
  828.   msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
  829.   memcpy(msgData.get_ptr(), inBuf, msgDataLength);
  830.   debugprintf(3, "Parsed msgdata length(0x%x), "
  831.       "msgSecurityParameters length(0x%x)", msgDataLength,
  832.       msgSecurityParametersLength);
  833.   switch (msgFlags & 0x03) {
  834.     case 3:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV;     break;}
  835.     case 0:  { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
  836.     case 1:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;   break;}
  837.     default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
  838.                snmpInvalidMsgs++;
  839.                // do not send back report
  840.                return SNMPv3_MP_INVALID_MESSAGE;
  841.                break;
  842.              }
  843.   }
  844.   bool reportableFlag;
  845.   if (msgFlags & 0x04) reportableFlag = TRUE;
  846.   else                 reportableFlag = FALSE;
  847.   securityStateReference = usm->get_new_sec_state_reference();
  848.   if (!securityStateReference)
  849.     return SNMPv3_MP_ERROR;
  850.   switch (msgSecurityModel) {
  851.     case SecurityModel_USM:
  852.       {
  853.         rc = usm->process_msg(
  854.                            msgMaxSize,
  855.                            msgSecurityParameters.get_ptr(),
  856.    msgSecurityParametersLength,
  857.                            securityParametersPosition,
  858.                            securityLevel,
  859.                            inBufPtr, origLength, //wholeMsg
  860.                            msgData.get_ptr(), msgDataLength,
  861.                            securityEngineID,
  862.                            securityName,
  863.                            scopedPDU.get_ptr(), &scopedPDULength,
  864.                            &maxSizeResponseScopedPDU,
  865.                            securityStateReference,
  866.    from_address);
  867.         pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
  868.         if (rc != SNMPv3_USM_OK) {
  869.           if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
  870.             errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
  871.           }
  872.           else {
  873.             // error handling! rfc2262 page 31
  874.             debugprintf(0, "mp: error while executing USM::process_msg");
  875.             errorCode = rc;
  876.           }
  877.         }
  878.         if (errorCode != SNMPv3_USM_PARSE_ERROR)
  879.           if (securityEngineID.len() == 0)
  880.             errorCode = SNMPv3_MP_INVALID_ENGINEID;
  881.         break;
  882.       }
  883.     default: {
  884.         snmpUnknownSecurityModels++;
  885. usm->delete_sec_state_reference(securityStateReference);
  886.         debugprintf(0, "SecurityModel of incomming Message not supported!");
  887.         // Message should be dropped without a report
  888.         return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
  889.       }
  890.   }
  891.   // process scopedPDU
  892.   debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);
  893.   unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
  894.   unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
  895.   unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
  896.   int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
  897.   int tmp_contextNameLength     = MAXLENGTH_CONTEXT_NAME;
  898.   unsigned char *data;
  899.   int dataLength;
  900.   debugprintf(1,"ErrorCode is %i",errorCode);
  901.   if (!errorCode) {
  902.     data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
  903.  tmp_contextEngineID,
  904.  &tmp_contextEngineIDLength,
  905.  tmp_contextName, &tmp_contextNameLength);
  906.     if (data == NULL) {
  907.       debugprintf(0, "mp: Error Parsing scopedPDU!");
  908.       usm->delete_sec_state_reference(securityStateReference);
  909.       return SNMPv3_MP_PARSE_ERROR;
  910.     }
  911.     dataLength = scopedPDULength;
  912.     contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
  913.     contextName.set_data(tmp_contextName, tmp_contextNameLength);
  914.     // parse data of scopedPDU
  915.     if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
  916.       debugprintf(0, "mp: Error parsing PDU!");
  917.       usm->delete_sec_state_reference(securityStateReference);
  918.       return SNMPv3_MP_PARSE_ERROR;
  919.     }
  920.     if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
  921.       debugprintf(0, "mp: Error parsing Vb");
  922.       usm->delete_sec_state_reference(securityStateReference);
  923.       return SNMPv3_MP_PARSE_ERROR;
  924.     }
  925.     if ((tmp_contextEngineIDLength == 0) &&
  926.         ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
  927.          (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
  928.          (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
  929.          (pdu->command == TRP2_REQ_MSG)))
  930.     {
  931.       //  RFC 2572