Ejemplo n.º 1
0
//=======[ create an octet string from a hex string ]===================
OctetStr OctetStr::from_hex_string(const OctetStr &hex_string)
{
  OctetStr val;
  unsigned int p;
  unsigned int hex_len = 0;

  // make sure the string has at least one byte
  if (hex_string.len() == 0) return val;

  // allocate max needed space for copy without spaces
  unsigned char *hex, *hex_ptr;
  hex = hex_ptr = new unsigned char[hex_string.len()];
  if (!hex) return val;

  // delete spaces
  const unsigned char *ptr = hex_string.smival.value.string.ptr;
  for (p = hex_string.len(); p > 0; p--)
  {
    unsigned char c = *ptr++;
    if (c != ' ')
    {
      *hex_ptr++ = c;
      ++hex_len;
    }
  }

  // leading 0 may be omitted
  if (hex_len % 2)
  {
    unsigned char c = hex[0];
    ATOI(c);
    val += c;
    p = 1;
  }
  else
  {
    p = 0;
  }

  while (p < hex_len)
  {
    unsigned char c = hex[p++];
    unsigned char d = hex[p++];

    ATOI(c);
    ATOI(d);
    val += (c*16 + d);
  }
  delete[] hex;
  return val;
}
int agentppTestSparseCol3::prepare_set_request(Request* req, int& ind)
{
	int status;
	if ((status = MibLeaf::prepare_set_request(req, ind)) !=
	    SNMP_ERROR_SUCCESS) return status;

	Vb vb(req->get_value(ind));
	OctetStr v;
	vb.get_value(v);
	if (!(((v.len() >= 0) && (v.len() <= 255))))
		 return SNMP_ERROR_WRONG_LENGTH;
	//--AgentGen BEGIN=agentppTestSparseCol3::prepare_set_request
	//--AgentGen END
	return SNMP_ERROR_SUCCESS;
}
Ejemplo n.º 3
0
int CSVBaseSNMP::InitUTarget()
{
    int nResult = 0;

    m_Utarget = address;                                //construct UTarger By address Class
    m_Utarget.set_version(version);                     // set the SNMP version SNMPV1 or V2 or V3
    m_Utarget.set_retry(m_nRetries);                    // set the number of auto retries
    m_Utarget.set_timeout(m_nTimeout);                  // set timeout
    m_Utarget.set_security_model(m_lSecurityModel);     //Set Security Model
    m_Utarget.set_security_name(m_szSecurityName);      //Set Security Name (Auth Name)

    OctetStr EgID;//Engine ID
    //Get Engine ID
//    if(m_pSnmp)
//      nResult = m_pSnmp->unicast_discovery(EgID, (m_nTimeout + 99) / 100, address, version, &m_szCommunity);

    if(EgID.len() > 0)
    {//Engine ID Length Big Than 0
        m_Utarget.set_engine_id(EgID);                  //Set Engine ID
    }
    else
    {//Less Than 0
        return 1;                                       //return Failed
    }
    return 0;                                           //retrun Successed
}
Ejemplo n.º 4
0
// Get the engine_id of the SNMP entity at the given host/port.
int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
                                   const OctetStr &hostport) const
{
  int port;
  char host[MAX_HOST_NAME_LENGTH + 1];
  char *ptr;

  /* Check length */
  if (hostport.len() > MAX_HOST_NAME_LENGTH)
    return SNMPv3_MP_ERROR;

  /* split up port from hostport */
  strcpy(host, hostport.get_printable());

  ptr = strstr((char*)host,"/");
  if (!ptr)
    return SNMPv3_MP_ERROR;

  *ptr = '\0';
  port = atol(ptr + 1);

  /* Check for IPv6 address with [] */
  if (host[0] == '[')
  {
    if (*(ptr -1) == ']')
    {
      *(ptr-1) = '\0';
      return get_entry(engine_id, &(host[1]), port);
    }
    else
      return SNMPv3_MP_ERROR;
  }
  return get_entry(engine_id, host, port);
}
Ejemplo n.º 5
0
// Initialize the v3MP.
v3MP::v3MP(const OctetStr& snmpEngineID,
           unsigned int engineBoots, int &construct_status)
  : own_engine_id(0), usm(0)
{
  if (I)
  {
    debugprintf(0, "v3MP: You must not create two objects of this class!");
    construct_status = SNMPv3_MP_ERROR;
    return;
  }

  I = this;

  snmpUnknownSecurityModels = 0;
  snmpInvalidMsgs = 0;
  snmpUnknownPDUHandlers = 0;

  int length = snmpEngineID.len();
  if (length > MAXLENGTH_ENGINEID)
    length = MAXLENGTH_ENGINEID;

  own_engine_id = v3strcpy(snmpEngineID.data(), length);
  own_engine_id_len = length;
  own_engine_id_oct = snmpEngineID;

  int result;
  usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);

  if (cur_msg_id >= MAX_MPMSGID)
    cur_msg_id = 1;

  if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
  {
    construct_status = SNMPv3_MP_ERROR;
    return;
  }

  cache.set_usm(usm);
  construct_status = SNMPv3_MP_OK;
}
Ejemplo n.º 6
0
/////////////////////////////////////////////////////////////////////////////
// 函数:InitUTarget                                                       //
// 说明:当SNMP版本是3时,初始化Utarget                                    //
// 参数:                                                                  //
//		无                                                                 //
// 返回:                                                                  //
//		成功返回0,否则返回1                                               //
/////////////////////////////////////////////////////////////////////////////
int BasicSNMP::InitUTarget()
{
	int nResult = 0;
	utarget = address;//construct UTarger By address Class
	utarget.set_version(version);          // set the SNMP version SNMPV1 or V2 or V3
	utarget.set_retry(retries);            // set the number of auto retries
	utarget.set_timeout(timeout);          // set timeout
	utarget.set_security_model(m_nSecurityModel);//Set Security Model
	utarget.set_security_name( securityName);//Set Security Name (Auth Name)
	OctetStr EgID;//Engine ID
	//Get Engine ID
	nResult = pSnmp->unicast_discovery(EgID,
				       (timeout + 99) / 100,
				       address, version, &community);
	if(EgID.len()>0)
	{//Engine ID Length Big Than 0
		utarget.set_engine_id(EgID);//Set Engine ID
	}
	else
	{//Less Than 0
		return 1;//return Failed
	}
	return 0;//retrun Successed
}
Ejemplo n.º 7
0
// Parse the given buffer as a SNMPv3-Message.
int v3MP::snmp_parse(Snmp *snmp_session,
                     struct snmp_pdu *pdu,
                     unsigned char *inBuf,
                     int inBufLength,
                     OctetStr &securityEngineID,
                     OctetStr &securityName,
                     OctetStr &contextEngineID,
                     OctetStr &contextName,
                     long     &securityLevel,
                     long     &msgSecurityModel,
                     snmp_version &spp_version,
                     UdpAddress from_address)
{
  debugprintf(3, "mp is parsing incoming message:");
  debughexprintf(25, inBuf, inBufLength);

  if (inBufLength > MAX_SNMP_PACKET)
    return  SNMPv3_MP_ERROR;

  unsigned char type;
  long version;
  int origLength = inBufLength;
  unsigned char *inBufPtr = inBuf;
  long msgID, msgMaxSize;
  unsigned char msgFlags;
  Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
  Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
  int msgSecurityParametersLength = inBufLength,   msgDataLength = inBufLength;
  Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
  int scopedPDULength = MAX_SNMP_PACKET;
  long  maxSizeResponseScopedPDU = 0;
  struct SecurityStateReference *securityStateReference = NULL;
  int securityParametersPosition;
  int rc;
  int errorCode = 0;

  // get the type
  inBuf = asn_parse_header( inBuf, &inBufLength, &type);
  if (inBuf == NULL){
    debugprintf(0, "snmp_parse: bad header");
    return SNMPv3_MP_PARSE_ERROR;
  }

  if (type != (ASN_SEQ_CON)){
    debugprintf(0, "snmp_parse: wrong auth header type");
    return SNMPv3_MP_PARSE_ERROR;
  }

  if (origLength != inBufLength + (inBuf - inBufPtr)) {
    debugprintf(0, "snmp_parse: wrong length of received packet");
    return SNMPv3_MP_PARSE_ERROR;
  }

  // get the version
  inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version);
  if (inBuf == NULL){
    debugprintf(0, "snmp_parse: bad parse of version");
    return SNMPv3_MP_PARSE_ERROR;
  }

  debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);

  if ( version != SNMP_VERSION_3 )
    return SNMPv3_MP_PARSE_ERROR;

  spp_version = (snmp_version) version;

  inBuf = asn1_parse_header_data(inBuf, &inBufLength,
				 &msgID, &msgMaxSize,
				 &msgFlags, &msgSecurityModel);

  if (inBuf == NULL){
    debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
    return SNMPv3_MP_PARSE_ERROR;
  }

  pdu->msgid = msgID;
  if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
    debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
    return SNMPv3_MP_PARSE_ERROR;
  }

  // do not allow larger messages than this entity can handle
  if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
  pdu->maxsize_scopedpdu = msgMaxSize;

  inBuf = asn_parse_string( inBuf, &inBufLength, &type,
                            msgSecurityParameters.get_ptr(),
                            &msgSecurityParametersLength);

  if (inBuf == NULL){
    debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
    return SNMPv3_MP_PARSE_ERROR;
  }

  securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;

  // the rest of the message is passed directly to the security module

  msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
  memcpy(msgData.get_ptr(), inBuf, msgDataLength);

  debugprintf(3, "Parsed msgdata length(0x%x), "
	      "msgSecurityParameters length(0x%x)", msgDataLength,
	      msgSecurityParametersLength);

  switch (msgFlags & 0x03) {
    case 3:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV;     break;}
    case 0:  { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
    case 1:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;   break;}
    default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
               snmpInvalidMsgs++;
               // do not send back report
               return SNMPv3_MP_INVALID_MESSAGE;
               break;
             }
  }

  bool reportableFlag;

  if (msgFlags & 0x04) reportableFlag = true;
  else                 reportableFlag = false;

  securityStateReference = usm->get_new_sec_state_reference();
  if (!securityStateReference)
    return SNMPv3_MP_ERROR;

  switch (msgSecurityModel) {
    case SNMP_SECURITY_MODEL_USM:
      {
        rc = usm->process_msg(
                           msgMaxSize,
                           msgSecurityParameters.get_ptr(),
			   msgSecurityParametersLength,
                           securityParametersPosition,
                           securityLevel,
                           inBufPtr, origLength, //wholeMsg
                           msgData.get_ptr(), msgDataLength,
                           securityEngineID,
                           securityName,
                           scopedPDU.get_ptr(), &scopedPDULength,
                           &maxSizeResponseScopedPDU,
                           securityStateReference,
			   from_address);
        pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
        if (rc != SNMPv3_USM_OK) {
          if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
            errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
          }
          else {
            // error handling! rfc2262 page 31
            debugprintf(0, "mp: error while executing USM::process_msg");
            errorCode = rc;
          }
        }
        if (errorCode != SNMPv3_USM_PARSE_ERROR)
          if (securityEngineID.len() == 0)
            errorCode = SNMPv3_MP_INVALID_ENGINEID;
        break;
      }
    default: {
        snmpUnknownSecurityModels++;
	usm->delete_sec_state_reference(securityStateReference);
        debugprintf(0, "SecurityModel of incomming Message not supported!");
        // Message should be dropped without a report
        return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
      }
  }
  // process scopedPDU
  debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);

  unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
  unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
  unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
  int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
  int tmp_contextNameLength     = MAXLENGTH_CONTEXT_NAME;

  unsigned char *data;
  int dataLength;

  debugprintf(1,"ErrorCode is %i",errorCode);

  if (!errorCode) {
    data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
				 tmp_contextEngineID,
				 &tmp_contextEngineIDLength,
				 tmp_contextName, &tmp_contextNameLength);
    if (data == NULL) {
      debugprintf(0, "mp: Error Parsing scopedPDU!");
      usm->delete_sec_state_reference(securityStateReference);
      return SNMPv3_MP_PARSE_ERROR;
    }
    dataLength = scopedPDULength;
    contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
    contextName.set_data(tmp_contextName, tmp_contextNameLength);

    // parse data of scopedPDU
    if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
      debugprintf(0, "mp: Error parsing PDU!");
      usm->delete_sec_state_reference(securityStateReference);
      return SNMPv3_MP_PARSE_ERROR;
    }
    if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
      debugprintf(0, "mp: Error parsing Vb");
      usm->delete_sec_state_reference(securityStateReference);
      return SNMPv3_MP_PARSE_ERROR;
    }
    if ((tmp_contextEngineIDLength == 0) &&
        ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
         (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
         (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
         (pdu->command == TRP2_REQ_MSG)))
    {
      //  RFC 2572 � 4.2.2.1 (2a)
      debugprintf(2, "mp: received request message with zero length"
                  " contextEngineID -> unknownPduHandlers.");
      inc_stats_unknown_pdu_handlers();
      errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
    }
  }
  if (errorCode) {
    if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) {
      // error occured: prepare reportpdu in agent
      cache.add_entry(msgID, pdu->reqid, securityEngineID,
                      msgSecurityModel,
                      securityName, securityLevel, "", "",
                      securityStateReference, errorCode, CACHE_REMOTE_REQ);

      send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode,
		  securityLevel, msgSecurityModel, securityName,
		  from_address, snmp_session);
      clear_pdu(pdu, true);   // Clear pdu and free all content AND IDs!
    }
    else {
      usm->delete_sec_state_reference(securityStateReference);
    }
    return errorCode;
  }

  struct Cache::Entry_T centry;

  if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) {
    rc = cache.get_entry(msgID, true, &centry);
    if (rc != SNMPv3_MP_OK) {
      // RFC 2572 � 4
      debugprintf(2, "Received rspMsg without outstanding request."
                  " -> SnmpUnknownPduHandler");
      usm->delete_sec_state_reference(securityStateReference);
      inc_stats_unknown_pdu_handlers();
      return SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
    }
    if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff))
	&& (pdu->command == REPORT_MSG))
      pdu->reqid = centry.req_id;
#ifdef BUGGY_REPORT_REQID
    if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG))
    {
      debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)",  pdu->reqid, centry.req_id);
      pdu->reqid = centry.req_id;
    }
#endif
  }

  if (pdu->command == REPORT_MSG) {
    // !! rfc2262 page 33

    debugprintf(2, "*** Receiving a ReportPDU ***");
    if (/*((securityEngineID != centry.sec_engine_id)
	  && (centry.sec_engine_id.len() != 0)) ||*/
        ((msgSecurityModel != centry.sec_model)
         && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) ||
        ((securityName != centry.sec_name)
         && (securityName.len() != 0)))
    {
      debugprintf(0, "Received report message doesn't match sent message!");
      usm->delete_sec_state_reference(securityStateReference);
      return SNMPv3_MP_MATCH_ERROR;
    }
    usm->delete_sec_state_reference(securityStateReference);
    cache.delete_content(centry);
    debugprintf(1, "mp finished (OK)");
    return SNMPv3_MP_OK;
  }

  if (pdu->command == GET_RSP_MSG) {
    if (((securityEngineID != centry.sec_engine_id)
         && (centry.sec_engine_id.len() != 0)) ||
        (msgSecurityModel != centry.sec_model) ||
        (securityName != centry.sec_name) ||
        (securityLevel != centry.sec_level) ||
        ((contextEngineID != centry.context_engine_id)
         && (centry.context_engine_id.len() != 0))||
        ((contextName != centry.context_name)
         && (centry.context_name.len() != 0))) {
      debugprintf(0, "Received response message doesn't match sent message!");
      usm->delete_sec_state_reference(securityStateReference);
      cache.delete_content(centry);
      return SNMPv3_MP_MATCH_ERROR;
    }
    usm->delete_sec_state_reference(securityStateReference);
    cache.delete_content(centry);
    debugprintf(1, "mp finished (OK)");
    return SNMPv3_MP_OK;
  }

  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
      (pdu->command == INFORM_REQ_MSG)) {
    if (securityEngineID.len() == 0) {
      debugprintf(2, "Received Message with engineID = 0.");
    }
    else {
      if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(),
                                own_engine_id, own_engine_id_len))) {
        debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id.");
	/* we are authoritative but engine id of message is wrong
	   if discovery in USM is enabled:
	   - remove automatically added illegal engine id from USM tables
	   - send a report
	*/
	if (usm->is_discovery_enabled())
	{
	  // TODO: try to remove engine id from USM
	  if (reportableFlag)
	  {
	    cache.add_entry(msgID, pdu->reqid, securityEngineID,
			    msgSecurityModel,
			    securityName, securityLevel, "", "",
			    securityStateReference,
			    SNMPv3_MP_INVALID_ENGINEID,
			    CACHE_REMOTE_REQ);

	    send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID,
			SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel,
			securityName, from_address, snmp_session);
	    clear_pdu(pdu, true);  // Clear pdu and free all content AND IDs!
	  }
	  else
	  {
	    usm->delete_sec_state_reference(securityStateReference);
	  }
	  return SNMPv3_MP_INVALID_ENGINEID;
	}

        usm->delete_sec_state_reference(securityStateReference);
        return SNMPv3_MP_MATCH_ERROR;
      }
    }
    int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID,
                              msgSecurityModel, securityName,
                              securityLevel, contextEngineID,
                              contextName, securityStateReference,
                              SNMPv3_MP_OK, CACHE_REMOTE_REQ);
    if (ret == SNMPv3_MP_DOUBLED_MESSAGE) {
      debugprintf(0, "*** received doubled message ***");
      // message will be ignored so return OK
      usm->delete_sec_state_reference(securityStateReference);
    }

    debugprintf(1, "mp: parsing finished (ok).");
    return SNMPv3_MP_OK;
  }

  if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))
  {
    usm->delete_sec_state_reference(securityStateReference);
    return SNMPv3_MP_OK;
  }

  debugprintf(0, "mp error: This line should not be executed.");
  usm->delete_sec_state_reference(securityStateReference);
  return SNMPv3_MP_ERROR;
}
Ejemplo n.º 8
0
// Do the complete process of encoding the given values into the buffer
// ready to send to the target.
int v3MP::snmp_build(struct snmp_pdu *pdu,
		     unsigned char *packet,
		     int *out_length,             // maximum Bytes in packet
		     const OctetStr &securityEngineID,
		     const OctetStr &securityName,
		     int securityModel,
		     int securityLevel,
		     const OctetStr &contextEngineID,
		     const OctetStr &contextName)
{
  Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
  unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
  unsigned char globalData[MAXLENGTH_GLOBALDATA];
  int globalDataLength = MAXLENGTH_GLOBALDATA;
  int scopedPDULength, maxLen = *out_length;
  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
  unsigned char *bufPtr = buf.get_ptr();
  long bufLength = 0, rc;
  int msgID;
  int cachedErrorCode = SNMPv3_MP_OK;
  struct SecurityStateReference *securityStateReference = NULL;
  int isRequestMessage = 0;

  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
      (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
      (pdu->command == TRP2_REQ_MSG))
    isRequestMessage = 1;

  if (isRequestMessage) {
    if (securityEngineID.len() == 0) {
      // First Contact => use user  noAuthNoPriv and USM
      securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
      securityModel = SNMP_SECURITY_MODEL_USM;
    }

    cur_msg_id_lock.lock();
    msgID = cur_msg_id;
    cur_msg_id++;
    if (cur_msg_id >= MAX_MPMSGID)
      cur_msg_id = 1;
    cur_msg_id_lock.unlock();

#ifdef INVALID_MSGID
    LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
    LOG("*** WARNING: Using constant MessageID! ***");
    LOG_END;

    msgID = 0xdead;
#endif

    if (securityEngineID.len() == 0) {
      // length==0 => SecurityLevel == noAuthNoPriv
      //  => we do not send any management information
      //  => delete VariableBinding
      clear_pdu(pdu);
    }
  }
  else {
    // it is a response => search for request
    debugprintf(3, "Looking up cache");
    msgID = pdu->msgid;
    rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
                         &cachedErrorCode, &securityStateReference);

    if (rc != SNMPv3_MP_OK) {

      debugprintf(0, "mp: Cache lookup error");
      return SNMPv3_MP_MATCH_ERROR;
    }
  }

  LOG_BEGIN(loggerModuleName, DEBUG_LOG | 5);
  LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
  LOG(securityEngineID.get_printable());
  LOG(securityName.get_printable());
  LOG(securityLevel);
  LOG(contextEngineID.get_printable());
  LOG(contextName.get_printable());
  LOG_END;

  // encode vb in buf
  scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
  if (!scopedPDUPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding vbs into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }
  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());

  //build dataPDU in buf
  maxLen = *out_length;
  scopedPDUPtr = scopedPDU.get_ptr();
  bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);

  if (!bufPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding data pdu into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }

  bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());

  //  serialize scopedPDU
  maxLen = *out_length;
  scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
				       contextEngineID.data(),
				       contextEngineID.len(),
				       contextName.data(), contextName.len(),
				       buf.get_ptr(), bufLength);

  if (!scopedPDUPtr)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("v3MP: Error encoding scoped pdu into buffer");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }

  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());

  // build msgGlobalData
  unsigned char *globalDataPtr = (unsigned char *)&globalData;
  unsigned char msgFlags;
  switch (securityLevel) {
    case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
      { msgFlags = 0 ; break;}
    case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
      { msgFlags = SNMPv3_AUTHFLAG; break;}
    case SNMP_SECURITY_LEVEL_AUTH_PRIV:
      { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
    default:
    {
      LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
      LOG("v3MP: Unknown security level requested, will use authPriv");
      LOG(securityLevel);
      LOG_END;

      msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
    }
  }

  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
      (pdu->command == INFORM_REQ_MSG))
    msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;

  globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
					 msgID, *out_length,  // maxMessageSize
					 msgFlags, securityModel);
  if (!globalDataPtr)
  {
    LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
    LOG("v3MP: Error building header data");
    LOG_END;

    return SNMPv3_MP_BUILD_ERROR;
  }
  globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);

  switch (securityModel) {
    case SNMP_SECURITY_MODEL_USM: {
      int use_own_engine_id = 0;
      if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
          (pdu->command == REPORT_MSG)  || (pdu->command == TRP2_REQ_MSG)) {
        use_own_engine_id = 1;
      }

      rc = usm->generate_msg(globalData, globalDataLength, *out_length,
                             (use_own_engine_id ?
                                        own_engine_id_oct : securityEngineID),
                             securityName, securityLevel,
                             scopedPDU.get_ptr(), scopedPDULength,
                             securityStateReference, packet, out_length);

      if ( rc == SNMPv3_USM_OK ) {
        // build cache
        if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
              (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
          cache.add_entry(msgID, pdu->reqid, securityEngineID,
                          securityModel, securityName, securityLevel,
                          contextEngineID, contextName, securityStateReference,
                          SNMPv3_MP_OK, CACHE_LOCAL_REQ);

	LOG_BEGIN(loggerModuleName, INFO_LOG | 3);
	LOG("v3MP: Message built OK");
	LOG_END;

        return SNMPv3_MP_OK;
      }
      else
      {
	LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
	LOG("v3MP: Returning error for building message");
	LOG(rc);
	LOG_END;

        return rc;
      }
    }
    default:
    {
      LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
      LOG("v3MP: Should build message with unsupported securityModel");
      LOG(securityModel);
      LOG_END;

      return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
    }
  }
}
Ejemplo n.º 9
0
int CNotifyEventQueue::AddEntry(Snmp *snmp,
                                const OidCollection &trapids,
                                const TargetCollection &targets)
{
  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()

  if (snmp != m_snmpSession)
  {
    debugprintf(0, "WARNING: Adding notification event for other Snmp object");
  }

  if (!m_msgCount)
  {
    m_notify_addr = snmp->get_listen_address();
    m_notify_addr.set_port(m_listen_port);

    int status = SNMP_CLASS_SUCCESS;

    // This is the first request to receive notifications
    // Set up the socket for the snmp trap port (162) or the
    // specified port through set_listen_port()
    bool is_v4_address = (m_notify_addr.get_ip_version() == Address::version_ipv4);
    if (is_v4_address)
    {
      struct sockaddr_in mgr_addr;

      // open a socket to be used for the session
      if ((m_notify_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (WSAEHOSTDOWN == werr)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#else
        if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (EHOSTDOWN == errno)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
        cleanup();
        return status;
      }

      // set up the manager socket attributes
      unsigned long inaddr = inet_addr(IpAddress(m_notify_addr).get_printable());
      memset(&mgr_addr, 0, sizeof(mgr_addr));
      mgr_addr.sin_family = AF_INET;
      mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
      mgr_addr.sin_port = htons(m_notify_addr.get_port());
#ifdef CYGPKG_NET_OPENBSD_STACK
      mgr_addr.sin_len = sizeof(mgr_addr);
#endif

      // bind the socket
      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
               sizeof(mgr_addr)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (WSAEADDRINUSE  == werr)
          status = SNMP_CLASS_TL_IN_USE;
        else if (WSAENOBUFS == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (werr == WSAEAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (werr == WSAENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (werr == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
          status = SNMP_CLASS_INTERNAL_ERROR;
#else
        if (EADDRINUSE  == errno)
          status = SNMP_CLASS_TL_IN_USE;
        else if (ENOBUFS == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (errno == EAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (errno == ENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (errno == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
        {
          debugprintf(0, "Uncatched errno value %d, returning internal error.",
                      errno);
          status = SNMP_CLASS_INTERNAL_ERROR;
        }
#endif
        debugprintf(0, "Fatal: could not bind to %s",
                    m_notify_addr.get_printable());
        cleanup();
        return status;
      }

      debugprintf(3, "Bind to %s for notifications, fd %d.",
                  m_notify_addr.get_printable(), m_notify_fd);
    } // is_v4_address
    else
    {
      // not is_v4_address
#ifdef SNMP_PP_IPv6
      // open a socket to be used for the session
      if ((m_notify_fd = socket(AF_INET6, SOCK_DGRAM,0)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (WSAEHOSTDOWN == werr)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#else
        if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (EHOSTDOWN == errno)
          status = SNMP_CLASS_TL_FAILED;
        else
          status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
        cleanup();
        return status;
      }

#ifdef NOTIFY_SET_IPV6_V6ONLY
      int on = 1;
      if (setsockopt(m_notify_fd, IPPROTO_IPV6, IPV6_V6ONLY,
		     (char *)&on, sizeof(on)) == -1)
      {
        LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
        LOG("Could not set option IPV6_V6ONLY on notify socket (errno)");
        LOG(errno);
        LOG_END;
      }
      else
      {
        LOG_BEGIN(loggerModuleName, INFO_LOG | 3);
        LOG("Have set IPV6_V6ONLY option on notify socket");
        LOG_END;
      }
#endif

      // set up the manager socket attributes
      struct sockaddr_in6 mgr_addr;
      memset(&mgr_addr, 0, sizeof(mgr_addr));

      unsigned int scope = 0;

      OctetStr addrstr = ((IpAddress &)m_notify_addr).IpAddress::get_printable();

      if (m_notify_addr.has_ipv6_scope())
      {
        scope = m_notify_addr.get_scope();

        int y = addrstr.len() - 1;
        while ((y>0) && (addrstr[y] != '%'))
        {
          addrstr.set_len(addrstr.len() - 1);
          y--;
        }
        if (addrstr[y] == '%')
          addrstr.set_len(addrstr.len() - 1);
      }

      if (inet_pton(AF_INET6, addrstr.get_printable(),
                    &mgr_addr.sin6_addr) < 0)
      {
	LOG_BEGIN(loggerModuleName, ERROR_LOG | 1);
        LOG("Notify transport: inet_pton returns (errno) (str)");
        LOG(errno);
        LOG(strerror(errno));
        LOG_END;
        cleanup();
        return SNMP_CLASS_INVALID_ADDRESS;
      }

      mgr_addr.sin6_family = AF_INET6;
      mgr_addr.sin6_port = htons(m_notify_addr.get_port());
      mgr_addr.sin6_scope_id = scope;

      // bind the socket
      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
               sizeof(mgr_addr)) < 0)
      {
#ifdef WIN32
        int werr = WSAGetLastError();
        if (WSAEADDRINUSE  == werr)
          status = SNMP_CLASS_TL_IN_USE;
        else if (WSAENOBUFS == werr)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (werr == WSAEAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (werr == WSAENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (werr == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
          status = SNMP_CLASS_INTERNAL_ERROR;
#else
        if (EADDRINUSE  == errno)
          status = SNMP_CLASS_TL_IN_USE;
        else if (ENOBUFS == errno)
          status = SNMP_CLASS_RESOURCE_UNAVAIL;
        else if (errno == EAFNOSUPPORT)
          status = SNMP_CLASS_TL_UNSUPPORTED;
        else if (errno == ENETUNREACH)
          status = SNMP_CLASS_TL_FAILED;
        else if (errno == EACCES)
          status = SNMP_CLASS_TL_ACCESS_DENIED;
        else
        {
          debugprintf(0, "Uncatched errno value %d, returning internal error.",
                      errno);
          status = SNMP_CLASS_INTERNAL_ERROR;
        }
#endif
        debugprintf(0, "Fatal: could not bind to %s",
                    m_notify_addr.get_printable());
        cleanup();
        return status;
      }
      debugprintf(3, "Bind to %s for notifications, fd %d.",
                  m_notify_addr.get_printable(), m_notify_fd);
#else
      debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
      cleanup();
      return SNMP_CLASS_TL_UNSUPPORTED;
#endif
    } // not is_v4_address
  }

  CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets);

  /*---------------------------------------------------------*/
  /* Insert entry at head of list, done automagically by the */
  /* constructor function, so don't use the return value.    */
  /*---------------------------------------------------------*/
  (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
  m_msgCount++;

  return SNMP_CLASS_SUCCESS;
}
Ejemplo n.º 10
0
// Store the bootCounter of the given engineID in the given file.
int saveBootCounter(const char *fileName,
                    const OctetStr &engineId, const unsigned int boot)
{
  char line[MAX_LINE_LEN];
  char tmpFileName[MAXLENGTH_FILENAME];
  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
  int found = FALSE;
  int len = engineId.len();
  FILE *file_in, *file_out;

  tmpFileName[0] = 0;
  sprintf(tmpFileName, "%s.tmp",fileName);
  if (len > MAXLENGTH_ENGINEID)
  {
    LOG_BEGIN(ERROR_LOG | 3);
    LOG("saveBootCounter: engine id too long, ignoring last bytes (len) (max)");
    LOG(len);
    LOG(MAXLENGTH_ENGINEID);
    LOG_END;

    len = MAXLENGTH_ENGINEID;
  }

  file_in = fopen(fileName, "r");
  if (!file_in)
  {
    file_in = fopen(fileName, "w");
    if (!file_in)
    {
      LOG_BEGIN(ERROR_LOG | 3);
      LOG("saveBootCounter: could not create new file (file)");
      LOG(fileName);
      LOG_END;

      return SNMPv3_FILECREATE_ERROR;
    }

    LOG_BEGIN(INFO_LOG | 3);
    LOG("saveBootCounter: created new file (file)");
    LOG(fileName);
    LOG_END;

    fputs("# \n",file_in);
    fputs("# This file was created by an SNMP++v3 application,\n", file_in);
    fputs("# it is used to store the snmpEngineBoots counters.\n", file_in);
    fputs("# \n",file_in);
    fputs("# Lines starting with '#' are comments.\n", file_in);
    fputs("# The snmpEngineBoots counters are stored as\n", file_in);
    fputs("# <encoded snmpEngineId> <bootCounter>\n", file_in);
    fputs("# \n", file_in);
    fclose(file_in);
    file_in = fopen(fileName, "r");
  }

  file_out = fopen(tmpFileName, "w");

  if ((file_in) && (file_out))
  {
    encodeString(engineId.data(), len, encoded);
    encoded[len*2] = ' ';
    encoded[len*2 + 1] = 0;

    while (fgets(line, MAX_LINE_LEN, file_in))
    {
      line[MAX_LINE_LEN - 1] = 0;
      if (!strncmp(encoded, line, len*2 + 1))
      {
        if (found)
        {
          LOG_BEGIN(WARNING_LOG | 3);
          LOG("saveBootCounter: Removing doubled entry (file) (line)");
          LOG(fileName);
          LOG(line);
          LOG_END;

          continue;
        }
        sprintf(line,"%s%i\n", encoded, boot);
        fputs(line, file_out);
        found = TRUE;
        continue;
      }
      fputs(line, file_out);
    }
    if (!found)
    {
      sprintf(line, "%s%i\n", encoded, boot);
      fputs(line, file_out);
    }
    fclose(file_in);
    fclose(file_out);
#ifdef WIN32
    _unlink(fileName);
#endif
    if (rename(tmpFileName, fileName))
    {
      LOG_BEGIN(ERROR_LOG | 1);
      LOG("saveBootCounter: Failed to rename temporary file (tmp file) (file)");
      LOG(tmpFileName);
      LOG(fileName);
      LOG_END;

      return SNMPv3_FILERENAME_ERROR;
    }

    LOG_BEGIN(INFO_LOG | 5);
    LOG("saveBootCounter: Saved counter (file) (engine id) (boot)");
    LOG(fileName);
    LOG(engineId.get_printable());
    LOG(boot);
    LOG_END;

    return SNMPv3_OK;
  }

  LOG_BEGIN(ERROR_LOG | 1);
  LOG("saveBootCounter: Failed to open both files (file) (tmp file)");
  LOG(fileName);
  LOG(tmpFileName);
  LOG_END;

  return SNMPv3_FILEOPEN_ERROR;
}
Ejemplo n.º 11
0
// Read the bootCounter of the given engineID stored in the given file.
int getBootCounter(const char *fileName,
                   const OctetStr &engineId, unsigned int &boot)
{
  char line[MAX_LINE_LEN];
  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
  int len = engineId.len();

  FILE *file;

  boot = 0;
  file = fopen(fileName, "r");

  if (!file)
  {
    LOG_BEGIN(ERROR_LOG | 1);
    LOG("getBootCounter: Could not open (file)");
    LOG(fileName);
    LOG_END;

    return SNMPv3_FILEOPEN_ERROR;
  }

  if (len > MAXLENGTH_ENGINEID)
  {
    LOG_BEGIN(ERROR_LOG | 3);
    LOG("getBootCounter: engine id too long, ignoring last bytes (len) (max)");
    LOG(len);
    LOG(MAXLENGTH_ENGINEID);
    LOG_END;

    len = MAXLENGTH_ENGINEID;
  }

  encodeString(engineId.data(), len, encoded);
  encoded[2*len]=' ';
  encoded[2*len + 1] = 0;

  while (fgets(line, MAX_LINE_LEN, file))
  {
    line[MAX_LINE_LEN - 1] = 0;
    /* ignore comments */
    if (line[0]=='#')
      continue;

    if (!strncmp(encoded, line, len*2 + 1))
    {
      /* line starts with engineId */
      char* ptr = line;
      /* skip until first space */
      while (*ptr != 0 && *ptr != ' ')
        ptr++;

      if (*ptr == 0)
      {
        fclose(file);

        LOG_BEGIN(ERROR_LOG | 3);
        LOG("getBootCounter: Illegal line: (file) (line)");
        LOG(fileName);
        LOG(line);
        LOG_END;

        return SNMPv3_FILE_ERROR;
      }
      boot = atoi(ptr);
      fclose(file);

      LOG_BEGIN(DEBUG_LOG | 3);
      LOG("getBootCounter: found entry (file) (engine id) (boot counter)");
      LOG(fileName);
      LOG(engineId.get_printable());
      LOG(boot);
      LOG_END;

      return SNMPv3_OK;
    }
  }
  fclose(file);

  LOG_BEGIN(WARNING_LOG | 3);
  LOG("getBootCounter: No entry found (file) (engine id)");
  LOG(fileName);
  LOG(engineId.get_printable());
  LOG_END;

  return SNMPv3_NO_ENTRY_ERROR;
}
Ejemplo n.º 12
0
//------------[ convert SNMP++ VB to WinSNMP smiVALUE ]----------------
int convertVbToSmival( const Vb &tempvb, SmiVALUE *smival )
{
  smival->syntax = tempvb.get_syntax();
  switch ( smival->syntax ) {

    // case sNMP_SYNTAX_NULL
  case sNMP_SYNTAX_NULL:
  case sNMP_SYNTAX_NOSUCHOBJECT:
  case sNMP_SYNTAX_NOSUCHINSTANCE:
  case sNMP_SYNTAX_ENDOFMIBVIEW:
    break;

    // case sNMP_SYNTAX_INT32:
  case sNMP_SYNTAX_INT:
    tempvb.get_value(smival->value.sNumber);
    break;

    //    case sNMP_SYNTAX_UINT32:
  case sNMP_SYNTAX_GAUGE32:
  case sNMP_SYNTAX_CNTR32:
  case sNMP_SYNTAX_TIMETICKS:
    //  case sNMP_SYNTAX_UINT32:
    tempvb.get_value(smival->value.uNumber);
    break;

    // case Counter64
  case sNMP_SYNTAX_CNTR64:
    {
      Counter64 c64;
      tempvb.get_value(c64);
      smival->value.hNumber.hipart = c64.high();
      smival->value.hNumber.lopart = c64.low();
    }
    break;

  case sNMP_SYNTAX_BITS:
  case sNMP_SYNTAX_OCTETS:
  case sNMP_SYNTAX_OPAQUE:
  case sNMP_SYNTAX_IPADDR:
    {
      OctetStr os;
      tempvb.get_value(os);
      smival->value.string.ptr = NULL;
      smival->value.string.len = os.len();
      if ( smival->value.string.len > 0 )
      {
        smival->value.string.ptr
          = (SmiLPBYTE) new  unsigned char [smival->value.string.len];
        if ( smival->value.string.ptr )
        {
          for (int i=0; i<(int) smival->value.string.len ; i++)
            smival->value.string.ptr[i] = os[i];
        }
        else
        {
          smival->syntax = sNMP_SYNTAX_NULL;  // invalidate the smival
          return SNMP_CLASS_RESOURCE_UNAVAIL;
        }
      }
    }
    break;

  case sNMP_SYNTAX_OID:
    {
      Oid oid;
      tempvb.get_value(oid);
      smival->value.oid.ptr = NULL;
      smival->value.oid.len = oid.len();
      if ( smival->value.oid.len > 0 )
      {
        smival->value.oid.ptr
          = (SmiLPUINT32) new unsigned long [ smival->value.oid.len];
        if ( smival->value.oid.ptr )
        {
          for (int i=0; i<(int)smival->value.oid.len ; i++)
            smival->value.oid.ptr[i] = oid[i];
        }
        else
        {
          smival->syntax = sNMP_SYNTAX_NULL;  // invalidate the smival
          return SNMP_CLASS_RESOURCE_UNAVAIL;
        }
      }
    }
    break;

  default:
    return SNMP_CLASS_INTERNAL_ERROR;
  }
  return SNMP_CLASS_SUCCESS;
}
Ejemplo n.º 13
0
int SnmpMessage::load(const Pdu &cpdu,
                      const OctetStr &community,
                      const snmp_version version,
                      const OctetStr* engine_id,
                      const OctetStr* security_name,
                      const int security_model)
{
  int status;
  const Pdu *pdu = &cpdu;
  Pdu temppdu;

  // make sure pdu is valid
  if ( !pdu->valid())
    return SNMP_CLASS_INVALID_PDU;

  // create a raw pdu
  snmp_pdu *raw_pdu;
  raw_pdu = snmp_pdu_create( (int) pdu->get_type());

  Oid enterprise;

  // load it up
  raw_pdu->reqid = pdu->get_request_id();
#ifdef _SNMPv3
  raw_pdu->msgid = pdu->get_message_id();
#endif
  raw_pdu->errstat= (unsigned long) pdu->get_error_status();
  raw_pdu->errindex= (unsigned long) pdu->get_error_index();

  // if its a V1 trap then load up other values
  // for v2, use normal pdu format
  if (raw_pdu->command == sNMP_PDU_V1TRAP)
  {
    // DON'T forget about the v1 trap agent address (changed by Frank Fock)
    GenAddress gen_addr;
    IpAddress ip_addr;
    int addr_set = FALSE;

    if (pdu->get_v1_trap_address(gen_addr))
    {
      /* User did set the v1 trap address */
      if ((gen_addr.get_type() != Address::type_ip) &&
          (gen_addr.get_type() != Address::type_udp) )
      {
	LOG_BEGIN(ERROR_LOG | 4);
	LOG("SNMPMessage: Bad v1 trap address type in pdu");
	LOG(gen_addr.get_type());
	LOG_END;

        snmp_free_pdu( raw_pdu);
        return SNMP_CLASS_INVALID_PDU;
      }

      ip_addr = gen_addr;
      if (!ip_addr.valid())
      {
	LOG_BEGIN(ERROR_LOG | 1);
	LOG("SNMPMessage: Copied v1 trap address not valid");
	LOG_END;

        snmp_free_pdu( raw_pdu);
        return SNMP_CLASS_RESOURCE_UNAVAIL;
      }
      addr_set = TRUE;
    }
    else
    {
      /* User did not set the v1 trap address */
      char addrString[256];
      if (gethostname(addrString, 255) == 0)
      {
          ip_addr = addrString;
          addr_set = TRUE;
      }
    }
    struct sockaddr_in agent_addr;  // agent address socket struct
    // prepare the agent address
    memset(&agent_addr, 0, sizeof(agent_addr));
    agent_addr.sin_family = AF_INET;
    if (addr_set)
    {
      agent_addr.sin_addr.s_addr
        = inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
      LOG_BEGIN(INFO_LOG | 7);
      LOG("SNMPMessage: Setting v1 trap address");
      LOG(((IpAddress &)ip_addr).IpAddress::get_printable());
      LOG_END;
    }
    raw_pdu->agent_addr = agent_addr;

    //-----[ compute generic trap value ]-------------------------------
    // determine the generic value
    // 0 - cold start
    // 1 - warm start
    // 2 - link down
    // 3 - link up
    // 4 - authentication failure
    // 5 - egpneighborloss
    // 6 - enterprise specific
    Oid trapid;
    pdu->get_notify_id( trapid);
    if ( !trapid.valid() || trapid.len() < 2 )
      {
        snmp_free_pdu( raw_pdu);
        return SNMP_CLASS_INVALID_NOTIFYID;
      }
    raw_pdu->specific_type=0;
    if ( trapid == coldStart)
      raw_pdu->trap_type = 0;  // cold start
    else if ( trapid == warmStart)
      raw_pdu->trap_type = 1;  // warm start
    else if( trapid == linkDown)
      raw_pdu->trap_type = 2;  // link down
    else if ( trapid == linkUp)
      raw_pdu->trap_type = 3;  // link up
    else if ( trapid == authenticationFailure )
      raw_pdu->trap_type = 4;  // authentication failure
    else if ( trapid == egpNeighborLoss)
      raw_pdu->trap_type = 5;  // egp neighbor loss
    else {
      raw_pdu->trap_type = 6;     // enterprise specific
      // last oid subid is the specific value
      // if 2nd to last subid is "0", remove it
      // enterprise is always the notify oid prefix
      raw_pdu->specific_type = (int) trapid[(int) (trapid.len()-1)];

      trapid.trim(1);
      if ( trapid[(int)(trapid.len()-1)] == 0 )
        trapid.trim(1);
      enterprise = trapid;
    }

    if ( raw_pdu->trap_type !=6)
      pdu->get_notify_enterprise( enterprise);
    if ( enterprise.len() >0) {
      // note!!
      // these are hooks into an SNMP++ oid
      // and therefor the raw_pdu enterprise
      // should not free them. null them out!!
      SmiLPOID rawOid;
      rawOid = enterprise.oidval();
      raw_pdu->enterprise = rawOid->ptr;
      raw_pdu->enterprise_length = (int) rawOid->len;
    }

    // timestamp
    TimeTicks timestamp;
    pdu->get_notify_timestamp( timestamp);
    raw_pdu->time = ( unsigned long) timestamp;

  }

  // if its a v2 trap then we need to make a few adjustments
  // vb #1 is the timestamp
  // vb #2 is the id, represented as an Oid
  if (( raw_pdu->command == sNMP_PDU_TRAP) ||
      ( raw_pdu->command == sNMP_PDU_INFORM))
  {
    Vb tempvb;

    temppdu = *pdu;
    temppdu.trim(temppdu.get_vb_count());

    // vb #1 is the timestamp
    TimeTicks timestamp;
    tempvb.set_oid(SNMP_MSG_OID_SYSUPTIME);   // sysuptime
    pdu->get_notify_timestamp( timestamp);
    tempvb.set_value ( timestamp);
    temppdu += tempvb;

    // vb #2 is the id
    Oid trapid;
    tempvb.set_oid(SNMP_MSG_OID_TRAPID);
    pdu->get_notify_id( trapid);
    tempvb.set_value( trapid);
    temppdu += tempvb;

    // append the remaining vbs
    for (int z=0; z<pdu->get_vb_count(); z++) {
      pdu->get_vb( tempvb,z);
      temppdu += tempvb;
    }

    pdu = &temppdu;          // reassign the pdu to the temp one
  }
  // load up the payload
  // for all Vbs in list, add them to the pdu
  int vb_count;
  Vb tempvb;
  Oid tempoid;
  SmiLPOID smioid;
  SmiVALUE smival;

  vb_count = pdu->get_vb_count();
  for (int z=0;z<vb_count;z++) {
    pdu->get_vb( tempvb,z);
    tempvb.get_oid( tempoid);
    smioid = tempoid.oidval();
    // clear the value portion, in case its
    // not already been done so by the app writer
    // only do it in the case its a get,next or bulk
    if ((raw_pdu->command == sNMP_PDU_GET) ||
        (raw_pdu->command == sNMP_PDU_GETNEXT) ||
        (raw_pdu->command == sNMP_PDU_GETBULK))
      tempvb.set_null();
    status = convertVbToSmival( tempvb, &smival );
    if ( status != SNMP_CLASS_SUCCESS) {
      snmp_free_pdu( raw_pdu);
      return status;
    }
    // add the vb to the raw pdu
    snmp_add_var( raw_pdu, smioid->ptr, (int) smioid->len, &smival);

    freeSmivalDescriptor( &smival);
  }

  // ASN1 encode the pdu
#ifdef _SNMPv3
  if (version == version3)
  {
    if ((!engine_id) || (!security_name))
    {
      LOG_BEGIN(ERROR_LOG | 4);
      LOG("SNMPMessage: Need security name and engine id for v3 message");
      LOG_END;

      // prevention of SNMP++ Enterprise Oid death
      if ( enterprise.len() >0) {
	raw_pdu->enterprise = 0;
	raw_pdu->enterprise_length=0;
      }
      snmp_free_pdu( raw_pdu);
      return SNMP_CLASS_INVALID_TARGET;
    }

    status = v3MP::I->snmp_build(raw_pdu, databuff, (int *)&bufflen,
				 *engine_id, *security_name, security_model,
				 pdu->get_security_level(),
				 pdu->get_context_engine_id(),
				 pdu->get_context_name());
    if (status == SNMPv3_MP_OK) {
      if ((pdu->get_type() == sNMP_PDU_RESPONSE) &&
          ((int)pdu->get_maxsize_scopedpdu() < pdu->get_asn1_length())) {

	LOG_BEGIN(ERROR_LOG | 1);
	LOG("SNMPMessage: *BUG*: Serialized response pdu is too big (len) (max)");
	LOG(pdu->get_asn1_length());
	LOG(pdu->get_maxsize_scopedpdu());
	LOG_END;

        // prevention of SNMP++ Enterprise Oid death
        if ( enterprise.len() >0) {
          raw_pdu->enterprise = 0;
          raw_pdu->enterprise_length=0;
        }
        snmp_free_pdu( raw_pdu);
        return SNMP_ERROR_TOO_BIG;
      }
    }
  }
  else
#endif
    status = snmp_build( raw_pdu, databuff, (int *) &bufflen, version,
                         community.data(), (int) community.len());

  LOG_BEGIN(DEBUG_LOG | 4);
  LOG("SNMPMessage: return value for build message");
  LOG(status);
  LOG_END;

  if ((status != 0)
#ifdef _SNMPv3
      && ((version != version3) || (status != SNMPv3_MP_OK))
#endif
      ) {
    valid_flag = false;
    // prevention of SNMP++ Enterprise Oid death
    if ( enterprise.len() >0) {
      raw_pdu->enterprise = 0;
      raw_pdu->enterprise_length=0;
    }
    snmp_free_pdu( raw_pdu);
#ifdef _SNMPv3
    if (version == version3)
      return status;
    else
#endif
      // NOTE: This is an assumption - in most cases during normal
      // operation the reason is a tooBig - another could be a
      // damaged variable binding.
      return SNMP_ERROR_TOO_BIG;
  }
  valid_flag = true;

  // prevention of SNMP++ Enterprise Oid death
  if ( enterprise.len() >0) {
    raw_pdu->enterprise = 0;
    raw_pdu->enterprise_length=0;
  }

  snmp_free_pdu( raw_pdu);

  return SNMP_CLASS_SUCCESS;
}