You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
665 lines
19 KiB
665 lines
19 KiB
//***************************************************************************
|
|
|
|
//
|
|
|
|
// File:
|
|
|
|
//
|
|
|
|
// Module: MS SNMP Provider
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
//***************************************************************************
|
|
|
|
/*---------------------------------------------------------
|
|
Filename: ophelp.cpp
|
|
Written By: B.Rajeev
|
|
----------------------------------------------------------*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
#include "value.h"
|
|
#include "encdec.h"
|
|
#include "vblist.h"
|
|
#include "sec.h"
|
|
#include "pdu.h"
|
|
#include "vbl.h"
|
|
#include "fs_reg.h"
|
|
#include "pseudo.h"
|
|
#include "encap.h"
|
|
#include "error.h"
|
|
#include "ophelp.h"
|
|
|
|
#include "dummy.h"
|
|
#include "flow.h"
|
|
#include "frame.h"
|
|
#include "timer.h"
|
|
#include "message.h"
|
|
#include "ssent.h"
|
|
#include "idmap.h"
|
|
#include "opreg.h"
|
|
|
|
#include "session.h"
|
|
#include "op.h"
|
|
#include <winsock.h>
|
|
|
|
// returns an SnmpTransportAddress created using the HSNMP_ENTITY
|
|
// this method returns the first transport address it can create
|
|
// using the string form of the HSNMP_ENTITY supplied
|
|
SnmpTransportAddress *OperationHelper::GetTransportAddress(IN HSNMP_ENTITY &haddr)
|
|
{
|
|
char buff[MAX_ADDRESS_LEN];
|
|
SNMPAPI_STATUS status = SnmpEntityToStr(haddr, MAX_ADDRESS_LEN, (LPSTR)buff);
|
|
|
|
if (SNMPAPI_FAILURE == status)
|
|
{
|
|
return (SnmpTransportAddress *)NULL;
|
|
}
|
|
|
|
//first try ip...
|
|
SnmpTransportIpAddress *retip = new SnmpTransportIpAddress(buff, SNMP_ADDRESS_RESOLVE_VALUE);
|
|
|
|
if (retip->IsValid())
|
|
{
|
|
return (SnmpTransportAddress *)retip;
|
|
}
|
|
|
|
delete retip;
|
|
|
|
//next try ipx...
|
|
SnmpTransportIpxAddress *retipx = new SnmpTransportIpxAddress(buff);
|
|
|
|
if (retipx->IsValid())
|
|
{
|
|
return (SnmpTransportAddress *)retipx;
|
|
}
|
|
|
|
delete retipx;
|
|
|
|
//nothing worked...
|
|
return (SnmpTransportAddress *)NULL;
|
|
}
|
|
|
|
// returns an SnmpSecurity created using the HSNMP_CONTEXT
|
|
// this method returns the first security context it can create
|
|
// using the string form of the HSNMP_CONTEXT supplied
|
|
SnmpSecurity *OperationHelper::GetSecurityContext(IN HSNMP_CONTEXT &hctxt)
|
|
{
|
|
smiOCTETS buff;
|
|
SNMPAPI_STATUS status = SnmpContextToStr(hctxt, &buff);
|
|
|
|
if (SNMPAPI_FAILURE == status)
|
|
{
|
|
return (SnmpSecurity *)NULL;
|
|
}
|
|
|
|
SnmpOctetString octstr( (UCHAR *)(buff.ptr), (ULONG)(buff.len) );
|
|
SnmpCommunityBasedSecurity* retval = new SnmpCommunityBasedSecurity(octstr);
|
|
SnmpFreeDescriptor (SNMP_SYNTAX_OCTETS, &buff);
|
|
|
|
if (NULL != (*retval)())
|
|
{
|
|
return (SnmpSecurity *)retval;
|
|
}
|
|
|
|
delete retval;
|
|
return (SnmpSecurity *)NULL;
|
|
}
|
|
|
|
// returns an SnmpVarBind containing an SnmpObjectIdentifier and an
|
|
// SnmpValue created using the instance(OID) and the value(VALUE)
|
|
SnmpVarBind *OperationHelper::GetVarBind(IN smiOID &instance,
|
|
IN smiVALUE &value)
|
|
{
|
|
SnmpVarBind *var_bind = NULL ;
|
|
|
|
// create an SnmpObjectIdentifier using the instance value
|
|
SnmpObjectIdentifier id(instance.ptr, instance.len);
|
|
|
|
// for each possible value for value.syntax, create the
|
|
// corresponding SnmpValue
|
|
|
|
switch(value.syntax)
|
|
{
|
|
case SNMP_SYNTAX_NULL: // null value
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpNull () );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_INT: // integer *(has same value as SNMP_SYNTAX_INT32)*
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpInteger(value.value.sNumber) ) ;
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_UINT32: // integer *(has same value as SNMP_SYNTAX_GAUGE)*
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpUInteger32(value.value.uNumber) ) ;
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_CNTR32: // counter32
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpCounter (value.value.uNumber) ) ;
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_GAUGE32: // gauge
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpGauge(value.value.uNumber) );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_TIMETICKS: // time ticks
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpTimeTicks(value.value.uNumber) );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OCTETS: // octets
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpOctetString(value.value.string.ptr,
|
|
value.value.string.len) ) ;
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OPAQUE: // opaque value
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpOpaque(value.value.string.ptr,
|
|
value.value.string.len) );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OID: // object identifier
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpObjectIdentifier(value.value.oid.ptr,
|
|
value.value.oid.len) );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_IPADDR: // ip address value
|
|
{
|
|
if ( value.value.string.ptr )
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpIpAddress(ntohl(*((ULONG *)value.value.string.ptr))) );
|
|
}
|
|
else
|
|
{
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"OperationHelper::DecodeVarBind: Invalid encoding\n"
|
|
) ;
|
|
)
|
|
var_bind = NULL ;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_CNTR64: // counter64
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpCounter64 (value.value.hNumber.lopart , value.value.hNumber.hipart ) );
|
|
}
|
|
break;
|
|
|
|
case SNMP_SYNTAX_NOSUCHOBJECT:
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpNoSuchObject () ) ;
|
|
}
|
|
break ;
|
|
|
|
case SNMP_SYNTAX_NOSUCHINSTANCE:
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpNoSuchInstance () ) ;
|
|
}
|
|
break ;
|
|
|
|
case SNMP_SYNTAX_ENDOFMIBVIEW:
|
|
{
|
|
var_bind = new SnmpVarBind(id, SnmpEndOfMibView () ) ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
{
|
|
// it must be an unsupported type
|
|
// return an SnmpNullValue by default
|
|
var_bind = new SnmpVarBind(id, SnmpNull() );
|
|
|
|
}
|
|
break;
|
|
};
|
|
|
|
return var_bind;
|
|
}
|
|
|
|
|
|
void OperationHelper::TransmitFrame (
|
|
|
|
OUT SessionFrameId &session_frame_id,
|
|
VBList &vbl)
|
|
{
|
|
SnmpSecurity *security = operation.frame_state_registry.GetSecurity();
|
|
|
|
// encode a frame
|
|
SnmpPdu *t_SnmpPdu = new SnmpPdu ;
|
|
SnmpErrorReport t_SnmpErrorReport ;
|
|
SnmpTransportAddress *t_SrcTransportAddress = NULL ;
|
|
SnmpTransportAddress *t_DstTransportAddress = NULL ;
|
|
SnmpCommunityBasedSecurity *t_SnmpcommunityBasedSecurity = NULL ;
|
|
|
|
try
|
|
{
|
|
operation.session.GetSnmpEncodeDecode ().EncodeFrame (
|
|
|
|
*t_SnmpPdu ,
|
|
session_frame_id ,
|
|
operation.GetPduType () ,
|
|
t_SnmpErrorReport ,
|
|
vbl.GetVarBindList () ,
|
|
t_SnmpcommunityBasedSecurity ,
|
|
t_SrcTransportAddress ,
|
|
t_DstTransportAddress
|
|
);
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
delete t_SnmpPdu ;
|
|
|
|
operation.m_OperationWindow.PostMessage (
|
|
|
|
Window :: g_SendErrorEvent ,
|
|
(WPARAM)&vbl,
|
|
(LPARAM)(new GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__))
|
|
);
|
|
|
|
return ;
|
|
}
|
|
catch ( GeneralException exception )
|
|
{
|
|
delete t_SnmpPdu ;
|
|
|
|
operation.m_OperationWindow.PostMessage (
|
|
|
|
Window :: g_SendErrorEvent ,
|
|
(WPARAM)&vbl,
|
|
(LPARAM)(new GeneralException(exception))
|
|
);
|
|
|
|
return ;
|
|
}
|
|
|
|
if ( security != NULL )
|
|
{
|
|
operation.session.SessionSendFrame (
|
|
|
|
operation,
|
|
session_frame_id,
|
|
*t_SnmpPdu,
|
|
*security
|
|
);
|
|
}
|
|
else
|
|
{
|
|
operation.session.SessionSendFrame (
|
|
|
|
operation,
|
|
session_frame_id,
|
|
*t_SnmpPdu
|
|
);
|
|
}
|
|
}
|
|
|
|
void OperationHelper::ReceiveResponse (
|
|
|
|
ULONG var_index ,
|
|
SnmpVarBindList &sent_var_bind_list,
|
|
SnmpVarBindList &received_var_bind_list,
|
|
SnmpErrorReport &error_report
|
|
)
|
|
{
|
|
|
|
// check if the var bind list has the same length
|
|
|
|
if ( sent_var_bind_list.GetLength() != received_var_bind_list.GetLength () )
|
|
{
|
|
operation.is_valid = FALSE;
|
|
return;
|
|
}
|
|
|
|
sent_var_bind_list.Reset();
|
|
received_var_bind_list.Reset();
|
|
|
|
ULONG t_Index = 0 ;
|
|
while( sent_var_bind_list.Next() && received_var_bind_list.Next() )
|
|
{
|
|
const SnmpVarBind *sent_var_bind = sent_var_bind_list.Get();
|
|
const SnmpVarBind *received_var_bind = received_var_bind_list.Get();
|
|
|
|
operation.ReceiveVarBindResponse(
|
|
|
|
var_index + t_Index ,
|
|
*sent_var_bind,
|
|
*received_var_bind,
|
|
error_report
|
|
);
|
|
|
|
t_Index ++ ;
|
|
}
|
|
}
|
|
|
|
|
|
// processes the response (successful or otherwise) for the specified
|
|
// frame. the frame may be retransmitted in case of a reply bearing
|
|
// an errored index
|
|
void OperationHelper::ProcessResponse (
|
|
|
|
FrameState *frame_state,
|
|
SnmpVarBindList &a_SnmpVarBindList ,
|
|
SnmpErrorReport &a_SnmpErrorReport
|
|
)
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"OperationHelper::ProcessResponse: eindex(%d), error(%d), status(%d)\n",a_SnmpErrorReport.GetIndex(), a_SnmpErrorReport.GetError(), a_SnmpErrorReport.GetStatus()
|
|
) ;
|
|
)
|
|
|
|
// if there is an error in a particular var bind
|
|
if ( (a_SnmpErrorReport.GetIndex () != 0) && (a_SnmpErrorReport.GetStatus () != SNMP_ERROR_NOERROR) )
|
|
{
|
|
if ( operation.GetPduType () != SnmpEncodeDecode :: PduType :: SET )
|
|
{
|
|
// delete the corresponding var bind from the VBList
|
|
// in the frame_state and announce the receipt of
|
|
// errored var bind by making a callback
|
|
VBList *vblist = frame_state->GetVBList();
|
|
SnmpVarBind *errored_vb;
|
|
|
|
try
|
|
{
|
|
errored_vb = vblist->Get(a_SnmpErrorReport.GetIndex () );
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__)
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
exception
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
|
|
// *** (SnmpStatus) casting
|
|
SnmpErrorReport report(Snmp_Error, a_SnmpErrorReport.GetStatus () , a_SnmpErrorReport.GetIndex () );
|
|
|
|
operation.ReceiveErroredVarBindResponse(
|
|
|
|
vblist->GetIndex () + a_SnmpErrorReport.GetIndex () - 1 ,
|
|
*errored_vb,
|
|
report
|
|
);
|
|
|
|
delete errored_vb;
|
|
|
|
try
|
|
{
|
|
vblist->Remove (a_SnmpErrorReport.GetIndex () );
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__)
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
exception
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
|
|
// if the VarBindList becomes empty, corresp. frame state
|
|
// may be deleted
|
|
if ( vblist->GetVarBindList().Empty() )
|
|
delete frame_state;
|
|
else
|
|
{
|
|
// Split the frame in half
|
|
|
|
SnmpVarBindList &vbl = vblist->GetVarBindList ();
|
|
|
|
if ( a_SnmpErrorReport.GetIndex () > 1 )
|
|
{
|
|
SnmpVarBindList *t_Car = vbl.Car ( a_SnmpErrorReport.GetIndex () - 1 ) ;
|
|
VBList *t_List = new VBList (
|
|
|
|
operation.session.GetSnmpEncodeDecode () ,
|
|
*t_Car,
|
|
vblist->GetIndex ()
|
|
) ;
|
|
|
|
operation.SendFrame(*t_List) ;
|
|
}
|
|
|
|
if ( a_SnmpErrorReport.GetIndex () < vbl.GetLength () )
|
|
{
|
|
SnmpVarBindList *t_Cdr = vbl.Cdr ( a_SnmpErrorReport.GetIndex () - 1 ) ;
|
|
|
|
VBList *t_List = new VBList (
|
|
|
|
operation.session.GetSnmpEncodeDecode () ,
|
|
*t_Cdr,
|
|
vblist->GetIndex () + a_SnmpErrorReport.GetIndex ()
|
|
) ;
|
|
|
|
operation.SendFrame(*t_List) ;
|
|
}
|
|
|
|
// re-send the frame using the old frame_state
|
|
|
|
delete frame_state ;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
VBList *vblist = frame_state->GetVBList();
|
|
SnmpVarBind *errored_vb;
|
|
|
|
try
|
|
{
|
|
errored_vb = vblist->Remove(a_SnmpErrorReport.GetIndex () );
|
|
}
|
|
catch ( Heap_Exception e_He )
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__)
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
catch(GeneralException exception)
|
|
{
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
exception
|
|
);
|
|
|
|
delete &frame_state;
|
|
return;
|
|
}
|
|
|
|
// *** (SnmpStatus) casting
|
|
SnmpErrorReport report(Snmp_Error, a_SnmpErrorReport.GetStatus () , a_SnmpErrorReport.GetIndex () );
|
|
|
|
operation.ReceiveErroredVarBindResponse(
|
|
|
|
vblist->GetIndex () + a_SnmpErrorReport.GetIndex () - 1 ,
|
|
*errored_vb,
|
|
report
|
|
);
|
|
|
|
delete errored_vb;
|
|
|
|
SnmpErrorReport t_SnmpErrorReport ;
|
|
|
|
operation.ReceiveErroredResponse(
|
|
|
|
vblist->GetIndex () + a_SnmpErrorReport.GetIndex () - 1 ,
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
t_SnmpErrorReport
|
|
);
|
|
|
|
// destroy the frame_state: since the only case when the
|
|
// old frame_state is reused is when there is an error
|
|
// in a particular index and we wouldn't have come here in that case
|
|
delete frame_state;
|
|
|
|
return ;
|
|
}
|
|
}
|
|
|
|
// otherwise, check the error status
|
|
switch(a_SnmpErrorReport.GetStatus () )
|
|
{
|
|
case SNMP_ERROR_NOERROR:
|
|
{
|
|
// call ReceiveResponse for each vb
|
|
ReceiveResponse (
|
|
frame_state->GetVBList()->GetIndex (),
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
a_SnmpVarBindList ,
|
|
a_SnmpErrorReport
|
|
);
|
|
}
|
|
break;
|
|
|
|
case SNMP_ERROR_TOOBIG:
|
|
{
|
|
if ( operation.GetPduType () != SnmpEncodeDecode :: PduType :: SET )
|
|
{
|
|
// callback FrameTooBig()
|
|
operation.FrameTooBig();
|
|
|
|
// check if the callback cancelled the operation
|
|
if ( ! operation.in_progress )
|
|
return;
|
|
|
|
// obtain the list, length
|
|
SnmpVarBindList &list = frame_state->GetVBList()->GetVarBindList();
|
|
UINT length = list.GetLength();
|
|
|
|
// if the length is 1, call ReceiveErroredResponse
|
|
if ( length == 1 )
|
|
{
|
|
// *** casting Snmp_Status ***
|
|
SnmpErrorReport report(Snmp_Error, a_SnmpErrorReport.GetStatus () , a_SnmpErrorReport.GetIndex () );
|
|
|
|
operation.ReceiveErroredVarBindResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex () + a_SnmpErrorReport.GetIndex () - 1 ,
|
|
*(list[1]),
|
|
report
|
|
);
|
|
}
|
|
else // split the list midway and send both fragments
|
|
{
|
|
operation.SendVarBindList(
|
|
|
|
list,
|
|
(length/2),
|
|
frame_state->GetVBList()->GetIndex () + a_SnmpErrorReport.GetIndex () - 1
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// *** casting Snmp_Status ***
|
|
SnmpErrorReport report(Snmp_Error, a_SnmpErrorReport.GetStatus () , a_SnmpErrorReport.GetIndex ());
|
|
|
|
// for each varbind in varbindlist
|
|
// call ReceiveResponse for each vb
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex (),
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
report
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
// *** casting Snmp_Status ***
|
|
SnmpErrorReport report(Snmp_Error, a_SnmpErrorReport.GetStatus () , a_SnmpErrorReport.GetIndex ());
|
|
|
|
// for each varbind in varbindlist
|
|
// call ReceiveResponse for each vb
|
|
operation.ReceiveErroredResponse(
|
|
|
|
frame_state->GetVBList()->GetIndex (),
|
|
frame_state->GetVBList()->GetVarBindList(),
|
|
report
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
// destroy the frame_state: since the only case when the
|
|
// old frame_state is reused is when there is an error
|
|
// in a particular index and we wouldn't have come here in that case
|
|
delete frame_state;
|
|
}
|
|
|