Blame snmplib/snmptsm.c

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