Beispiel #1
0
int snmp_preview(u_char *data, unsigned length, struct SnmpObjects *vbinds)
{
   int i = 0;       /* number of varbinds parsed */
   unsigned tmp;
   struct SnmpObject *obj; 
   vbinds->num=0;  /* number of varbinds present in vbinds */
   while (length)
   {
      /* parse the name, value pair */
      obj = &(vbinds->objs[i]);
      obj->namelen = MAX_NAME_LEN;
      data = snmp_parse_var_op(data, obj->name, &obj->namelen, 
         &obj->valuetype, &obj->valuelen, &obj->value, &length);
      if (data == NULL)
         return -1;
      /* obj->value points to ASN encoded value
       * - skip past "type" and "len" fields, so that "value"
       * points to received value.
       */
      tmp = data - obj->value;
      obj->value = asn_parse_header(obj->value, &tmp, &obj->valuetype);
      if (obj->value == NULL)
         return -1;
      i++;
      /* test which verifies that SET command contains valid VB ammount */
      if((i >= SNMP_MAX_OIDS) && (length > 0))  
         return -1 ;
   }
   vbinds->num=i;  /* number of varbinds present in vbinds */
   return 0;
}
//*
//*---------------------------------------------------------------------------------
//* Function Name: snmp_parse_auth
//* Description  : Get the community name and version number by parsing snmp
//*        message. The message is decoded in BER deconding rules.
//* Return Value : Community Name and its length, version number and new pointer to
//*        next snmp fields
//* Calling To   : asn_parse_header, asn_parse_int, asn_parse_string
//* Called By    : snmp_parse
//*---------------------------------------------------------------------------------
//*
uint8           *snmp_parse_auth(
        uint8   *data,
        int     *length,
        uint8   *community,
        int         *community_len,
        long    *version
)
{
        uint8           type;

        data = asn_parse_header(data, length, &type);
        if (data == NULL) {
                return (NULL);   //------SNMP: Parse authority failure.
    }
        if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
                return (NULL);  //------SNMP: Wrong auth header type.

        data = asn_parse_int(data, length, &type, version, sizeof(*version));
        if (data == NULL)
                return (NULL);  //------SNMP: Bad parse of version.

        data = asn_parse_string(data, length, &type, community, community_len);
        if (data == NULL)
                return (NULL);  //------SNMP: Bad parse of community.

        community[*community_len] = '\0';
        return (data);
}
//*
//* create a packet identical to the input packet, except for the error status
//* and the error index which are set according to the input variables.
//* Returns 1 upon success and 0 upon failure.
//*
int
create_identical(
        snmp_session *session,
    uint8 *snmp_in,
    uint8 *snmp_out,
    int   snmp_length,
    long  errstat,
    long  errindex
)
{
        uint8  *data;
        uint8  type;
        uint32 dummy;
        uint8  *headerPtr, *reqidPtr, *errstatPtr, *errindexPtr, *varListPtr;
        int        headerLength, length;

        bcopy((char *)snmp_in, (char *)snmp_out, snmp_length);
        length = snmp_length;
        headerPtr = snmp_parse_auth(snmp_out, &length, community, &session->community_len, (long *)&dummy);
        community[session->community_len] = 0;
        if (headerPtr == NULL) return 0;

    reqidPtr = asn_parse_header(headerPtr, &length, (uint8 *)&dummy);
    if (reqidPtr == NULL)
        return 0;
    headerLength = length;
    errstatPtr = asn_parse_int(reqidPtr, &length, &type, (long *)&dummy, sizeof dummy); // request id
    if (errstatPtr == NULL)
        return 0;
    errindexPtr = asn_parse_int(errstatPtr, &length, &type, (long *)&dummy, sizeof dummy);      // error status
    if (errindexPtr == NULL)
        return 0;
    varListPtr = asn_parse_int(errindexPtr, &length, &type, (long *)&dummy, sizeof dummy);      // error index
    if (varListPtr == NULL)
        return 0;

#if 0
    data = asn_build_header(headerPtr, &headerLength, GET_RSP_MSG, headerLength);
    if (data != reqidPtr)
        return 0;
#else
         /*bug fixed */
    *headerPtr = GET_RSP_MSG;
#endif

    length = snmp_length;
    type = (uint8)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
    data = asn_build_int(errstatPtr, &length, type, &errstat, sizeof errstat);
    if (data != errindexPtr)
        return 0;
    data = asn_build_int(errindexPtr, &length, type, &errindex, sizeof errindex);
    if (data != varListPtr)
        return 0;
    packet_end = snmp_out + snmp_length;
    return 1;
}
Beispiel #4
0
u_char *
snmp_msg_Decode(u_char * Packet, int *PacketLenP,
                u_char * Community, int *CommLenP,
                int *Version, struct snmp_pdu * PDU)
{
    u_char *bufp;
    u_char type;

    bufp = asn_parse_header(Packet, PacketLenP, &type);
    if (bufp == NULL) {
        snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
        ASN_PARSE_ERROR(NULL);
    }
    if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
        snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
        ASN_PARSE_ERROR(NULL);
    }
    bufp = asn_parse_int(bufp, PacketLenP,
                         &type,
                         (int *) Version, sizeof(*Version));
    if (bufp == NULL) {
        snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Version)!\n");
        ASN_PARSE_ERROR(NULL);
    }
    bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
    if (bufp == NULL) {
        snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Community)!\n");
        ASN_PARSE_ERROR(NULL);
    }
    Community[*CommLenP] = '\0';

    if ((*Version != SNMP_VERSION_1) &&
            (*Version != SNMP_VERSION_2)) {

        /* Don't know how to handle this one. */
        snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
        snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
    }
    /* Now that we know the header, decode the PDU */

    /* XXXXX -- More than one PDU? */
    bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
    if (bufp == NULL)
        /* snmp_pdu_decode registered failure */
        return (NULL);

    bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
    if (bufp == NULL)
        /* snmp_var_DecodeVarBind registered failure */
        return (NULL);

    return (u_char *) bufp;
}
Beispiel #5
0
// Tests if the given buffer contains a SNMPv3-Message.
bool v3MP::is_v3_msg(unsigned char *buffer, int length)
{
  unsigned char type;
  long version;

  // get the type
  buffer = asn_parse_header(buffer, &length, &type);
  if (!buffer)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("Testing for v3 message: Bad header");
    LOG_END;

    return false;
  }

  if (type != ASN_SEQ_CON)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("Testing for v3 message: Wrong auth header type");
    LOG((int)type);
    LOG_END;

    return false;
  }

  // get the version
  buffer = asn_parse_int(buffer, &length, &type, &version);
  if (!buffer)
  {
    LOG_BEGIN(loggerModuleName, WARNING_LOG | 1);
    LOG("Testing for v3 message: Bad parse of version");
    LOG_END;

    return 0;
  }

  return (version == SNMP_VERSION_3);
}
u_char *
snmp_parse_var_op(u_char *data,
                  oid *var_name,
                  size_t *var_name_len,
                  u_char *var_val_type,
                  size_t *var_val_len,
                  u_char **var_val,
                  size_t *listlength)
{
    u_char	    var_op_type;
    size_t		    var_op_len = *listlength;
    u_char	    *var_op_start = data;

    data = asn_parse_sequence(data, &var_op_len, &var_op_type,
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR), "var_op");
    if (data == NULL) {
        /* msg detail is set */
        return NULL;
    }
    data = asn_parse_objid(data, &var_op_len, &var_op_type, var_name, var_name_len);
    if (data == NULL) {
        ERROR_MSG("No OID for variable");
        return NULL;
    }
    if (var_op_type != (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID))
        return NULL;
    *var_val = data;	/* save pointer to this object */
    /* find out what type of object this is */
    data = asn_parse_header(data, &var_op_len, var_val_type);
    if (data == NULL) {
        ERROR_MSG("No header for value");
        return NULL;
    }
    /* XXX no check for type! */
    *var_val_len = var_op_len;
    data += var_op_len;
    *listlength -= (int)(data - var_op_start);
    return data;
}
Beispiel #7
0
/* Parse SMUX message. */
int
smux_parse (char *ptr, size_t len)
{
  /* This buffer we'll use for SOUT message. We could allocate it with
     malloc and save only static pointer/lenght, but IMHO static
     buffer is a faster solusion. */
  static u_char sout_save_buff[SMUXMAXPKTSIZE];
  static int sout_save_len = 0;

  int len_income = len; /* see note below: YYY */
  u_char type;
  u_char rollback;

  rollback = ptr[2]; /* important only for SMUX_SOUT */

process_rest: /* see note below: YYY */

  /* Parse SMUX message type and subsequent length. */
  ptr = asn_parse_header (ptr, &len, &type);

  if (debug_smux)
    zlog_debug ("SMUX message received type: %d rest len: %ld", type, len);

  switch (type)
    {
    case SMUX_OPEN:
      /* Open must be not send from SNMP agent. */
      zlog_warn ("SMUX_OPEN received: resetting connection.");
      return -1;
      break;
    case SMUX_RREQ:
      /* SMUX_RREQ message is invalid for us. */
      zlog_warn ("SMUX_RREQ received: resetting connection.");
      return -1;
      break;
    case SMUX_SOUT:
      /* SMUX_SOUT message is now valied for us. */
      if (debug_smux)
        zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");

      if (sout_save_len > 0)
        {
          smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
          sout_save_len = 0;
        }
      else
        zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);

      if (len_income > 3) 
        {
          /* YYY: this strange code has to solve the "slow peer"
             problem: When agent sends SMUX_SOUT message it doesn't
             wait any responce and may send some next message to
             subagent. Then the peer in 'smux_read()' will recieve
             from socket the 'concatenated' buffer, contaning both
             SMUX_SOUT message and the next one
             (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
             the buffer is longer than 3 ( length of SMUX_SOUT ), we
             must process the rest of it.  This effect may be observed
             if 'debug_smux' is set to '1' */
          ptr++;
          len = len_income - 3;
          goto process_rest;
        }
      break;
    case SMUX_GETRSP:
      /* SMUX_GETRSP message is invalid for us. */
      zlog_warn ("SMUX_GETRSP received: resetting connection.");
      return -1;
      break;
    case SMUX_CLOSE:
      /* Close SMUX connection. */
      if (debug_smux)
	zlog_debug ("SMUX_CLOSE");
      smux_parse_close (ptr, len);
      return -1;
      break;
    case SMUX_RRSP:
      /* This is response for register message. */
      if (debug_smux)
	zlog_debug ("SMUX_RRSP");
      smux_parse_rrsp (ptr, len);
      break;
    case SMUX_GET:
      /* Exact request for object id. */
      if (debug_smux)
	zlog_debug ("SMUX_GET");
      smux_parse_get (ptr, len, 1);
      break;
    case SMUX_GETNEXT:
      /* Next request for object id. */
      if (debug_smux)
	zlog_debug ("SMUX_GETNEXT");
      smux_parse_get (ptr, len, 0);
      break;
    case SMUX_SET:
      /* SMUX_SET is supported with some limitations. */
      if (debug_smux)
	zlog_debug ("SMUX_SET");

      /* save the data for future SMUX_SOUT */
      memcpy (sout_save_buff, ptr, len);
      sout_save_len = len;
      smux_parse_set (ptr, len, RESERVE1);
      break;
    default:
      zlog_info ("Unknown type: %d", type);
      break;
    }
  return 0;
}
Beispiel #8
0
char *
smux_var (char *ptr, size_t len, oid objid[], size_t *objid_len,
          size_t *var_val_len,
          u_char *var_val_type,
          void **var_value)
{
  u_char type;
  u_char val_type;
  size_t val_len;
  u_char *val;

  if (debug_smux)
    zlog_debug ("SMUX var parse: len %ld", len);

  /* Parse header. */
  ptr = asn_parse_header (ptr, &len, &type);
  
  if (debug_smux)
    {
      zlog_debug ("SMUX var parse: type %d len %ld", type, len);
      zlog_debug ("SMUX var parse: type must be %d", 
		 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
    }

  /* Parse var option. */
  *objid_len = MAX_OID_LEN;
  ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, 
			  &val_len, &val, &len);

  if (var_val_len)
    *var_val_len = val_len;

  if (var_value)
    *var_value = (void*) val;

  if (var_val_type)
    *var_val_type = val_type;

  /* Requested object id length is objid_len. */
  if (debug_smux)
    smux_oid_dump ("Request OID", objid, *objid_len);

  if (debug_smux)
    zlog_debug ("SMUX val_type: %d", val_type);

  /* Check request value type. */
  if (debug_smux)
  switch (val_type)
    {
    case ASN_NULL:
      /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
         ASN_NULL. */
      zlog_debug ("ASN_NULL");
      break;

    case ASN_INTEGER:
      zlog_debug ("ASN_INTEGER");
      break;
    case ASN_COUNTER:
    case ASN_GAUGE:
    case ASN_TIMETICKS:
    case ASN_UINTEGER:
      zlog_debug ("ASN_COUNTER");
      break;
    case ASN_COUNTER64:
      zlog_debug ("ASN_COUNTER64");
      break;
    case ASN_IPADDRESS:
      zlog_debug ("ASN_IPADDRESS");
      break;
    case ASN_OCTET_STR:
      zlog_debug ("ASN_OCTET_STR");
      break;
    case ASN_OPAQUE:
    case ASN_NSAP:
    case ASN_OBJECT_ID:
      zlog_debug ("ASN_OPAQUE");
      break;
    case SNMP_NOSUCHOBJECT:
      zlog_debug ("SNMP_NOSUCHOBJECT");
      break;
    case SNMP_NOSUCHINSTANCE:
      zlog_debug ("SNMP_NOSUCHINSTANCE");
      break;
    case SNMP_ENDOFMIBVIEW:
      zlog_debug ("SNMP_ENDOFMIBVIEW");
      break;
    case ASN_BIT_STR:
      zlog_debug ("ASN_BIT_STR");
      break;
    default:
      zlog_debug ("Unknown type");
      break;
    }
  return ptr;
}
Beispiel #9
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;
}
Beispiel #10
0
/* Parse all Vars from the buffer */
u_char *snmp_var_DecodeVarBind(u_char *Buffer, int *BufLen,
			       struct variable_list **VarP,
			       int Version)
{
  struct variable_list *Var, **VarLastP;
  u_char *bufp, *tmp;
  u_char  VarBindType;
  u_char *DataPtr;
  int     DataLen;
  oid TmpBuf[MAX_NAME_LEN];

  int AllVarLen = *BufLen;
  int ThisVarLen = 0;

  VarLastP = VarP;
#ifdef DEBUG_VARS_DECODE
  printf("VARS: Decoding buffer of length %d\n", *BufLen);
#endif

  /* Now parse the variables */
  bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
  if (bufp == NULL)
    ASN_PARSE_ERROR(NULL);

  if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
      snmp_set_api_error(SNMPERR_PDU_PARSE);
      ASN_PARSE_ERROR(NULL);
  }

#ifdef DEBUG_VARS_DECODE
  printf("VARS: All Variable length %d\n", AllVarLen);
#endif

  /* We know how long the variable list is.  Parse it. */
  while ((int)AllVarLen > 0) {

    /* Create a new variable */
    Var = snmp_var_new(NULL, MAX_NAME_LEN);
    if (Var == NULL)
      return(NULL);
    
    /* Parse the header to find out the length of this variable. */
    ThisVarLen = AllVarLen;
    tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType);
    if (tmp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* Now that we know the length , figure out how it relates to 
     * the entire variable list
     */
    AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp));
    bufp = tmp;

    /* Is it valid? */
    if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
      snmp_set_api_error(SNMPERR_PDU_PARSE);
      ASN_PARSE_ERROR(NULL);
    }

#ifdef DEBUG_VARS_DECODE
    printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen);
#endif

    /* Parse the OBJID */
    bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType, 
			   Var->name, &(Var->name_length));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    if (VarBindType != (u_char)(ASN_UNIVERSAL | 
				ASN_PRIMITIVE | 
				ASN_OBJECT_ID)) {
      snmp_set_api_error(SNMPERR_PDU_PARSE);
      ASN_PARSE_ERROR(NULL);
    }

#ifdef DEBUG_VARS_DECODE
    printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n", 
	   Var->name_length, ThisVarLen);
#endif

    /* Keep a pointer to this object */
    DataPtr = bufp;
    DataLen = ThisVarLen;

    /* find out type of object */
    bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);
    ThisVarLen = DataLen;

#ifdef DEBUG_VARS_DECODE
    printf("VARS: Data type %d\n", Var->type);
#endif

    /* Parse the type */
    
    switch((short)Var->type){

    case ASN_INTEGER:
      Var->val.integer = (int *)malloc(sizeof(int));
      if (Var->val.integer == NULL) {
	snmp_set_api_error(SNMPERR_OS_ERR);
	return(NULL);
      }
      Var->val_len = sizeof(int);
      bufp = asn_parse_int(DataPtr, &ThisVarLen, 
			   &Var->type, (int *)Var->val.integer, 
			   Var->val_len);
#ifdef DEBUG_VARS_DECODE
      printf("VARS: Decoded integer '%d' (%d bytes left)\n",
	     *(Var->val.integer), ThisVarLen);
#endif
      break;

    case SMI_COUNTER32:
    case SMI_GAUGE32:
      /*  case SMI_UNSIGNED32: */
    case SMI_TIMETICKS:
      Var->val.integer = (int *)malloc(sizeof(u_int));
      if (Var->val.integer == NULL) {
	snmp_set_api_error(SNMPERR_OS_ERR);
	return(NULL);
      }
      Var->val_len = sizeof(u_int);
      bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen, 
				    &Var->type, (u_int *)Var->val.integer, 
				    Var->val_len);
#ifdef DEBUG_VARS_DECODE
      printf("VARS: Decoded timeticks '%d' (%d bytes left)\n",
	     *(Var->val.integer), ThisVarLen);
#endif
      break;

    case ASN_OCTET_STR:
    case SMI_IPADDRESS:
    case SMI_OPAQUE:
      Var->val_len = *&ThisVarLen; /* String is this at most */
      Var->val.string = (u_char *)malloc((unsigned)Var->val_len);
      if (Var->val.string == NULL) {
	snmp_set_api_error(SNMPERR_OS_ERR);
	return(NULL);
      }
      bufp = asn_parse_string(DataPtr, &ThisVarLen, 
			      &Var->type, Var->val.string, 
			      &Var->val_len);
#ifdef DEBUG_VARS_DECODE
      printf("VARS: Decoded string '%s' (length %d) (%d bytes left)\n",
	     (Var->val.string), Var->val_len, ThisVarLen);
#endif
      break;
         
    case ASN_OBJECT_ID:
      Var->val_len = MAX_NAME_LEN;
      bufp = asn_parse_objid(DataPtr, &ThisVarLen, 
			     &Var->type, TmpBuf, &Var->val_len);
      Var->val_len *= sizeof(oid);
      Var->val.objid = (oid *)malloc((unsigned)Var->val_len);
      if (Var->val.integer == NULL) {
	snmp_set_api_error(SNMPERR_OS_ERR);
	return(NULL);
      }
      /* Only copy if we successfully decoded something */
      if (bufp) {
	memcpy((char *)Var->val.objid, (char *)TmpBuf, Var->val_len);
      }
#ifdef DEBUG_VARS_DECODE
      printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n",
	      Var->val_len, ThisVarLen);
#endif
      break;

    case ASN_NULL:
    case SMI_NOSUCHINSTANCE:
    case SMI_NOSUCHOBJECT:
    case SMI_ENDOFMIBVIEW:
      Var->val_len   = 0;
      Var->val.objid = NULL;
      bufp = asn_parse_null(DataPtr, &ThisVarLen, &Var->type);
#ifdef DEBUG_VARS_DECODE
      printf("VARS: Decoded ASN_NULL (length %d) (%d bytes left)\n",
	     Var->val_len, ThisVarLen);
#endif
      break;

    case SMI_COUNTER64:
#ifdef STDERR_OUTPUT
      fprintf(stderr, WIDE("Unable to parse type SMI_COUNTER64!\n"));
#endif
      snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
      return(NULL);
      break;

    default:
#ifdef STDERR_OUTPUT
      fprintf(stderr, WIDE("bad type returned (%x)\n"), Var->type);
#endif
      snmp_set_api_error(SNMPERR_PDU_PARSE);
      return(NULL);
      break;
    } /* End of var type switch */

    /* Why is this here? XXXXX */
    if (bufp == NULL)
      return(NULL);

#ifdef DEBUG_VARS_DECODE
    printf("VARS: Adding to list of decoded variables.  (%d bytes remain.)\n", AllVarLen);
#endif
    /* Add variable to the list */
    *VarLastP = Var;
    VarLastP = &(Var->next_variable);
  }

  return(bufp);
}
//*
//* Parse_var_op_list goes through the list of variables and retrieves each one,
//* placing it's value in the output packet.  In the case of a set request,
//* if action is RESERVE, the value is just checked for correct type and
//* value, and resources may need to be reserved.  If the action is COMMIT,
//* the variable is set.  If the action is FREE, an error was discovered
//* somewhere in the previous RESERVE pass, so any reserved resources
//* should be FREE'd.
//* If any error occurs, an error code is returned.
//*
int
parse_var_op_list(
        snmp_session *session,
        uint8 *data,      //point to variable-binding of in-packet data
        int    length,     //in packet data length
        uint8 *out_data,  //point to variable-binding of out-packet data
        int    out_length, //out packet buffer length
        long   *index,     //error-index (output)
        int    msgtype,    //message type
        int    action      //???
)
{
        uint8  type;
        oid         var_name[SNMP_MAX_NAME_LEN];
        int         var_name_len, var_val_len;
        uint8  var_val_type, *var_val, statType;
        uint8 *statP;
        int         statLen;
        uint16  acl;
        int         (*write_method)();
        uint8  *headerP, *var_list_start;
        int         dummyLen;
#ifdef WEBADMIN
        int         dummyLen1;      // add -- By arius 5/17/2000
        uint8       *newpacket_end; // add -- By arius 5/17/2000
#endif WEBADMIN
        int         noSuchObject;
        int     (*WriteMethod)(int,uint8 *,uint8,int,uint8 *,oid *,int);
        int         err, exact;

//      if (msgtype== SET_REQ_MSG)      rw = SNMP_WRITE;
//  else rw = SNMP_READ;

        if (msgtype == GETNEXT_REQ_MSG) exact = FALSE;
        else exact = TRUE;

        //Parse variable-binging header
        data = asn_parse_header(data, &length, &type);

        if (data == NULL){
                ERROR("not enough space for varlist");
                return PARSE_ERROR;
        }
        if (type != (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR)){
                ERROR("wrong type");
                return PARSE_ERROR;
    }

        headerP = out_data;
        //Set Resp variable-binging header
    out_data = asn_build_sequence(out_data, &out_length,
                                (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);

        if (out_data == NULL){
                ERROR("not enough space in output packet");
                return BUILD_ERROR;
        }

    var_list_start = out_data;

        *index = 1;
        while((int)length > 0){
                // parse the name, value pair
                var_name_len = SNMP_MAX_NAME_LEN;

                data = snmp_parse_var_op(data, var_name, &var_name_len, &var_val_type,
                                         &var_val_len, &var_val, (int *)&length);

                if (data == NULL)  return PARSE_ERROR;

                // now attempt to retrieve the variable on the local entity
                statP = getStatPtr(var_name, &var_name_len, &statType,
                           &statLen, &acl, exact,
                           &write_method, SNMP_VERSION_1, &noSuchObject,
                           (msgtype==SET_REQ_MSG?
                             (session->access & SNMP_ACCESS_WRITE):
                             (session->access & SNMP_ACCESS_READ)    )
                        );

                if (/* session->version == SNMP_VERSION_1 &&*/
                                    statP == NULL &&
                                    (msgtype != SET_REQ_MSG || !write_method))
                {
                        //** XXX: happens when running
                        //   XXX: snmpwalk localhost public .1
                        //   XXX: fix me some day.
                        //**
                        //** ERROR("warning: internal v1_error"); **
                        return SNMP_ERR_NOSUCHNAME;
                }

                // check if this variable is read-write (in the MIB sense).
                if( msgtype == SET_REQ_MSG && acl != RWRITE )
                        return SNMP_ERR_READONLY;
//          return session->version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOTWRITABLE;

                //* Its bogus to check here on getnexts - the whole packet shouldn't
                //   be dumped - this should should be the loop in getStatPtr
                //   luckily no objects are set unreadable.  This can still be
                //  useful for sets to determine which are intrinsically writable

                if (msgtype== SET_REQ_MSG){
                        if (write_method == NULL){
                                if (statP != NULL){
                                        // see if the type and value is consistent with this entity's variable
                                        if (!goodValue(var_val_type, var_val_len, statType,statLen))
                                        {
//                                              if (session->version != SNMP_VERSION_1)
//                                                      return SNMP_ERR_WRONGTYPE; // poor approximation
//                                              else
                                                {
                                                        snmp_inbadvalues++;
                                                        return SNMP_ERR_BADVALUE;
                                                }
                                    }
                                    // actually do the set if necessary
                                        if (action == COMMIT)
                                                setVariable(var_val, var_val_type, var_val_len,statP, statLen);
                                } else {
//                                  if (session->version != SNMP_VERSION_1)
//                                              return SNMP_ERR_NOCREATION;
//                                  else
                                                return SNMP_ERR_NOSUCHNAME;
                                }
                        } else {
                                WriteMethod = (int (*)(int,uint8 *,uint8,int,uint8 *,oid *,int)) write_method;

                                err = (*WriteMethod)(action, var_val, var_val_type,
                                          var_val_len, statP, var_name,
                                          var_name_len);

                                //*
                                //* Map the SNMPv2 error codes to SNMPv1 error codes (RFC 2089).
                                //*

//                              if (session->version == SNMP_VERSION_1) {
                                    switch (err) {
                                        case SNMP_ERR_NOERROR:
                                                        // keep the no-error error:
                                                        break;
                                            case SNMP_ERR_WRONGVALUE:
                                            case SNMP_ERR_WRONGENCODING:
                                            case SNMP_ERR_WRONGTYPE:
                                            case SNMP_ERR_WRONGLENGTH:
                                            case SNMP_ERR_INCONSISTENTVALUE:
                                                        err = SNMP_ERR_BADVALUE;
                                                        break;
                                            case SNMP_ERR_NOACCESS:
                                            case SNMP_ERR_NOTWRITABLE:
                                            case SNMP_ERR_NOCREATION:
                                            case SNMP_ERR_INCONSISTENTNAME:
                                            case SNMP_ERR_AUTHORIZATIONERROR:
                                                        err = SNMP_ERR_NOSUCHNAME;
                                                        break;
                                            default:
                                                        err = SNMP_ERR_GENERR;
                                                        break;
//                                      }
                                }//if(session->version == SNMP_VERSION_1) ....

                                if (err != SNMP_ERR_NOERROR){
//                                      if (session->version == SNMP_VERSION_1) {
                                                snmp_inbadvalues++;
//                                      }
                                        return err;
                                }
                        }
                } else {
                        //* retrieve the value of the variable and place it into the
                        //* outgoing packet
                        if (statP == NULL){
                                statLen = 0;
                                if (exact){
                                        if (noSuchObject == TRUE){
                                                statType = SNMP_NOSUCHOBJECT;
                                        } else {
                                                statType = SNMP_NOSUCHINSTANCE;
                                        }
                                } else {
                                        statType = SNMP_ENDOFMIBVIEW;
                                }
                        } //if (statP == NULL) ...

                        out_data = snmp_build_var_op(out_data, var_name, &var_name_len,
                                                     statType, statLen, statP,
                                                     &out_length);
                        if (out_data == NULL){
                                return SNMP_ERR_TOOBIG;
                        }
                } //if (msgtype== SET_REQ_MSG) ...

                (*index)++;
        } //while((int)length > 0) ....
        if(msgtype!= SET_REQ_MSG){
                // save a pointer to the end of the packet
                packet_end = out_data;

                // Now rebuild header with the actual lengths
                dummyLen = packet_end - var_list_start;

// modified by ---- Arius 5/17/2000
#ifdef WEBADMIN
  dummyLen1 = packet_end - headerP;
  newpacket_end = asn_build_sequence(headerP, &dummyLen1,
                    (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen);
  var_list_start -= (packet_end - newpacket_end);
  out_length += (packet_end - newpacket_end);
  // save new pointer to the end of the packet when the sapces will be adjust
  packet_end = newpacket_end;
  if (headerP == NULL)
#else
                if (asn_build_sequence(headerP, &dummyLen,
                                       (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
                                       dummyLen) == NULL)
#endif WEBADMIN
// end of here
                {
                        return SNMP_ERR_TOOBIG; // bogus error ????
                }
        }
        *index = 0;
        return SNMP_ERR_NOERROR;
}
int
snmp_agent_parse(
        snmp_session *session,
        uint8 *indata,
        int inlength,
        uint8 *outdata,
        int *outlength
)
{
        uint8    msgtype, type;
        long      zero = 0;
        long      reqid, errstat, errindex, dummyindex;
        uint8    *out_auth, *out_header, *out_reqid;
        uint8    *startData = indata;
        int       startLength = inlength;
        long      version;
        uint8    *origdata = indata;
        int           origlen = inlength;
//      usecEntry *ue;
        int       packet_len, ret = 0;
#ifdef WEBADMIN
        int       newoutdata;   // add -- by arius 5/17/2000
        int       len;          // add -- by arius 5/17/2000
#endif WEBADMIN

        session->community_len = COMMUNITY_MAX_LEN;
        //get community name
        indata = snmp_parse_auth(indata, &inlength, community, &session->community_len, &version);

        if (indata == NULL){
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("bad auth encoding");
                return 0;
        }

#if 1 //ONLY SUPPORT VERSION 1
        if(version != SNMP_VERSION_1) {
                ERROR("wrong version");
                snmp_inbadversions++;
                return 0;
        }

#else ////////////////////////////////////////////
        if( version != SNMP_VERSION_1 && version != SNMP_VERSION_2C && version != SNMP_VERSION_2 ) {
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("wrong version");
                snmp_inbadversions++;
                return 0;
        }

        if( version == SNMP_VERSION_2C || version == SNMP_VERSION_2 ) {
                if( version == SNMP_VERSION_2 ) {
                        ret = check_auth( session, origdata, origlen, indata - session->community_len, session->community_len, &ue );
                        *outlength = (SNMP_MAX_LEN < session->MMS) ? SNMP_MAX_LEN : session->MMS;
                        session->MMS = SNMP_MAX_LEN;
                } else if( version == SNMP_VERSION_2C ) {
                        ret = community_auth( session );
                        session->version = SNMP_VERSION_2C;
                }

                if( ret < 0 ) {
//                      increment_stat( -ret );
                        if( (indata=asn_parse_header(indata, &inlength, &msgtype))
                        &&  asn_parse_int(indata, &inlength, &type, &reqid, sizeof(reqid)) )
                        {
                                if( msgtype == REPORT_MSG ) return 0;
                                if( !(session->qoS & USEC_QOS_GENREPORT) ) return 0;
                                session->agentBoots = _agentBoots;
                                session->agentClock = _agentStartTime;
                                memcpy( session->agentID, _agentID, 12 );
                                session->MMS = SNMP_MAX_LEN;
                                create_report( session, outdata, outlength, -ret, reqid );
                                return 1;
                        } else {
                                return 0;
                        }
                } else if( ret > 0 ) {
//                      increment_stat( ret );
                        return 0;
                }

        } else  {
#endif  /////////////////////////////////////////////////////

        //VERSION 1
        if(community_auth( session )==0) return 0;
//      session->version = SNMP_VERSION_1;

#if 0 ////////
        }
#endif ///////

        indata = asn_parse_header(indata, &inlength, &msgtype);
        if (indata == NULL){
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("bad header");
                return 0;
        }

    // XXX: increment by total number of vars at correct place:
    snmp_intotalreqvars++;

        if(msgtype == GET_REQ_MSG)      snmp_ingetrequests++;
        else if (msgtype == GETNEXT_REQ_MSG) snmp_ingetnexts++;
        else if (msgtype ==     SET_REQ_MSG) snmp_insetrequests++;
        else return 0;

//   if (msgtype == GETBULK_REQ_MSG: //version 2

        // Request ID
        indata = asn_parse_int(indata, &inlength, &type, &reqid, sizeof(reqid));
        if (indata == NULL){
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("bad parse of reqid");
                return 0;
        }

        //Error Status
        indata = asn_parse_int(indata, &inlength, &type, &errstat, sizeof(errstat));
        if (indata == NULL){
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("bad parse of errstat");
                snmp_inasnparseerrors++;
                return 0;
        }

        //Error Index
    indata = asn_parse_int(indata, &inlength, &type, &errindex, sizeof(errindex));
    if (indata == NULL){
//              increment_stat( SNMP_STAT_ENCODING_ERRORS );
                ERROR("bad parse of errindex");
                return 0;
        }

     //
     // Now start cobbling together what is known about the output packet.
     // The final lengths are not known now, so they will have to be recomputed
     // later.
     //

    // setup for response
//Simon    time( (time_t *) &session->agentTime );
//Simon    session->agentClock = _agentStartTime;
//Simon    session->agentBoots = _agentBoots;
//Simon   memcpy( session->agentID, _agentID, 12 );

        out_auth = outdata;

        //Set Resp Community
        out_header = snmp_build_auth(out_auth, outlength,
                                     community,session->community_len,
                                     (long)SNMP_VERSION_1,0);
        if (out_header == NULL){
                ERROR("snmp_build_auth failed");
                snmp_inasnparseerrors++;
                return 0;
        }

        out_reqid = asn_build_sequence(out_header, outlength, (uint8)GET_RSP_MSG, 0);
        if (out_reqid == NULL){
                ERROR("out_reqid == NULL");
                return 0;
        }

        //Set Resp ID
        type = (uint8)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
        // return identical request id
        outdata = asn_build_int(out_reqid, outlength, type, &reqid, sizeof(reqid));
        if (outdata == NULL){
                ERROR("build reqid failed");
                return 0;
        }

    // assume that error status will be zero
        outdata = asn_build_int(outdata, outlength, type, &zero, sizeof(zero));
        if (outdata == NULL){
                ERROR("build errstat failed");
                return 0;
        }

    // assume that error index will be zero
        outdata = asn_build_int(outdata, outlength, type, &zero, sizeof(zero));
        if (outdata == NULL){
                ERROR("build errindex failed");
                return 0;
        }

#if 0 ///////////////////////////////////////////
        if (msgtype == GETBULK_REQ_MSG)
        errstat = bulk_var_op_list(indata, inlength, outdata, *outlength,
                                    errstat, errindex, &errindex );
    else
#endif 0 ////////////////////////////////////////

        errstat = parse_var_op_list(session, indata, inlength, outdata, *outlength,
                                    &errindex, msgtype, RESERVE1);

        if (msgtype== SET_REQ_MSG){
                if (errstat == SNMP_ERR_NOERROR)
                        errstat = parse_var_op_list(session, indata, inlength, outdata, *outlength,
                                        &errindex, msgtype, RESERVE2);
                if (errstat == SNMP_ERR_NOERROR){
                //
                //* SETS require 3-4 passes through the var_op_list.  The first two
                //* passes verify that all types, lengths, and values are valid
                //* and may reserve resources and the third does the set and a
                //* fourth executes any actions.  Then the identical GET RESPONSE
                //* packet is returned.
                //* If either of the first two passes returns an error, another
                //* pass is made so that any reserved resources can be freed.
                //*
              parse_var_op_list(session, indata, inlength, outdata, *outlength,
                                &dummyindex, msgtype, COMMIT);
              parse_var_op_list(session, indata, inlength, outdata, *outlength,
                                &dummyindex, msgtype, ACTION);
              if (create_identical(session, startData, out_auth, startLength, 0L, 0L )){
                  *outlength = packet_end - out_auth;
                  return 1;
              }
              return 0;
        } else {
              parse_var_op_list(session, indata, inlength, outdata, *outlength,
                                &dummyindex, msgtype, COMM_FREE);
        }
    }
    switch((short)errstat){
        case SNMP_ERR_NOERROR:
            // re-encode the headers with the real lengths
            *outlength = packet_end - out_header;
            packet_len = *outlength;
            outdata = asn_build_sequence(out_header, outlength, GET_RSP_MSG,
                                        packet_end - out_reqid);
// add --- By arius 5/17/2000
#ifdef WEBADMIN
newoutdata = packet_end - outdata;  // how many shifts
len = packet_end - out_reqid;
packet_end = outdata;               // save new pointer end of packet
outdata -= len;
out_reqid = out_reqid - newoutdata;
#endif WEBADMIN
// end of here
            if (outdata != out_reqid){
                ERROR("internal error: header");
                return 0;
            }

            *outlength = packet_end - out_auth;
            outdata = snmp_build_auth(out_auth, outlength,
                                          community, session->community_len,
                                          (long)SNMP_VERSION_1,
                                          packet_end - out_header );
// add --- By arius 5/17/2000
#ifdef WEBADMIN
out_header -= (packet_end - outdata);
packet_end = outdata;            // save new pointer end of packet
#endif WEBADMIN
// end of here
            *outlength = packet_end - out_auth;
#if 0
            // packet_end is correct for old SNMP.  This dichotomy needs to be fixed.
            if (session->version == SNMP_VERSION_2)
                packet_end = out_auth + packet_len;
#endif
            break;
        case SNMP_ERR_TOOBIG:
            snmp_intoobigs++;
#if notdone
            if (session->version == SNMP_VERSION_2){
                create_toobig(out_auth, *outlength, reqid, pi);
                break;
            } // else FALLTHRU
#endif
        case SNMP_ERR_NOACCESS:
        case SNMP_ERR_WRONGTYPE:
        case SNMP_ERR_WRONGLENGTH:
        case SNMP_ERR_WRONGENCODING:
        case SNMP_ERR_WRONGVALUE:
        case SNMP_ERR_NOCREATION:
        case SNMP_ERR_INCONSISTENTVALUE:
        case SNMP_ERR_RESOURCEUNAVAILABLE:
        case SNMP_ERR_COMMITFAILED:
        case SNMP_ERR_UNDOFAILED:
        case SNMP_ERR_AUTHORIZATIONERROR:
        case SNMP_ERR_NOTWRITABLE:
    case SNMP_ERR_INCONSISTENTNAME:
        case SNMP_ERR_NOSUCHNAME:
        case SNMP_ERR_BADVALUE:
        case SNMP_ERR_READONLY:
        case SNMP_ERR_GENERR:
            if (create_identical(session, startData, out_auth, startLength, errstat,
                                 errindex)){
                *outlength = packet_end - out_auth;
                return 1;
            }
            return 0;
        default:
            return 0;
    }

#if 0
    if( session->qoS & USEC_QOS_AUTH ) {
        md5Digest( out_auth, *outlength, outdata - (session->contextLen + 16),
            outdata - (session->contextLen + 16) );
    }
#endif

        return 1;
}
Beispiel #13
0
char *   
snmp_parse_trap(u_char * trapdata,  /* IN - actual trap data from packet */
   unsigned    datalen,             /* IN - length of trapdata */
   struct trap_info *   trapInfo)   /* IN/OUT - struct to fill in */
{
   u_char * more;    /* pointer to next unparsed PDU data */
   u_char * nextVar; /* pointer to next unparsed TRAP variable */
   unsigned   left;  /* length of more */
   long     version; /* SNMP version, always v1 */
   u_char   type;    /* data types for checking */
   u_char * varValPtr;
   int   vars_in_struct;
   struct trapVar *  vars; /* trap variables data structures */
   u_long   trapType;
   unsigned length;  /* scratch for passing to asn1 */

   /* do some basic setup of the passed data structures */
   vars_in_struct = trapInfo->trapVars;
   trapInfo->trapVars = 0;       /* bump later if vars are present */

   left = datalen;
   more = snmp_auth_parse(trapdata, &left, (u_char*)trapInfo->community, 
    (unsigned*)&trapInfo->commLen, &version);
   if (!more)
      return "community parse";

   more = asn_parse_header(more, &left, &type);
   if (!more || type != TRP_REQ_MSG)
      return "trap pdu header";

   more = asn_parse_objid(more, &left, &type, &trapInfo->objId[0],
    (unsigned*)&trapInfo->objLen);
   if (!more || type != ASN_OBJECT_ID)
      return "sys ObjId";

   length = 4;       /* number of bytes in IP address buffer */
   more = asn_parse_string(more, &left, &type, 
    (u_char*)(&trapInfo->agent_ip), &length);

   if (!more || type != IPADDRESS)
      return "agent's IP address";

   more = asn_parse_int(more, &left, &type, (long*)&trapType, sizeof(long));
   if (!more || type != ASN_INTEGER || trapType > 6)
      return "trap type";
   trapInfo->trapType = trapType;

   more = asn_parse_int(more, &left, &type, (long*)&trapType, sizeof(long));
   if (!more || type != ASN_INTEGER)
      return "specific type";
   trapInfo->trapSpecific = trapType;

   more = asn_parse_int(more, &left, &type, (long*)&trapInfo->time, sizeof(long));
   if (!more || type != TIMETICKS)
      return "timestamp";

   if (!left)     /* no variables in trap ? */
      return NULL;

   /* rest of packet is a sequence of variables */
   more = asn_parse_header(more, &left, &type);    /* strip off leading SEQ */
   if (!more || type != SEQUENCE)
      return "trap vars header";

   vars = trapInfo->vars;     /* set pointer array to receive variables data */

   while (left)   /* keep parsing & counting vars as long as there's data */
   {
      /* extract variable info for this var */
      length = left;    /* number of valid bytes left in packet buffer */
      varNameLen = MAX_OID_LEN ; /* define the max size of varName */
      nextVar = snmp_parse_var_op(more, varName, &varNameLen, &varType,
       &varLen, &varValPtr, &left);

      if (!nextVar)     /* quit if parse failed */
         return ("var_op header");

      /* extract the variable's value; pointed to by varValPtr: */
      length -= more - nextVar;     /* deduct size of header -> max. length of var */
      switch (varType)
      {
      case ASN_INTEGER:
      case GAUGE:
      case COUNTER:
      case TIMETICKS:
         varLen = sizeof(long);     /* size required by asn_parse_int() */
         nextVar = asn_parse_int(varValPtr, &length, &varType,
          (long *)(&varVal[0]), varLen);
         break;
      case ASN_OCTET_STR:
      case IPADDRESS:
      case OPAQUE:
         varLen = MAX_TRAP_VAR;
         nextVar = asn_parse_string(varValPtr, &length, &varType,
          varVal, &varLen);
         break;
      case ASN_OBJECT_ID:
         varLen = MAX_TRAP_VAR;
         nextVar = asn_parse_objid(varValPtr, &length, &varType,
          (oid *)(&varVal[0]), &varLen);
         break;
      case ASN_NULL:
         nextVar = asn_parse_null(varValPtr, &length, &varType);
         break;
         default:
         SNMPERROR("wrong type");
         return NULL;
      }

      if (!nextVar)
         return("variable");

      /* if another trap variable info slot is available, fill it in */
      if (trapInfo->trapVars <= vars_in_struct)
      {
         oidcpy(vars->varName, varName, varNameLen);
         if (vars->varBufLen <= varLen)   /* need to truncate? */
            vars->varValLen = vars->varBufLen-1;
         else     /* we have room for the full variable data field */
            vars->varValLen = varLen;
         MEMCPY(vars->varBuf, varVal, vars->varValLen);
         vars->varNameLen = varNameLen;
         vars->varType = varType;
         vars++;     /* point to next variable info structure */
      }
      trapInfo->trapVars++;      /* another var */
      more = nextVar;      /* bump pointer to pdu */
   }
   return NULL;
}
//*
//*---------------------------------------------------------------------------------
//* Function Name: snmp_parse_var
//* Description  : Get variables by parsing snmp message. The message is decoded in
//*        BER deconding rules.
//* Return Value : Pointer of decoding variables
//* Calling To   : asn_parse_header, asn_parse_objid, asn_parse_int,
//*        asn_parse_string
//* Called By    : snmp_parse
//*---------------------------------------------------------------------------------
//*
variable_list   *snmp_parse_var(uint8 *data,int length)
{
    uint8                       type;
    variable_list               vh, *vp;
    uint8                       *varBindP;
    int                         varBind_len;
    uint8                       objId[SNMP_MAX_NAME_LEN];
    uint8                       *varVal;
    int                         parse_ok;

    data = asn_parse_header(data, &length, &type);
    if ((data == NULL) || (type != (uint8) (ASN_SEQUENCE | ASN_CONSTRUCTOR)))
        return ( NULL );

    vh.next  = NULL;
    vp       = &vh;
    varBindP = data;
    parse_ok = TRUE;

    while (length > 0) {
        varBind_len = length;

        vp->next = (variable_list *) malloc(sizeof(variable_list));
        if (vp->next == NULL) {
            parse_ok = FALSE;
            break;      //---SNMP: Memory allocation error on 'snmp_parse_var'.
        }
        else {
            vp             = vp->next;
            vp->next       = NULL;
            vp->name       = NULL;
            vp->name_len   = SNMP_MAX_NAME_LEN;
            vp->val.string = NULL;
        }

        varBindP = asn_parse_header(varBindP, &varBind_len, &type);
        if ((varBindP == NULL) ||
            (type != (uint8) (ASN_SEQUENCE | ASN_CONSTRUCTOR))) {
            parse_ok = FALSE;
            break;
        }

        //*
        //*  Parse variable bind name.
        //*
        varBindP = asn_parse_objid(varBindP, &varBind_len, &type, objId, &vp->name_len);
        if ((varBindP == NULL) ||
            (type != (uint8) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID))) {
            parse_ok = FALSE;
            break;
        }

        vp->name = (oid *) malloc((unsigned) vp->name_len * sizeof(oid));
        if (vp->name == NULL) {
            parse_ok = FALSE;
            break;      //-----SNMP: Memory alloc error on 'snmp_parse_var'.
        }
        else {
            bcopy((char *) objId, (char *) vp->name, vp->name_len * sizeof(oid));
        }

        //*
        //*  Parse variable bind value.
        //*
        varVal   = varBindP;
        varBindP = asn_parse_header(varBindP, &varBind_len, &vp->type);
        if (varBindP == NULL) {
            parse_ok = FALSE;
            break;
        }
        else {
            vp->val_len = varBind_len;
            varBindP    = varBindP + varBind_len;  // skip value body to next variable
            length      = length - (int)(varBindP - data);
            data        = varBindP;
            varBind_len = SNMP_MAX_LEN;
        }

        switch (vp->type) {
            case ASN_INTEGER:
            case COUNTER:
            case GAUGE:
            case TIMETICKS:
                 vp->val_len     = sizeof(long);   // support long intger only
                 vp->val.integer = (long *) malloc(vp->val_len);
                 if (vp->val.integer == NULL) {
                        parse_ok = FALSE;
                     break;  //---SNMP:Memory alloc error on 'snmp_parse_var'.
                 }
                 asn_parse_int(varVal, &varBind_len, &vp->type,
                           (long *) vp->val.integer, vp->val_len);
                 break;
            case ASN_OCTET_STRING:
            case IPADDRESS:
            case OPAQUE:
                 vp->val.string = (uint8 *) malloc(vp->val_len);
                 if (vp->val.string == NULL) {
                        parse_ok = FALSE;
                        break;  //----SNMP:Memory alloc error on 'snmp_parse_var'.
                 }
                 asn_parse_string(varVal, &varBind_len, &vp->type,
                           vp->val.string, &vp->val_len);
                 break;
            case ASN_OBJECT_ID:
                 vp->val_len = SNMP_MAX_NAME_LEN;
                 asn_parse_objid(varVal, &varBind_len, &vp->type, objId, &vp->val_len);
                 vp->val_len = vp->val_len * sizeof(oid);
                 vp->val.objid = (oid *) malloc((unsigned) vp->val_len);
                 if (vp->val.objid == NULL) {
                        parse_ok = FALSE;
                     break;   //---SNMP:Memory alloc error on 'snmp_parse_var'.
                 }
                 bcopy((char *) objId, (char *) vp->val.objid, vp->val_len);
                 break;
            case ASN_NULL:
                 break;
            default:
                 parse_ok = FALSE;  //-----Warning: Bad type received.
                 break;
        }

        if ( ! parse_ok ) break;
    }

    if ( parse_ok ) {
        return( vh.next );
    }
    else {
        while ( vh.next ) {
            vp      = vh.next;
            vh.next = vp->next;
            if (vp->name != NULL) free((char *) vp->name);
            if (vp->val.string != NULL) free((char *) vp->val.string);
            free((char *) vp);
        }
        return ( NULL );
    }
}
Beispiel #15
0
/* Decodes PDU from Packet into PDU.
 *
 * Returns a pointer to the next byte of the packet, which is where the
 * Variable Bindings start.
 */
u_char *snmp_pdu_decode(u_char *Packet,       /* data */
			int *Length,          /* &length */
			struct snmp_pdu *PDU) /* pdu */
{
  u_char *bufp;
  u_char PDUType;
  int four;
  u_char ASNType;
  oid objid[MAX_NAME_LEN];

  bufp = asn_parse_header(Packet, Length, &PDUType);
  if (bufp == NULL)
    ASN_PARSE_ERROR(NULL);

#ifdef DEBUG_PDU_DECODE
  printf("PDU Type: %d\n", PDUType);
#endif

  PDU->command = PDUType;
  switch (PDUType) {

  case TRP_REQ_MSG:

    /* SNMPv1 Trap Message */

    /* enterprise */
    PDU->enterprise_length = MAX_NAME_LEN;
    bufp = asn_parse_objid(bufp, Length,
			   &ASNType, objid, &PDU->enterprise_length);
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    PDU->enterprise = (oid *)malloc(PDU->enterprise_length * sizeof(oid));
    if (PDU->enterprise == NULL) {
      snmp_set_api_error(SNMPERR_OS_ERR);
      return(NULL);
    }

    memcpy((char *)PDU->enterprise, (char *)objid, 
	   PDU->enterprise_length * sizeof(oid));
	
    /* Agent-addr */
    four = 4;
    bufp = asn_parse_string(bufp, Length, 
			    &ASNType, 
			    (u_char *)&PDU->agent_addr.sin_addr.s_addr, 
			    &four);
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* Generic trap */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 (int *)&PDU->trap_type, 
			 sizeof(PDU->trap_type));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* Specific Trap */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 (int *)&PDU->specific_type, 
			 sizeof(PDU->specific_type));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* Timestamp */
    bufp = asn_parse_unsigned_int(bufp, Length, 
				  &ASNType, 
				  &PDU->time, sizeof(PDU->time));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);
    break;

    /**********************************************************************/

  case SNMP_PDU_GETBULK:

    /* SNMPv2 Bulk Request */

    /* request id */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->reqid, sizeof(PDU->reqid));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* non-repeaters */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->non_repeaters, sizeof(PDU->non_repeaters));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    /* max-repetitions */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->max_repetitions, sizeof(PDU->max_repetitions));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

    break;
    /**********************************************************************/

  default:

    /* Normal PDU Encoding */

    /* request id */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->reqid, sizeof(PDU->reqid));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

#ifdef DEBUG_PDU_DECODE
    printf("PDU Request ID: %d\n", PDU->reqid);
#endif

    /* error status */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->errstat, sizeof(PDU->errstat));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

#ifdef DEBUG_PDU_DECODE
    printf("PDU Error Status: %d\n", PDU->errstat);
#endif

    /* error index */
    bufp = asn_parse_int(bufp, Length, 
			 &ASNType, 
			 &PDU->errindex, sizeof(PDU->errindex));
    if (bufp == NULL)
      ASN_PARSE_ERROR(NULL);

#ifdef DEBUG_PDU_DECODE
    printf("PDU Error Index: %d\n", PDU->errindex);
#endif

    break;
  }

  return(bufp);
}