Exemplo n.º 1
0
/* GET message header. */
char *
smux_parse_get_header (char *ptr, size_t *len, long *reqid)
{
  u_char type;
  long errstat;
  long errindex;

  /* Request ID. */
  ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));

  if (debug_smux)
    zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);

  /* Error status. */
  ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));

  if (debug_smux)
    zlog_debug ("SMUX GET errstat %ld len: %ld", errstat, *len);

  /* Error index. */
  ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));

  if (debug_smux)
    zlog_debug ("SMUX GET errindex %ld len: %ld", errindex, *len);

  return ptr;
}
//*
//* 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;
}
//*
//*---------------------------------------------------------------------------------
//* 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);
}
Exemplo n.º 4
0
/* SMUX_RRSP message. */
void
smux_parse_rrsp (char *ptr, size_t len)
{
  char val;
  long errstat;
  
  ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));

  if (debug_smux)
    zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
0
/*******************************************************************-o-******
 * snmp_comstr_parse
 *
 * Parameters:
 *	*data		(I)   Message.
 *	*length		(I/O) Bytes left in message.
 *	*psid		(O)   Community string.
 *	*slen		(O)   Length of community string.
 *	*version	(O)   Message version.
 *      
 * Returns:
 *	Pointer to the remainder of data.
 *
 *
 * Parse the header of a community string-based message such as that found
 * in SNMPv1 and SNMPv2c.
 */
u_char         *
snmp_comstr_parse(u_char * data,
                  size_t * length,
                  u_char * psid, size_t * slen, long *version)
{
    u_char          type;
    long            ver;
    size_t          origlen = *slen;

    /*
     * Message is an ASN.1 SEQUENCE.
     */
    data = asn_parse_sequence(data, length, &type,
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
                              "auth message");
    if (data == NULL) {
        return NULL;
    }

    /*
     * First field is the version.
     */
    DEBUGDUMPHEADER("recv", "SNMP version");
    data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
    DEBUGINDENTLESS();
    *version = ver;
    if (data == NULL) {
        ERROR_MSG("bad parse of version");
        return NULL;
    }

    /*
     * second field is the community string for SNMPv1 & SNMPv2c 
     */
    DEBUGDUMPHEADER("recv", "community string");
    data = asn_parse_string(data, length, &type, psid, slen);
    DEBUGINDENTLESS();
    if (data == NULL) {
        ERROR_MSG("bad parse of community");
        return NULL;
    }
    psid[SNMP_MIN(*slen, origlen - 1)] = '\0';
    return (u_char *) data;

}                               /* end snmp_comstr_parse() */
void setVariable(uint8 *var_val,uint8 var_val_type,int var_val_len,uint8  *statP,int statLen)
{
	int 	buffersize = 1000;

	switch(var_val_type){
		case ASN_INTEGER:
		case COUNTER:
		case GAUGE:
		case TIMETICKS:
			asn_parse_int(var_val, &buffersize, &var_val_type, (long *)statP, statLen);
			break;
		case ASN_OCTET_STRING:
		case IPADDRESS:
		case OPAQUE:
			asn_parse_string(var_val, &buffersize, &var_val_type, statP, &statLen);
			break;
		case ASN_OBJECT_ID:
			asn_parse_objid(var_val, &buffersize, &var_val_type, (oid *)statP, &statLen);
			break;
	}
}
Exemplo n.º 8
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);
}
Exemplo n.º 9
0
int
fixExecError(int action,
	     u_char *var_val,
	     u_char var_val_type,
	     int var_val_len,
	     u_char *statP,
	     oid *name,
	     int name_len)
{
  
  struct extensible *exten;
  long tmp=0;
  int tmplen=1000, fd;
  static struct extensible ex;
  FILE *file;

  if ((exten = get_exten_instance(extens,name[10]))) {
    if (var_val_type != ASN_INTEGER) {
      printf("Wrong type != int\n");
      return SNMP_ERR_WRONGTYPE;
    }
    asn_parse_int(var_val,&tmplen,&var_val_type,&tmp,sizeof(int));
    if ((tmp == 1) && (action == COMMIT) && (exten->fixcmd[0] != 0)) {
      sprintf(ex.command, exten->fixcmd);
      if ((fd = get_exec_output(&ex))) {
        file = fdopen(fd,"r");
        while (fgets(ex.output,STRMAX,file) != NULL);
        fclose(file);
        close(fd);
        wait_on_exec(&ex);
      }
    }
    return SNMP_ERR_NOERROR;
  }
  return SNMP_ERR_WRONGTYPE;
}
Exemplo n.º 10
0
static void
setVariable(u_char *var_val,
	    u_char var_val_type,
	    size_t var_val_len,
	    u_char *statP,
	    size_t statLen)
{
    size_t buffersize = 1000;

    switch(var_val_type){
	case ASN_INTEGER:
	    asn_parse_int(var_val, &buffersize, &var_val_type, (long *)statP, statLen);
	    break;
	case ASN_COUNTER:
	case ASN_GAUGE:
	case ASN_TIMETICKS:
	    asn_parse_unsigned_int(var_val, &buffersize, &var_val_type, (u_long *)statP, statLen);
	    break;
	case ASN_COUNTER64:
	    asn_parse_unsigned_int64(var_val, &buffersize, &var_val_type,
				     (struct counter64 *)statP, statLen);
	    break;
	case ASN_OCTET_STR:
	case ASN_IPADDRESS:
	case ASN_OPAQUE:
	case ASN_NSAP:
	    asn_parse_string(var_val, &buffersize, &var_val_type, statP, &statLen);
	    break;
	case ASN_OBJECT_ID:
	    asn_parse_objid(var_val, &buffersize, &var_val_type, (oid *)statP, &statLen);
	    break;
	case ASN_BIT_STR:
	    asn_parse_bitstring(var_val, &buffersize, &var_val_type, statP, &statLen);
	    break;
    }
}
//*
//*---------------------------------------------------------------------------------
//* 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 );
    }
}
Exemplo n.º 12
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);
}
Exemplo n.º 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;
}
Exemplo n.º 14
0
/* FUNCTION: snmp_print_value()
 * Print the value into a buffer and return the buffer. 
 * 
 * Buffer is static to this function.
 *
 * PARAM1: u_char * var_val          - ASN.1 encoded value
 * PARAM1: u_char  var_val_type      - ASN.1 type of value
 *
 * RETURNS: 
 */
char *
snmp_print_value(u_char *var_val, u_char var_val_type)
{
   /* set an abritrarily large buffer parm for asn1 parsing. 
    * We don't use the returned value for this anyway.
    */
   unsigned   asn_buf_size = 1000;     /*  */
   unsigned   set_var_size = _MAX_PATH;  /* bytes in field to set */
   long tmpvalue=0;

   static char datastr[_MAX_PATH];
   static char datatmp[_MAX_PATH];
   static oid  dataoid[_MAX_PATH];

   datastr[0]=0;  /* null terminate */

   if (!var_val)
      return datastr;

   switch (var_val_type)
   {
   case ASN_INTEGER:
   case COUNTER:
   case GAUGE: /* valid for GAUGE32 and UNSIGNED32 too */
   case TIMETICKS:
      if (!asn_parse_int(var_val, &asn_buf_size, &var_val_type, 
         &tmpvalue, sizeof(long)))
      {
         break;
      }
      sprintf(datastr,"%ld",tmpvalue) ;

      break;
   case ASN_BIT_STR:
      if (!asn_parse_bits(var_val, &asn_buf_size, &var_val_type, 
         (unsigned char *)datatmp, &set_var_size))
      {
         break;
      }
      strcpy(datastr,datatmp);
         break;
   case ASN_OCTET_STR:
   case IPADDRESS:
   case OPAQUE:
      if (!asn_parse_string(var_val, &asn_buf_size, &var_val_type, 
         (unsigned char *)datatmp, &set_var_size))
      {
         break;
      }
      *(datatmp + set_var_size) = '\0'; /* null terminate the strings */
      strcpy(datastr,datatmp);
      break;
   case ASN_OBJECT_ID:
      if (!asn_parse_objid(var_val, &asn_buf_size, &var_val_type, 
         dataoid, &set_var_size))
      {
         break;
      }
      strcpy(datastr, print_oid(dataoid, set_var_size));
      break;
   case ASN_NULL:
      strcpy (datastr, "<NULL>");
      break;
   }

   return datastr;
}
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;
}
Exemplo n.º 16
0
int
decode_vbind (unsigned char *data, unsigned int vb_len)
{
  unsigned char *var_val;
  oid var_name[MAX_OID_LEN];	/* To test the objid */
  size_t name_len = MAX_OID_LEN;	/* To test the objid */
  int badtype=0;
  size_t len;
  struct variable_list *vp;
  oid objid[MAX_OID_LEN];
  char _docsis_snmp_label[50];	/* To hold the 'name' of the type, i.e. Integer etc */
  char *enum_string = NULL;
  static char outbuf[16384];
  struct tree *subtree;
  struct enum_list *enums;

  memset (outbuf, 0, 16384);

  vp = (struct variable_list *) malloc (sizeof (struct variable_list));
  if (vp == NULL)
    {
      fprintf (stderr, "Out of memory\n");
      return 0;
    }
  memset (vp, 0, sizeof (struct variable_list));

  vp->next_variable = NULL;
  vp->val.string = NULL;
  vp->name_length = MAX_OID_LEN;
  vp->name = 0;
  data = snmp_parse_var_op (data, objid, &vp->name_length, &vp->type, &vp->val_len,
		       &var_val, (size_t *) & vb_len);

  if (data == NULL)
    return -1;
  if (snmp_set_var_objid (vp, objid, vp->name_length))
    return -1;

  len = PACKET_LENGTH;

  if (netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
                                 NETSNMP_DS_LIB_EXTENDED_INDEX);
    } /* Disable extended index format ... makes it harder to parse tokens in lex */
  if (!netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
                                 NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
    } /* Enable printing numeric enums */
  if (netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
                                 NETSNMP_DS_LIB_ESCAPE_QUOTES);
    } /* Disable escape quotes in string index output  */

  netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID,
			      NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
			      NETSNMP_OID_OUTPUT_SUFFIX);

  if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_OID_OUTPUT_NUMERIC)) {
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
                                                  NETSNMP_OID_OUTPUT_NUMERIC);
  }

  snprint_objid (outbuf, 1023, vp->name, vp->name_length);

  if (!get_node (outbuf, var_name, &name_len))
    {
      if (!read_objid (outbuf, var_name, &name_len))
	{
	  fprintf (stderr,
		   "/* Hmm ... can't find oid %s at line %d ... perhaps the MIBs are not installed ? */\n",
		   outbuf, line);
	  /* temporarily set full output format */
	  netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID,
			      NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
			      NETSNMP_OID_OUTPUT_FULL);
	  memset (outbuf, 0, 1024);
	  snprint_objid (outbuf, 1023, vp->name, vp->name_length);
	  /* Go back to suffix-mode for better readability */
	  netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID,
			      NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
			      NETSNMP_OID_OUTPUT_SUFFIX);
	}
    }

  printf("%s", outbuf);

/* save the subtree - we need it later to show enums */
  subtree = get_tree (var_name, name_len, get_tree_head() );

/* This first switch is just for saving the type in the format we actually want
   to print. */

  switch ((short) vp->type)
    {
    case ASN_INTEGER:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Integer");
      break;
    case ASN_COUNTER:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Counter32");
      break;
    case ASN_GAUGE:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Gauge32");
      break;
    case ASN_TIMETICKS:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "TimeTicks");
      break;
    case ASN_UINTEGER:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Unsigned32");
      break;
#ifdef OPAQUE_SPECIAL_TYPES
    case ASN_OPAQUE_COUNTER64:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "OpaqueCounter64");
      break;
    case ASN_OPAQUE_U64:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "OpaqueU64");
      break;
#endif /* OPAQUE_SPECIAL_TYPES */
    case ASN_COUNTER64:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Counter64");
      break;
#ifdef OPAQUE_SPECIAL_TYPES
    case ASN_OPAQUE_FLOAT:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "OpaqueFloat");
      break;
    case ASN_OPAQUE_DOUBLE:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "OpaqueDouble");
      break;
    case ASN_OPAQUE_I64:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "OpaqueI64");
      break;
#endif /* OPAQUE_SPECIAL_TYPES */
    case ASN_OCTET_STR:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "String");
      break;
    case ASN_IPADDRESS:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "IPAddress");
      break;
    case ASN_OPAQUE:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "Opaque");
      break;
    case ASN_NSAP:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "NSAP");
      break;
    case ASN_OBJECT_ID:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "ObjectID");
      break;
    case ASN_BIT_STR:
      memset (_docsis_snmp_label, 0, 50);
      sprintf (_docsis_snmp_label, "BitString");
      break;
    }

  switch ((short) vp->type)
    {
    case ASN_INTEGER:

      vp->val.integer = (long *) vp->buf;
      vp->val_len = sizeof (long);
      asn_parse_int (var_val, &len, &vp->type,
		     (long *) vp->val.integer, sizeof (vp->val.integer));

      break;
    case ASN_COUNTER:
    case ASN_GAUGE:
    case ASN_TIMETICKS:
    case ASN_UINTEGER:
      vp->val.integer = (long *) vp->buf;
      vp->val_len = sizeof (u_long);
      asn_parse_unsigned_int (var_val, &len, &vp->type,
			      (u_long *) vp->val.integer,
			      sizeof (vp->val.integer));

      break;

#ifdef OPAQUE_SPECIAL_TYPES
    case ASN_OPAQUE_COUNTER64:
    case ASN_OPAQUE_U64:
#endif /* OPAQUE_SPECIAL_TYPES */
    case ASN_COUNTER64:
      vp->val.counter64 = (struct counter64 *) vp->buf;
      vp->val_len = sizeof (struct counter64);
      asn_parse_unsigned_int64 (var_val, &len, &vp->type,
				(struct counter64 *) vp->val.counter64,
				sizeof (*vp->val.counter64));
      break;
#ifdef OPAQUE_SPECIAL_TYPES
    case ASN_OPAQUE_FLOAT:
      vp->val.floatVal = (float *) vp->buf;
      vp->val_len = sizeof (float);
      asn_parse_float (var_val, &len, &vp->type,
		       vp->val.floatVal, vp->val_len);
      break;
    case ASN_OPAQUE_DOUBLE:
      vp->val.doubleVal = (double *) vp->buf;
      vp->val_len = sizeof (double);
      asn_parse_double (var_val, &len, &vp->type,
			vp->val.doubleVal, vp->val_len);
      break;
    case ASN_OPAQUE_I64:
      vp->val.counter64 = (struct counter64 *) vp->buf;
      vp->val_len = sizeof (struct counter64);
      asn_parse_signed_int64 (var_val, &len, &vp->type,
			      (struct counter64 *) vp->val.counter64,
			      sizeof (*vp->val.counter64));

      break;
#endif /* OPAQUE_SPECIAL_TYPES */
    case ASN_OCTET_STR:
    case ASN_IPADDRESS:
    case ASN_OPAQUE:
    case ASN_NSAP:
      if (vp->val_len < sizeof (vp->buf))
	{
	  vp->val.string = (u_char *) vp->buf;
	}
      else
	{
	  vp->val.string = (u_char *) malloc ((unsigned) vp->val_len+1);
	  memset(vp->val.string, 0, vp->val_len+1);
	}
      asn_parse_string (var_val, &len, &vp->type, vp->val.string,
			&vp->val_len);
      break;
    case ASN_OBJECT_ID:
      vp->val_len = MAX_OID_LEN;
      asn_parse_objid (var_val, &len, &vp->type, objid, &vp->val_len);
      vp->val_len *= sizeof (oid);
      vp->val.objid = (oid *) malloc ((unsigned) vp->val_len);
      memmove (vp->val.objid, objid, vp->val_len);
      break;
    case SNMP_NOSUCHOBJECT:
    case SNMP_NOSUCHINSTANCE:
    case SNMP_ENDOFMIBVIEW:
    case ASN_NULL:
      break;
    case ASN_BIT_STR:
      vp->val.bitstring = (u_char *) malloc (vp->val_len);
      asn_parse_bitstring (var_val, &len, &vp->type,
			   vp->val.bitstring, &vp->val_len);
      break;
    default:
      fprintf(stderr, "Error: bad type returned (%x)\n", vp->type);
      badtype = 1;
      break;
    }

  if (!netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_FULL_OID))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
				 NETSNMP_DS_LIB_PRINT_FULL_OID);
    }
  if (!netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
				 NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS);
    }
  if (!netsnmp_ds_get_boolean
      (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT))
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
				 NETSNMP_DS_LIB_QUICK_PRINT);
    }

  if (!strcmp (_docsis_snmp_label, "String"))	/* Strings need special treatment - see below  */
    {
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
				 NETSNMP_DS_LIB_QUICK_PRINT);
      netsnmp_ds_toggle_boolean (NETSNMP_DS_LIBRARY_ID,
				 NETSNMP_DS_LIB_ESCAPE_QUOTES);
    }

  switch ((short) vp->type)
    {
    case ASN_OCTET_STR:
	if (str_isprint((char *) vp->val.string, vp->val_len))
		{
		 	snprintf(outbuf, vp->val_len+5, "\"%s\"", vp->val.string);
		} else {
			snprint_hexadecimal (outbuf, 16383, (char *) vp->val.string, vp->val_len);
      			memset (_docsis_snmp_label, 0, 50);
      			sprintf (_docsis_snmp_label, "HexString");
		}
	break;

    case ASN_BIT_STR:
		snprint_hexadecimal (outbuf, 1023, (char *) vp->val.bitstring, vp->val_len);
		break;
    case ASN_OBJECT_ID:
      		netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID,
			  	NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
			  	NETSNMP_OID_OUTPUT_NUMERIC);
		snprint_value (outbuf, 1023, vp->name, vp->name_length, vp);
      		netsnmp_ds_set_int (NETSNMP_DS_LIBRARY_ID,
				NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
				NETSNMP_OID_OUTPUT_SUFFIX);
		break;

    default:
	snprint_value (outbuf, 1023, vp->name, vp->name_length, vp);

    }

    if ( subtree )
    {
   	enums = subtree->enums;
	   	for (; enums; enums = enums->next) {
			if (enums->value == *vp->val.integer) {
			enum_string = enums->label;
       			break;
			}
		}
    }
  if (enum_string)
	printf(" %s %s; /* %s */", _docsis_snmp_label, outbuf, enum_string);
  else
	printf(" %s %s;", _docsis_snmp_label, outbuf);


  snmp_free_var (vp);

  return badtype;
}
Exemplo n.º 17
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;
}
Exemplo n.º 18
0
int
ksm_process_in_msg(struct snmp_secmod_incoming_params *parms)
{
    long            temp;
    krb5_cksumtype  cksumtype;
    krb5_auth_context auth_context = NULL;
    krb5_error_code retcode;
    krb5_checksum   checksum;
    krb5_data       ap_req, ivector;
    krb5_flags      flags;
    krb5_keyblock  *subkey = NULL;
#ifdef MIT_NEW_CRYPTO
    krb5_data       input, output;
    krb5_boolean    valid;
    krb5_enc_data   in_crypt;
#else                           /* MIT_NEW_CRYPTO */
    krb5_encrypt_block eblock;
#endif                          /* MIT_NEW_CRYPTO */
    krb5_ticket    *ticket = NULL;
    int             retval = SNMPERR_SUCCESS, response = 0;
    size_t          length =
        parms->wholeMsgLen - (u_int) (parms->secParams - parms->wholeMsg);
    u_char         *current = parms->secParams, type;
    size_t          cksumlength, blocksize;
    long            hint;
    char           *cname;
    struct ksm_secStateRef *ksm_state;
    struct ksm_cache_entry *entry;

    DEBUGMSGTL(("ksm", "Processing has begun\n"));

    checksum.contents = NULL;
    ap_req.data = NULL;
    ivector.length = 0;
    ivector.data = NULL;

    /*
     * First, parse the security parameters (because we need the subkey inside
     * of the ticket to do anything
     */

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR),
                                      "ksm first octet")) == NULL) {
        DEBUGMSGTL(("ksm", "Initial security paramter parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_SEQUENCE | ASN_CONSTRUCTOR),
                                      "ksm sequence")) == NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter sequence parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    if ((current = asn_parse_int(current, &length, &type, &temp,
                                 sizeof(temp))) == NULL) {
        DEBUGMSGTL(("ksm", "Security parameter checksum type parsing"
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    cksumtype = temp;

#ifdef MIT_NEW_CRYPTO
    if (!krb5_c_valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!krb5_c_is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!krb5_c_is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#else /* ! MIT_NEW_CRYPTO */
    if (!valid_cksumtype(cksumtype)) {
        DEBUGMSGTL(("ksm", "Invalid checksum type (%d)\n", cksumtype));

        retval = SNMPERR_KRB5;
        snmp_set_detail("Invalid checksum type");
        goto error;
    }

    if (!is_keyed_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n",
                    cksumtype));
        snmp_set_detail("Checksum is not a keyed checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }

    if (!is_coll_proof_cksum(cksumtype)) {
        DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof "
                    "checksum\n", cksumtype));
        snmp_set_detail("Checksum is not a collision-proof checksum");
        retval = SNMPERR_KRB5;
        goto error;
    }
#endif /* MIT_NEW_CRYPTO */

    checksum.checksum_type = cksumtype;

    cksumlength = length;

    if ((current = asn_parse_sequence(current, &cksumlength, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm checksum")) ==
        NULL) {
        DEBUGMSGTL(("ksm",
                    "Security parameter checksum parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    checksum.contents = malloc(cksumlength);
    if (!checksum.contents) {
        DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum.\n",
                    cksumlength));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(checksum.contents, current, cksumlength);

    checksum.length = cksumlength;
    checksum.checksum_type = cksumtype;

    /*
     * Zero out the checksum so the validation works correctly
     */

    memset(current, 0, cksumlength);

    current += cksumlength;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_sequence(current, &length, &type,
                                      (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                       ASN_OCTET_STR), "ksm ap_req")) ==
        NULL) {
        DEBUGMSGTL(("ksm", "KSM security parameter AP_REQ/REP parsing "
                    "failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    ap_req.length = length;
    ap_req.data = malloc(length);
    if (!ap_req.data) {
        DEBUGMSGTL(("ksm",
                    "KSM unable to malloc %d bytes for AP_REQ/REP.\n",
                    length));
        retval = SNMPERR_MALLOC;
        goto error;
    }

    memcpy(ap_req.data, current, length);

    current += length;
    length = parms->wholeMsgLen - (u_int) (current - parms->wholeMsg);

    if ((current = asn_parse_int(current, &length, &type, &hint,
                                 sizeof(hint))) == NULL) {
        DEBUGMSGTL(("ksm",
                    "KSM security parameter hint parsing failed\n"));

        retval = SNMPERR_ASN_PARSE_ERR;
        goto error;
    }

    /*
     * Okay!  We've got it all!  Now try decoding the damn ticket.
     *
     * But of course there's a WRINKLE!  We need to figure out if we're
     * processing a AP_REQ or an AP_REP.  How do we do that?  We're going
     * to cheat, and look at the first couple of bytes (which is what
     * the Kerberos library routines do anyway).
     *
     * If there are ever new Kerberos message formats, we'll need to fix
     * this here.
     *
     * If it's a _response_, then we need to get the auth_context
     * from our cache.
     */

    if (ap_req.length
        && (ap_req.data[0] == 0x6e || ap_req.data[0] == 0x4e)) {

        /*
         * We need to initalize the authorization context, and set the
         * replay cache in it (and initialize the replay cache if we
         * haven't already
         */

        retcode = krb5_auth_con_init(kcontext, &auth_context);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_init failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        if (!rcache) {
            krb5_data       server;
            server.data = "host";
            server.length = strlen(server.data);

            retcode = krb5_get_server_rcache(kcontext, &server, &rcache);

            if (retcode) {
                DEBUGMSGTL(("ksm", "krb5_get_server_rcache failed: %s\n",
                            error_message(retcode)));
                retval = SNMPERR_KRB5;
                snmp_set_detail(error_message(retcode));
                goto error;
            }
        }

        retcode = krb5_auth_con_setrcache(kcontext, auth_context, rcache);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_auth_con_setrcache failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode = krb5_rd_req(kcontext, &auth_context, &ap_req, NULL,
                              keytab, &flags, &ticket);

        krb5_auth_con_setrcache(kcontext, auth_context, NULL);

        if (retcode) {
            DEBUGMSGTL(("ksm", "krb5_rd_req() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

        retcode =
            krb5_unparse_name(kcontext, ticket->enc_part2->client, &cname);

        if (retcode == 0) {
            DEBUGMSGTL(("ksm", "KSM authenticated principal name: %s\n",
                        cname));
            free(cname);
        }

        /*
         * Check to make sure AP_OPTS_MUTUAL_REQUIRED was set
         */

        if (!(flags & AP_OPTS_MUTUAL_REQUIRED)) {
            DEBUGMSGTL(("ksm",
                        "KSM MUTUAL_REQUIRED not set in request!\n"));
            retval = SNMPERR_KRB5;
            snmp_set_detail("MUTUAL_REQUIRED not set in message");
            goto error;
        }

        retcode =
            krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM remote subkey retrieval failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail(error_message(retcode));
            goto error;
        }

    } else if (ap_req.length && (ap_req.data[0] == 0x6f ||
                                 ap_req.data[0] == 0x4f)) {
        /*
         * Looks like a response; let's see if we've got that auth_context
         * in our cache.
         */

        krb5_ap_rep_enc_part *repl = NULL;

        response = 1;

        entry = ksm_get_cache(parms->pdu->msgid);

        if (!entry) {
            DEBUGMSGTL(("ksm",
                        "KSM: Unable to find auth_context for PDU with "
                        "message ID of %ld\n", parms->pdu->msgid));
            retval = SNMPERR_KRB5;
            goto error;
        }

        auth_context = entry->auth_context;

        /*
         * In that case, let's call the rd_rep function
         */

        retcode = krb5_rd_rep(kcontext, auth_context, &ap_req, &repl);

        if (repl)
            krb5_free_ap_rep_enc_part(kcontext, repl);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() failed: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            goto error;
        }

        DEBUGMSGTL(("ksm", "KSM: krb5_rd_rep() decoded successfully.\n"));

        retcode =
            krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "Unable to retrieve local subkey: %s\n",
                        error_message(retcode)));
            retval = SNMPERR_KRB5;
            snmp_set_detail("Unable to retrieve local subkey");
            goto error;
        }

    } else {
        DEBUGMSGTL(("ksm", "Unknown Kerberos message type (%02x)\n",
                    ap_req.data[0]));
        retval = SNMPERR_KRB5;
        snmp_set_detail("Unknown Kerberos message type");
        goto error;
    }

#ifdef MIT_NEW_CRYPTO
    input.data = (char *) parms->wholeMsg;
    input.length = parms->wholeMsgLen;

    retcode =
        krb5_c_verify_checksum(kcontext, subkey, KSM_KEY_USAGE_CHECKSUM,
                               &input, &checksum, &valid);
#else                           /* MIT_NEW_CRYPTO */
    retcode = krb5_verify_checksum(kcontext, cksumtype, &checksum,
                                   parms->wholeMsg, parms->wholeMsgLen,
                                   (krb5_pointer) subkey->contents,
                                   subkey->length);
#endif                          /* MIT_NEW_CRYPTO */

    if (retcode) {
        DEBUGMSGTL(("ksm", "KSM checksum verification failed: %s\n",
                    error_message(retcode)));
        retval = SNMPERR_KRB5;
        snmp_set_detail(error_message(retcode));
        goto error;
    }

    /*
     * Don't ask me why they didn't simply return an error, but we have
     * to check to see if "valid" is false.
     */

#ifdef MIT_NEW_CRYPTO
    if (!valid) {
        DEBUGMSGTL(("ksm", "Computed checksum did not match supplied "
                    "checksum!\n"));
        retval = SNMPERR_KRB5;
        snmp_set_detail
            ("Computed checksum did not match supplied checksum");
        goto error;
    }
#endif                          /* MIT_NEW_CRYPTO */

    /*
     * Handle an encrypted PDU.  Note that it's an OCTET_STRING of the
     * output of whatever Kerberos cryptosystem you're using (defined by
     * the encryption type).  Note that this is NOT the EncryptedData
     * sequence - it's what goes in the "cipher" field of EncryptedData.
     */

    if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

        if ((current = asn_parse_sequence(current, &length, &type,
                                          (ASN_UNIVERSAL | ASN_PRIMITIVE |
                                           ASN_OCTET_STR), "ksm pdu")) ==
            NULL) {
            DEBUGMSGTL(("ksm", "KSM sPDU octet decoding failed\n"));
            retval = SNMPERR_ASN_PARSE_ERR;
            goto error;
        }

        /*
         * The PDU is now pointed at by "current", and the length is in
         * "length".
         */

        DEBUGMSGTL(("ksm", "KSM starting sPDU decode\n"));

        /*
         * We need to set up a blank initialization vector for the decryption.
         * Use a block of all zero's (which is dependent on the block size
         * of the encryption method).
         */

#ifdef MIT_NEW_CRYPTO

        retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize);

        if (retcode) {
            DEBUGMSGTL(("ksm",
                        "Unable to determine crypto block size: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#else                           /* MIT_NEW_CRYPTO */

        blocksize =
            krb5_enctype_array[subkey->enctype]->system->block_length;

#endif                          /* MIT_NEW_CRYPTO */

        ivector.data = malloc(blocksize);

        if (!ivector.data) {
            DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n",
                        blocksize));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ivector.length = blocksize;
        memset(ivector.data, 0, blocksize);

#ifndef MIT_NEW_CRYPTO

        krb5_use_enctype(kcontext, &eblock, subkey->enctype);

        retcode = krb5_process_key(kcontext, &eblock, subkey);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM key post-processing failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }
#endif                          /* !MIT_NEW_CRYPTO */

        if (length > *parms->scopedPduLen) {
            DEBUGMSGTL(("ksm", "KSM not enough room - have %d bytes to "
                        "decrypt but only %d bytes available\n", length,
                        *parms->scopedPduLen));
            retval = SNMPERR_TOO_LONG;
#ifndef MIT_NEW_CRYPTO
            krb5_finish_key(kcontext, &eblock);
#endif                          /* ! MIT_NEW_CRYPTO */
            goto error;
        }
#ifdef MIT_NEW_CRYPTO
        in_crypt.ciphertext.data = (char *) current;
        in_crypt.ciphertext.length = length;
        in_crypt.enctype = subkey->enctype;
        output.data = (char *) *parms->scopedPdu;
        output.length = *parms->scopedPduLen;

        retcode =
            krb5_c_decrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION,
                           &ivector, &in_crypt, &output);
#else                           /* MIT_NEW_CRYPTO */

        retcode = krb5_decrypt(kcontext, (krb5_pointer) current,
                               *parms->scopedPdu, length, &eblock,
                               ivector.data);

        krb5_finish_key(kcontext, &eblock);

#endif                          /* MIT_NEW_CRYPTO */

        if (retcode) {
            DEBUGMSGTL(("ksm", "Decryption failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        *parms->scopedPduLen = length;

    } else {
        /*
         * Clear PDU
         */

        *parms->scopedPdu = current;
        *parms->scopedPduLen =
            parms->wholeMsgLen - (current - parms->wholeMsg);
    }

    /*
     * A HUGE GROSS HACK
     */

    *parms->maxSizeResponse = parms->maxMsgSize - 200;

    DEBUGMSGTL(("ksm", "KSM processing complete\n"));

    /*
     * Set the secName to the right value (a hack for now).  But that's
     * only used for when we're processing a request, not a response.
     */

    if (!response) {

        retcode = krb5_unparse_name(kcontext, ticket->enc_part2->client,
                                    &cname);

        if (retcode) {
            DEBUGMSGTL(("ksm", "KSM krb5_unparse_name failed: %s\n",
                        error_message(retcode)));
            snmp_set_detail(error_message(retcode));
            retval = SNMPERR_KRB5;
            goto error;
        }

        if (strlen(cname) > *parms->secNameLen + 1) {
            DEBUGMSGTL(("ksm",
                        "KSM: Principal length (%d) is too long (%d)\n",
                        strlen(cname), parms->secNameLen));
            retval = SNMPERR_TOO_LONG;
            free(cname);
            goto error;
        }

        strcpy(parms->secName, cname);
        *parms->secNameLen = strlen(cname);

        free(cname);

        /*
         * Also, if we're not a response, keep around our auth_context so we
         * can encode the reply message correctly
         */

        ksm_state = SNMP_MALLOC_STRUCT(ksm_secStateRef);

        if (!ksm_state) {
            DEBUGMSGTL(("ksm", "KSM unable to malloc memory for "
                        "ksm_secStateRef\n"));
            retval = SNMPERR_MALLOC;
            goto error;
        }

        ksm_state->auth_context = auth_context;
        auth_context = NULL;
        ksm_state->cksumtype = cksumtype;

        *parms->secStateRef = ksm_state;
    } else {

        /*
         * We _still_ have to set the secName in process_in_msg().  Do
         * that now with what we were passed in before (we cached it,
         * remember?)
         */

        memcpy(parms->secName, entry->secName, entry->secNameLen);
        *parms->secNameLen = entry->secNameLen;
    }

    /*
     * Just in case
     */

    parms->secEngineID = (u_char *) "";
    *parms->secEngineIDLen = 0;

    auth_context = NULL;        /* So we don't try to free it on success */

  error:
    if (retval == SNMPERR_ASN_PARSE_ERR &&
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS) == 0)
        DEBUGMSGTL(("ksm", "Failed to increment statistics.\n"));

    if (subkey)
        krb5_free_keyblock(kcontext, subkey);

    if (checksum.contents)
        free(checksum.contents);

    if (ivector.data)
        free(ivector.data);

    if (ticket)
        krb5_free_ticket(kcontext, ticket);

    if (!response && auth_context)
        krb5_auth_con_free(kcontext, auth_context);

    if (ap_req.data)
        free(ap_req.data);

    return retval;
}
Exemplo n.º 19
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);
}