626 lines
23 KiB
C
626 lines
23 KiB
C
/*
|
|
* snmptsmsm.c -- Implements RFC #5591
|
|
*
|
|
* This code implements a security model that assumes the local user
|
|
* that executed the agent is the user who's attributes are passed up
|
|
* by the transport underneath. The RFC describing this security
|
|
* model is RFC5591.
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#include <net-snmp/net-snmp-features.h>
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
|
|
#include <net-snmp/library/snmptsm.h>
|
|
|
|
#ifdef NETSNMP_TRANSPORT_SSH_DOMAIN
|
|
#include <net-snmp/library/snmpSSHDomain.h>
|
|
#endif
|
|
#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
|
|
#include <net-snmp/library/snmpDTLSUDPDomain.h>
|
|
#endif
|
|
#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
|
|
#include <net-snmp/library/snmpTLSTCPDomain.h>
|
|
#endif
|
|
#ifdef NETSNMP_TRANSPORT_DTLSSCTP_DOMAIN
|
|
#include <net-snmp/library/snmpDTLSSCTPDomain.h>
|
|
#endif
|
|
|
|
netsnmp_feature_require(snmpv3_probe_contextEngineID_rfc5343)
|
|
netsnmp_feature_require(row_create)
|
|
|
|
static int tsm_session_init(netsnmp_session *);
|
|
static void tsm_free_state_ref(void *);
|
|
static int tsm_clone_pdu(netsnmp_pdu *, netsnmp_pdu *);
|
|
static int tsm_free_pdu(netsnmp_pdu *pdu);
|
|
|
|
u_int next_sess_id = 1;
|
|
|
|
/** Initialize the TSM security module */
|
|
void
|
|
init_tsm(void)
|
|
{
|
|
struct snmp_secmod_def *def;
|
|
int ret;
|
|
|
|
def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
|
|
|
|
if (!def) {
|
|
snmp_log(LOG_ERR,
|
|
"Unable to malloc snmp_secmod struct, not registering TSM\n");
|
|
return;
|
|
}
|
|
|
|
def->encode_reverse = tsm_rgenerate_out_msg;
|
|
def->decode = tsm_process_in_msg;
|
|
def->session_open = tsm_session_init;
|
|
def->pdu_free_state_ref = tsm_free_state_ref;
|
|
def->pdu_clone = tsm_clone_pdu;
|
|
def->pdu_free = tsm_free_pdu;
|
|
def->probe_engineid = snmpv3_probe_contextEngineID_rfc5343;
|
|
|
|
DEBUGMSGTL(("tsm","registering ourselves\n"));
|
|
ret = register_sec_mod(SNMP_SEC_MODEL_TSM, "tsm", def);
|
|
DEBUGMSGTL(("tsm"," returned %d\n", ret));
|
|
|
|
netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "tsmUseTransportPrefix",
|
|
NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_TSM_USE_PREFIX);
|
|
}
|
|
|
|
/** shutdown the TSM security module */
|
|
void
|
|
shutdown_tsm(void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Initialize specific session information (right now, just set up things to
|
|
* not do an engineID probe)
|
|
*/
|
|
|
|
static int
|
|
tsm_session_init(netsnmp_session * sess)
|
|
{
|
|
DEBUGMSGTL(("tsm",
|
|
"TSM: Reached our session initialization callback\n"));
|
|
|
|
sess->flags |= SNMP_FLAGS_DONT_PROBE;
|
|
|
|
/* XXX: likely needed for something: */
|
|
/*
|
|
tsmsession = sess->securityInfo =
|
|
if (!tsmsession)
|
|
return SNMPERR_GENERR;
|
|
*/
|
|
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/** Free our state information (this is only done on the agent side) */
|
|
static void
|
|
tsm_free_state_ref(void *ptr)
|
|
{
|
|
netsnmp_tsmSecurityReference *tsmRef = ptr;
|
|
|
|
if (!tsmRef)
|
|
return;
|
|
|
|
/* the tmStateRef is always taken care of by the normal PDU, since this
|
|
is just a reference to that one */
|
|
/* DON'T DO: SNMP_FREE(tsmRef->tmStateRef); */
|
|
/* SNMP_FREE(tsmRef); ? */
|
|
}
|
|
|
|
static int
|
|
tsm_free_pdu(netsnmp_pdu *pdu)
|
|
{
|
|
/* free the security reference */
|
|
if (pdu->securityStateRef) {
|
|
tsm_free_state_ref(pdu->securityStateRef);
|
|
pdu->securityStateRef = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** This is called when a PDU is cloned (to increase reference counts) */
|
|
static int
|
|
tsm_clone_pdu(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
|
|
{
|
|
netsnmp_tsmSecurityReference *oldref, *newref;
|
|
|
|
oldref = pdu->securityStateRef;
|
|
if (!oldref)
|
|
return SNMPERR_SUCCESS;
|
|
|
|
newref = SNMP_MALLOC_TYPEDEF(netsnmp_tsmSecurityReference);
|
|
netsnmp_assert_or_return(NULL != newref, SNMPERR_GENERR);
|
|
DEBUGMSGTL(("tsm", "cloned as pdu=%p, ref=%p (oldref=%p)\n",
|
|
pdu2, newref, pdu2->securityStateRef));
|
|
|
|
memcpy(newref, oldref, sizeof(*oldref));
|
|
|
|
/* the tm state reference is just a link to the one in the pdu,
|
|
which was already copied by snmp_clone_pdu before handing it to
|
|
us. */
|
|
|
|
newref->tmStateRef = netsnmp_memdup(oldref->tmStateRef,
|
|
sizeof(*oldref->tmStateRef));
|
|
if (!newref->tmStateRef) {
|
|
snmp_log(LOG_ERR, "tsm: malloc failure\n");
|
|
free(newref);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
pdu2->securityStateRef = newref;
|
|
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/* asn.1 easing definitions */
|
|
#define TSMBUILD_OR_ERR(fun, args, msg, desc) \
|
|
DEBUGDUMPHEADER("send", desc); \
|
|
rc = fun args; \
|
|
DEBUGINDENTLESS(); \
|
|
if (rc == 0) { \
|
|
DEBUGMSGTL(("tsm",msg)); \
|
|
retval = SNMPERR_TOO_LONG; \
|
|
goto outerr; \
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* tsm_generate_out_msg
|
|
*
|
|
* Parameters:
|
|
* (See list below...)
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS On success.
|
|
* ... and others
|
|
*
|
|
*
|
|
* Generate an outgoing message.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int
|
|
tsm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
|
|
{
|
|
u_char **wholeMsg = parms->wholeMsg;
|
|
size_t *offset = parms->wholeMsgOffset;
|
|
int rc;
|
|
|
|
size_t *wholeMsgLen = parms->wholeMsgLen;
|
|
netsnmp_tsmSecurityReference *tsmSecRef;
|
|
netsnmp_tmStateReference *tmStateRef;
|
|
int tmStateRefLocal = 0;
|
|
|
|
DEBUGMSGTL(("tsm", "Starting TSM processing\n"));
|
|
|
|
/* if we have this, then this message to be sent is in response to
|
|
something that came in earlier and the tsmSecRef was created by
|
|
the tsm_process_in_msg. */
|
|
tsmSecRef = parms->secStateRef;
|
|
|
|
if (tsmSecRef) {
|
|
/* 4.2, step 1: If there is a securityStateReference (Response
|
|
or Report message), then this Security Model uses the
|
|
cached information rather than the information provided by
|
|
the ASI. */
|
|
|
|
/* 4.2, step 1: Extract the tmStateReference from the
|
|
securityStateReference cache. */
|
|
netsnmp_assert_or_return(NULL != tsmSecRef->tmStateRef, SNMPERR_GENERR);
|
|
tmStateRef = tsmSecRef->tmStateRef;
|
|
|
|
/* 4.2 step 1: Set the tmRequestedSecurityLevel to the value
|
|
of the extracted tmTransportSecurityLevel. */
|
|
tmStateRef->requestedSecurityLevel = tmStateRef->transportSecurityLevel;
|
|
|
|
/* 4.2 step 1: Set the tmSameSecurity parameter in the
|
|
tmStateReference cache to true. */
|
|
tmStateRef->sameSecurity = NETSNMP_TM_USE_SAME_SECURITY;
|
|
|
|
/* 4.2 step 1: The cachedSecurityData for this message can
|
|
now be discarded. */
|
|
SNMP_FREE(parms->secStateRef);
|
|
} else {
|
|
/* 4.2, step 2: If there is no securityStateReference (e.g., a
|
|
Request-type or Notification message), then create a
|
|
tmStateReference cache. */
|
|
tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference);
|
|
netsnmp_assert_or_return(NULL != tmStateRef, SNMPERR_GENERR);
|
|
tmStateRefLocal = 1;
|
|
|
|
/* XXX: we don't actually use this really in our implementation */
|
|
/* 4.2, step 2: Set tmTransportDomain to the value of
|
|
transportDomain, tmTransportAddress to the value of
|
|
transportAddress */
|
|
|
|
/* 4.2, step 2: and tmRequestedSecurityLevel to the value of
|
|
securityLevel. */
|
|
tmStateRef->requestedSecurityLevel = parms->secLevel;
|
|
|
|
/* 4.2, step 2: Set the transaction-specific tmSameSecurity
|
|
parameter to false. */
|
|
tmStateRef->sameSecurity = NETSNMP_TM_SAME_SECURITY_NOT_REQUIRED;
|
|
|
|
if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_TSM_USE_PREFIX)) {
|
|
/* XXX: probably shouldn't be a hard-coded list of
|
|
supported transports */
|
|
/* 4.2, step 2: If the snmpTsmConfigurationUsePrefix
|
|
object is set to true, then use the transportDomain to
|
|
look up the corresponding prefix. */
|
|
const char *prefix;
|
|
if (strncmp("ssh:",parms->session->peername,4) == 0)
|
|
prefix = "ssh:";
|
|
else if (strncmp("dtls:",parms->session->peername,5) == 0)
|
|
prefix = "dtls:";
|
|
else if (strncmp("tls:",parms->session->peername,4) == 0)
|
|
prefix = "tls:";
|
|
else {
|
|
/* 4.2, step 2: If the prefix lookup fails for any
|
|
reason, then the snmpTsmUnknownPrefixes counter is
|
|
incremented, an error indication is returned to the
|
|
calling module, and message processing stops. */
|
|
snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
|
|
SNMP_FREE(tmStateRef);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/* 4.2, step 2: If the lookup succeeds, but there is no
|
|
prefix in the securityName, or the prefix returned does
|
|
not match the prefix in the securityName, or the length
|
|
of the prefix is less than 1 or greater than 4 US-ASCII
|
|
alpha-numeric characters, then the
|
|
snmpTsmInvalidPrefixes counter is incremented, an error
|
|
indication is returned to the calling module, and
|
|
message processing stops. */
|
|
if (strchr(parms->secName, ':') == 0 ||
|
|
strlen(prefix)+1 >= parms->secNameLen ||
|
|
strncmp(parms->secName, prefix, strlen(prefix)) != 0 ||
|
|
parms->secName[strlen(prefix)] != ':') {
|
|
/* Note: since we're assiging the prefixes above the
|
|
prefix lengths always meet the 1-4 criteria */
|
|
snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDPREFIXES);
|
|
SNMP_FREE(tmStateRef);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/* 4.2, step 2: Strip the transport-specific prefix and
|
|
trailing ':' character (US-ASCII 0x3a) from the
|
|
securityName. Set tmSecurityName to the value of
|
|
securityName. */
|
|
memcpy(tmStateRef->securityName,
|
|
parms->secName + strlen(prefix) + 1,
|
|
parms->secNameLen - strlen(prefix) - 1);
|
|
tmStateRef->securityNameLen = parms->secNameLen - strlen(prefix) -1;
|
|
} else {
|
|
/* 4.2, step 2: If the snmpTsmConfigurationUsePrefix object is
|
|
set to false, then set tmSecurityName to the value
|
|
of securityName. */
|
|
memcpy(tmStateRef->securityName, parms->secName,
|
|
parms->secNameLen);
|
|
tmStateRef->securityNameLen = parms->secNameLen;
|
|
}
|
|
}
|
|
|
|
/* truncate the security name with a '\0' for safety */
|
|
tmStateRef->securityName[tmStateRef->securityNameLen] = '\0';
|
|
|
|
/* 4.2, step 3: Set securityParameters to a zero-length OCTET
|
|
* STRING ('0400').
|
|
*/
|
|
DEBUGDUMPHEADER("send", "tsm security parameters");
|
|
rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
|
|
(u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
|
|
| ASN_OCTET_STR), 0);
|
|
DEBUGINDENTLESS();
|
|
if (rc == 0) {
|
|
DEBUGMSGTL(("tsm", "building msgSecurityParameters failed.\n"));
|
|
if (tmStateRefLocal)
|
|
SNMP_FREE(tmStateRef);
|
|
return SNMPERR_TOO_LONG;
|
|
}
|
|
|
|
/* 4.2, step 4: Combine the message parts into a wholeMsg and
|
|
calculate wholeMsgLength.
|
|
*/
|
|
while ((*wholeMsgLen - *offset) < parms->globalDataLen) {
|
|
if (!asn_realloc(wholeMsg, wholeMsgLen)) {
|
|
DEBUGMSGTL(("tsm", "building global data failed.\n"));
|
|
if (tmStateRefLocal)
|
|
SNMP_FREE(tmStateRef);
|
|
return SNMPERR_TOO_LONG;
|
|
}
|
|
}
|
|
|
|
*offset += parms->globalDataLen;
|
|
memcpy(*wholeMsg + *wholeMsgLen - *offset,
|
|
parms->globalData, parms->globalDataLen);
|
|
|
|
/* 4.2, step 5: The wholeMsg, wholeMsgLength, securityParameters,
|
|
and tmStateReference are returned to the calling Message
|
|
Processing Model with the statusInformation set to success. */
|
|
|
|
/* For the Net-SNMP implemantion that actually means we start
|
|
encoding the full packet sequence from here before returning it */
|
|
|
|
/*
|
|
* Total packet sequence.
|
|
*/
|
|
rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
|
|
(u_char) (ASN_SEQUENCE |
|
|
ASN_CONSTRUCTOR), *offset);
|
|
if (rc == 0) {
|
|
DEBUGMSGTL(("tsm", "building master packet sequence failed.\n"));
|
|
if (tmStateRefLocal)
|
|
SNMP_FREE(tmStateRef);
|
|
return SNMPERR_TOO_LONG;
|
|
}
|
|
|
|
if (parms->pdu->transport_data &&
|
|
parms->pdu->transport_data != tmStateRef) {
|
|
snmp_log(LOG_ERR, "tsm: needed to free transport data\n");
|
|
SNMP_FREE(parms->pdu->transport_data);
|
|
}
|
|
|
|
/* put the transport state reference into the PDU for the transport */
|
|
parms->pdu->transport_data = netsnmp_memdup(tmStateRef, sizeof(*tmStateRef));
|
|
if (tmStateRefLocal)
|
|
SNMP_FREE(tmStateRef);
|
|
|
|
if (!parms->pdu->transport_data) {
|
|
snmp_log(LOG_ERR, "tsm: malloc failure\n");
|
|
return SNMPERR_GENERR;
|
|
}
|
|
parms->pdu->transport_data_length = sizeof(*tmStateRef);
|
|
|
|
DEBUGMSGTL(("tsm", "TSM processing completed.\n"));
|
|
return SNMPERR_SUCCESS;
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* tsm_process_in_msg
|
|
*
|
|
* Parameters:
|
|
* (See list below...)
|
|
*
|
|
* Returns:
|
|
* TSM_ERR_NO_ERROR On success.
|
|
* TSM_ERR_GENERIC_ERROR
|
|
* TSM_ERR_UNSUPPORTED_SECURITY_LEVEL
|
|
*
|
|
*
|
|
* Processes an incoming message.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int
|
|
tsm_process_in_msg(struct snmp_secmod_incoming_params *parms)
|
|
{
|
|
u_char type_value;
|
|
size_t remaining;
|
|
u_char *data_ptr;
|
|
netsnmp_tmStateReference *tmStateRef;
|
|
netsnmp_tsmSecurityReference *tsmSecRef;
|
|
u_char ourEngineID[SNMP_MAX_ENG_SIZE];
|
|
static size_t ourEngineID_len = sizeof(ourEngineID);
|
|
|
|
/* Section 5.2, step 1: Set the securityEngineID to the local
|
|
snmpEngineID. */
|
|
ourEngineID_len =
|
|
snmpv3_get_engineID((u_char*) ourEngineID, ourEngineID_len);
|
|
netsnmp_assert_or_return(ourEngineID_len != 0 &&
|
|
ourEngineID_len <= *parms->secEngineIDLen,
|
|
SNMPERR_GENERR);
|
|
memcpy(parms->secEngineID, ourEngineID, *parms->secEngineIDLen);
|
|
|
|
/* Section 5.2, step 2: If tmStateReference does not refer to a
|
|
cache containing values for tmTransportDomain,
|
|
tmTransportAddress, tmSecurityName, and
|
|
tmTransportSecurityLevel, then the snmpTsmInvalidCaches counter
|
|
is incremented, an error indication is returned to the calling
|
|
module, and Security Model processing stops for this
|
|
message. */
|
|
if (!parms->pdu->transport_data ||
|
|
sizeof(netsnmp_tmStateReference) !=
|
|
parms->pdu->transport_data_length) {
|
|
/* if we're not coming in over a proper transport; bail! */
|
|
DEBUGMSGTL(("tsm","improper transport data\n"));
|
|
return -1;
|
|
}
|
|
tmStateRef = (netsnmp_tmStateReference *) parms->pdu->transport_data;
|
|
parms->pdu->transport_data = NULL;
|
|
|
|
if (tmStateRef == NULL ||
|
|
/* not needed: tmStateRef->transportDomain == NULL || */
|
|
/* not needed: tmStateRef->transportAddress == NULL || */
|
|
tmStateRef->securityName[0] == '\0'
|
|
) {
|
|
snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDCACHES);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/* Section 5.2, step 3: Copy the tmSecurityName to securityName. */
|
|
if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
|
|
NETSNMP_DS_LIB_TSM_USE_PREFIX)) {
|
|
/* Section 5.2, step 3:
|
|
If the snmpTsmConfigurationUsePrefix object is set to true, then
|
|
use the tmTransportDomain to look up the corresponding prefix.
|
|
*/
|
|
const char *prefix = NULL;
|
|
/*
|
|
possibilities:
|
|
|--------------------+-------|
|
|
| snmpTLSTCPDomain | tls: |
|
|
| snmpDTLSUDPDomain | dtls: |
|
|
| snmpSSHDomain | ssh: |
|
|
|--------------------+-------|
|
|
*/
|
|
|
|
/* XXX: cache in session! */
|
|
#ifdef NETSNMP_TRANSPORT_SSH_DOMAIN
|
|
if (netsnmp_oid_equals(netsnmp_snmpSSHDomain,
|
|
netsnmp_snmpSSHDomain_len,
|
|
tmStateRef->transportDomain,
|
|
tmStateRef->transportDomainLen) == 0) {
|
|
prefix = "ssh";
|
|
}
|
|
#endif /* NETSNMP_TRANSPORT_SSH_DOMAIN */
|
|
|
|
#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
|
|
if (netsnmp_oid_equals(netsnmpDTLSUDPDomain,
|
|
netsnmpDTLSUDPDomain_len,
|
|
tmStateRef->transportDomain,
|
|
tmStateRef->transportDomainLen) == 0) {
|
|
|
|
prefix = "dtls";
|
|
}
|
|
#endif /* NETSNMP_TRANSPORT_DTLSUDP_DOMAIN */
|
|
|
|
#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
|
|
if (netsnmp_oid_equals(netsnmpTLSTCPDomain,
|
|
netsnmpTLSTCPDomain_len,
|
|
tmStateRef->transportDomain,
|
|
tmStateRef->transportDomainLen) == 0) {
|
|
|
|
prefix = "tls";
|
|
}
|
|
#endif /* NETSNMP_TRANSPORT_TLSTCP_DOMAIN */
|
|
|
|
/* Section 5.2, step 3:
|
|
If the prefix lookup fails for any reason, then the
|
|
snmpTsmUnknownPrefixes counter is incremented, an error
|
|
indication is returned to the calling module, and message
|
|
processing stops.
|
|
*/
|
|
if (prefix == NULL) {
|
|
snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
|
|
return SNMPERR_GENERR;
|
|
}
|
|
|
|
/* Section 5.2, step 3:
|
|
If the lookup succeeds but the prefix length is less than 1 or
|
|
greater than 4 octets, then the snmpTsmInvalidPrefixes counter
|
|
is incremented, an error indication is returned to the calling
|
|
module, and message processing stops.
|
|
*/
|
|
#ifdef NOT_USING_HARDCODED_PREFIXES
|
|
/* the above code actually ensures this will never happen as
|
|
we don't support a dynamic prefix database where this might
|
|
happen. */
|
|
if (strlen(prefix) < 1 || strlen(prefix) > 4) {
|
|
/* XXX: snmpTsmInvalidPrefixes++ */
|
|
return SNMPERR_GENERR;
|
|
}
|
|
#endif
|
|
|
|
/* Section 5.2, step 3:
|
|
Set the securityName to be the concatenation of the prefix, a
|
|
':' character (US-ASCII 0x3a), and the tmSecurityName.
|
|
*/
|
|
snprintf(parms->secName, *parms->secNameLen,
|
|
"%s:%s", prefix, tmStateRef->securityName);
|
|
} else {
|
|
/* if the use prefix flag wasn't set, do a straight copy */
|
|
strncpy(parms->secName, tmStateRef->securityName, *parms->secNameLen);
|
|
}
|
|
|
|
/* set the length of the security name */
|
|
*parms->secNameLen = strlen(parms->secName);
|
|
DEBUGMSGTL(("tsm", "user: %s/%d\n", parms->secName, (int)*parms->secNameLen));
|
|
|
|
/* Section 5.2 Step 4:
|
|
Compare the value of tmTransportSecurityLevel in the
|
|
tmStateReference cache to the value of the securityLevel
|
|
parameter passed in the processIncomingMsg ASI. If securityLevel
|
|
specifies privacy (Priv) and tmTransportSecurityLevel specifies
|
|
no privacy (noPriv), or if securityLevel specifies authentication
|
|
(auth) and tmTransportSecurityLevel specifies no authentication
|
|
(noAuth) was provided by the Transport Model, then the
|
|
snmpTsmInadequateSecurityLevels counter is incremented, an error
|
|
indication (unsupportedSecurityLevel) together with the OID and
|
|
value of the incremented counter is returned to the calling
|
|
module, and Transport Security Model processing stops for this
|
|
message.*/
|
|
if (parms->secLevel > tmStateRef->transportSecurityLevel) {
|
|
snmp_increment_statistic(STAT_TSM_SNMPTSMINADEQUATESECURITYLEVELS);
|
|
DEBUGMSGTL(("tsm", "inadequate security level: %d\n", parms->secLevel));
|
|
/* net-snmp returns error codes not OIDs, which are dealt with later */
|
|
return SNMPERR_UNSUPPORTED_SEC_LEVEL;
|
|
}
|
|
|
|
/* Section 5.2 Step 5
|
|
The tmStateReference is cached as cachedSecurityData so that a
|
|
possible response to this message will use the same security
|
|
parameters. Then securityStateReference is set for subsequent
|
|
references to this cached data.
|
|
*/
|
|
if (NULL == *parms->secStateRef) {
|
|
tsmSecRef = SNMP_MALLOC_TYPEDEF(netsnmp_tsmSecurityReference);
|
|
} else {
|
|
tsmSecRef = *parms->secStateRef;
|
|
}
|
|
|
|
netsnmp_assert_or_return(NULL != tsmSecRef, SNMPERR_GENERR);
|
|
|
|
*parms->secStateRef = tsmSecRef;
|
|
tsmSecRef->tmStateRef = tmStateRef;
|
|
|
|
/* If this did not come through a tunneled connection, this
|
|
security model is inappropriate (and would be a HUGE security
|
|
hole to assume otherwise). This is functionally a double check
|
|
since the pdu wouldn't have transport data otherwise. But this
|
|
is safer though is functionally an extra step beyond the TSM
|
|
RFC. */
|
|
DEBUGMSGTL(("tsm","checking how we got here\n"));
|
|
if (!(parms->pdu->flags & UCD_MSG_FLAG_TUNNELED)) {
|
|
DEBUGMSGTL(("tsm"," pdu not tunneled\n"));
|
|
if (!(parms->sess->flags & NETSNMP_TRANSPORT_FLAG_TUNNELED)) {
|
|
DEBUGMSGTL(("tsm"," session not tunneled\n"));
|
|
return SNMPERR_USM_AUTHENTICATIONFAILURE;
|
|
}
|
|
DEBUGMSGTL(("tsm"," but session is tunneled\n"));
|
|
} else {
|
|
DEBUGMSGTL(("tsm"," tunneled\n"));
|
|
}
|
|
|
|
/* Section 5.2, Step 6:
|
|
The scopedPDU component is extracted from the wholeMsg. */
|
|
/*
|
|
* Eat the first octet header.
|
|
*/
|
|
remaining = parms->wholeMsgLen - (parms->secParams - parms->wholeMsg);
|
|
if ((data_ptr = asn_parse_sequence(parms->secParams, &remaining,
|
|
&type_value,
|
|
(ASN_UNIVERSAL | ASN_PRIMITIVE |
|
|
ASN_OCTET_STR),
|
|
"tsm first octet")) == NULL) {
|
|
/*
|
|
* RETURN parse error
|
|
*/
|
|
return SNMPERR_ASN_PARSE_ERR;
|
|
}
|
|
|
|
*parms->scopedPdu = data_ptr;
|
|
*parms->scopedPduLen = parms->wholeMsgLen - (data_ptr - parms->wholeMsg);
|
|
|
|
/* Section 5.2, Step 7:
|
|
The maxSizeResponseScopedPDU is calculated. This is the maximum
|
|
size allowed for a scopedPDU for a possible Response message.
|
|
*/
|
|
*parms->maxSizeResponse = parms->maxMsgSize; /* XXX */
|
|
|
|
/* Section 5.2, Step 8:
|
|
The statusInformation is set to success and a return is made to
|
|
the calling module passing back the OUT parameters as specified
|
|
in the processIncomingMsg ASI.
|
|
*/
|
|
return SNMPERR_SUCCESS;
|
|
}
|