Coverage Report

Created: 2026-01-09 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmptsm.c
Line
Count
Source
1
/*
2
 * snmptsmsm.c -- Implements RFC #5591
3
 *
4
 * This code implements a security model that assumes the local user
5
 * that executed the agent is the user who's attributes are passed up
6
 * by the transport underneath.  The RFC describing this security
7
 * model is RFC5591.
8
 */
9
10
#include <net-snmp/net-snmp-config.h>
11
12
#include <net-snmp/net-snmp-features.h>
13
#include <net-snmp/net-snmp-includes.h>
14
15
#include <net-snmp/library/snmptsm.h>
16
17
#ifdef NETSNMP_TRANSPORT_SSH_DOMAIN
18
#include <net-snmp/library/snmpSSHDomain.h>
19
#endif
20
#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
21
#include <net-snmp/library/snmpDTLSUDPDomain.h>
22
#endif
23
#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
24
#include <net-snmp/library/snmpTLSTCPDomain.h>
25
#endif
26
#ifdef NETSNMP_TRANSPORT_DTLSSCTP_DOMAIN
27
#include <net-snmp/library/snmpDTLSSCTPDomain.h>
28
#endif
29
30
netsnmp_feature_require(snmpv3_probe_contextEngineID_rfc5343);
31
netsnmp_feature_require(row_create);
32
33
static int      tsm_session_init(netsnmp_session *);
34
static void     tsm_free_state_ref(void *);
35
static int      tsm_clone_pdu(netsnmp_pdu *, netsnmp_pdu *);
36
static int      tsm_free_pdu(netsnmp_pdu *pdu);
37
38
u_int next_sess_id = 1;
39
40
/** Initialize the TSM security module */
41
void
42
init_tsm(void)
43
58
{
44
58
    struct snmp_secmod_def *def;
45
58
    int ret;
46
47
58
    def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
48
49
58
    if (!def) {
50
0
        snmp_log(LOG_ERR,
51
0
                 "Unable to malloc snmp_secmod struct, not registering TSM\n");
52
0
        return;
53
0
    }
54
55
58
    def->encode_reverse = tsm_rgenerate_out_msg;
56
58
    def->decode = tsm_process_in_msg;
57
58
    def->session_open = tsm_session_init;
58
58
    def->pdu_free_state_ref = tsm_free_state_ref;
59
58
    def->pdu_clone = tsm_clone_pdu;
60
58
    def->pdu_free = tsm_free_pdu;
61
58
    def->probe_engineid = snmpv3_probe_contextEngineID_rfc5343;
62
63
58
    DEBUGMSGTL(("tsm","registering ourselves\n"));
64
58
    ret = register_sec_mod(SNMP_SEC_MODEL_TSM, "tsm", def);
65
58
    DEBUGMSGTL(("tsm"," returned %d\n", ret));
66
67
58
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "tsmUseTransportPrefix",
68
58
             NETSNMP_DS_LIBRARY_ID,
69
58
                               NETSNMP_DS_LIB_TSM_USE_PREFIX);
70
58
}
71
72
/** shutdown the TSM security module */
73
void
74
shutdown_tsm(void)
75
58
{
76
58
}
77
78
/*
79
 * Initialize specific session information (right now, just set up things to
80
 * not do an engineID probe)
81
 */
82
83
static int
84
tsm_session_init(netsnmp_session * sess)
85
0
{
86
0
    DEBUGMSGTL(("tsm",
87
0
                "TSM: Reached our session initialization callback\n"));
88
89
0
    sess->flags |= SNMP_FLAGS_DONT_PROBE;
90
91
    /* XXX: likely needed for something: */
92
    /*
93
    tsmsession = sess->securityInfo =
94
    if (!tsmsession)
95
        return SNMPERR_GENERR;
96
    */
97
98
0
    return SNMPERR_SUCCESS;
99
0
}
100
101
/** Free our state information (this is only done on the agent side) */
102
static void
103
tsm_free_state_ref(void *ptr)
104
0
{
105
0
    netsnmp_tsmSecurityReference *tsmRef = ptr;
106
107
0
    if (!tsmRef)
108
0
        return;
109
110
    /* the tmStateRef is always taken care of by the normal PDU, since this
111
       is just a reference to that one */
112
    /* DON'T DO: SNMP_FREE(tsmRef->tmStateRef); */
113
    /* SNMP_FREE(tsmRef);  ? */
114
0
}
115
116
static int
117
tsm_free_pdu(netsnmp_pdu *pdu)
118
0
{
119
    /* free the security reference */
120
0
    if (pdu->securityStateRef) {
121
0
        tsm_free_state_ref(pdu->securityStateRef);
122
0
        pdu->securityStateRef = NULL;
123
0
    }
124
0
    return 0;
125
0
}
126
127
/** This is called when a PDU is cloned (to increase reference counts) */
128
static int
129
tsm_clone_pdu(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
130
0
{
131
0
    netsnmp_tsmSecurityReference *oldref, *newref;
132
133
0
    oldref = pdu->securityStateRef;
134
0
    if (!oldref)
135
0
        return SNMPERR_SUCCESS;
136
137
0
    newref = SNMP_MALLOC_TYPEDEF(netsnmp_tsmSecurityReference);
138
0
    netsnmp_assert_or_return(NULL != newref, SNMPERR_GENERR);
139
0
    DEBUGMSGTL(("tsm", "cloned as pdu=%p, ref=%p (oldref=%p)\n",
140
0
                pdu2, newref, pdu2->securityStateRef));
141
    
142
0
    memcpy(newref, oldref, sizeof(*oldref));
143
144
    /* the tm state reference is just a link to the one in the pdu,
145
       which was already copied by snmp_clone_pdu before handing it to
146
       us. */
147
148
0
    newref->tmStateRef = netsnmp_memdup(oldref->tmStateRef,
149
0
                                        sizeof(*oldref->tmStateRef));
150
0
    if (!newref->tmStateRef) {
151
0
        snmp_log(LOG_ERR, "tsm: malloc failure\n");
152
0
        free(newref);
153
0
        return SNMPERR_GENERR;
154
0
    }
155
156
0
    pdu2->securityStateRef = newref;
157
158
0
    return SNMPERR_SUCCESS;
159
0
}
160
161
/* asn.1 easing definitions */
162
#define TSMBUILD_OR_ERR(fun, args, msg, desc)       \
163
    DEBUGDUMPHEADER("send", desc); \
164
    rc = fun args;            \
165
    DEBUGINDENTLESS();        \
166
    if (rc == 0) { \
167
        DEBUGMSGTL(("tsm",msg)); \
168
        retval = SNMPERR_TOO_LONG; \
169
        goto outerr; \
170
    }
171
172
/****************************************************************************
173
 *
174
 * tsm_generate_out_msg
175
 *
176
 * Parameters:
177
 *  (See list below...)
178
 *
179
 * Returns:
180
 *  SNMPERR_SUCCESS                        On success.
181
 *  ... and others
182
 *
183
 *
184
 * Generate an outgoing message.
185
 *
186
 ****************************************************************************/
187
188
int
189
tsm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms)
190
0
{
191
0
    u_char         **wholeMsg = parms->wholeMsg;
192
0
    size_t     *offset = parms->wholeMsgOffset;
193
0
    int rc;
194
    
195
0
    size_t         *wholeMsgLen = parms->wholeMsgLen;
196
0
    netsnmp_tsmSecurityReference *tsmSecRef;
197
0
    netsnmp_tmStateReference *tmStateRef;
198
0
    int             tmStateRefLocal = 0;
199
    
200
0
    DEBUGMSGTL(("tsm", "Starting TSM processing\n"));
201
202
    /* if we have this, then this message to be sent is in response to
203
       something that came in earlier and the tsmSecRef was created by
204
       the tsm_process_in_msg. */
205
0
    tsmSecRef = parms->secStateRef;
206
    
207
0
    if (tsmSecRef) {
208
        /* 4.2, step 1: If there is a securityStateReference (Response
209
           or Report message), then this Security Model uses the
210
           cached information rather than the information provided by
211
           the ASI. */
212
213
        /* 4.2, step 1: Extract the tmStateReference from the
214
           securityStateReference cache. */
215
0
        netsnmp_assert_or_return(NULL != tsmSecRef->tmStateRef, SNMPERR_GENERR);
216
0
        tmStateRef = tsmSecRef->tmStateRef;
217
218
        /* 4.2 step 1: Set the tmRequestedSecurityLevel to the value
219
           of the extracted tmTransportSecurityLevel. */
220
0
        tmStateRef->requestedSecurityLevel = tmStateRef->transportSecurityLevel;
221
222
        /* 4.2 step 1: Set the tmSameSecurity parameter in the
223
           tmStateReference cache to true. */
224
0
        tmStateRef->sameSecurity = NETSNMP_TM_USE_SAME_SECURITY;
225
226
        /* 4.2 step 1: The cachedSecurityData for this message can
227
           now be discarded. */
228
0
        SNMP_FREE(parms->secStateRef);
229
0
    } else {
230
        /* 4.2, step 2: If there is no securityStateReference (e.g., a
231
           Request-type or Notification message), then create a
232
           tmStateReference cache. */
233
0
        tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference);
234
0
        netsnmp_assert_or_return(NULL != tmStateRef, SNMPERR_GENERR);
235
0
        tmStateRefLocal = 1;
236
237
        /* XXX: we don't actually use this really in our implementation */
238
        /* 4.2, step 2: Set tmTransportDomain to the value of
239
           transportDomain, tmTransportAddress to the value of
240
           transportAddress */
241
242
        /* 4.2, step 2: and tmRequestedSecurityLevel to the value of
243
           securityLevel. */
244
0
        tmStateRef->requestedSecurityLevel = parms->secLevel;
245
246
        /* 4.2, step 2: Set the transaction-specific tmSameSecurity
247
           parameter to false. */
248
0
        tmStateRef->sameSecurity = NETSNMP_TM_SAME_SECURITY_NOT_REQUIRED;
249
250
0
        if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
251
0
                                   NETSNMP_DS_LIB_TSM_USE_PREFIX)) {
252
            /* XXX: probably shouldn't be a hard-coded list of
253
               supported transports */
254
            /* 4.2, step 2: If the snmpTsmConfigurationUsePrefix
255
               object is set to true, then use the transportDomain to
256
               look up the corresponding prefix. */
257
0
            const char *prefix;
258
0
            if (strncmp("ssh:",parms->session->peername,4) == 0)
259
0
                prefix = "ssh:";
260
0
            else if (strncmp("dtls:",parms->session->peername,5) == 0)
261
0
                prefix = "dtls:";
262
0
            else if (strncmp("tls:",parms->session->peername,4) == 0)
263
0
                prefix = "tls:";
264
0
            else {
265
                /* 4.2, step 2: If the prefix lookup fails for any
266
                   reason, then the snmpTsmUnknownPrefixes counter is
267
                   incremented, an error indication is returned to the
268
                   calling module, and message processing stops. */
269
0
                snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
270
0
                SNMP_FREE(tmStateRef);
271
0
                return SNMPERR_GENERR;
272
0
            }
273
274
            /* 4.2, step 2: If the lookup succeeds, but there is no
275
               prefix in the securityName, or the prefix returned does
276
               not match the prefix in the securityName, or the length
277
               of the prefix is less than 1 or greater than 4 US-ASCII
278
               alpha-numeric characters, then the
279
               snmpTsmInvalidPrefixes counter is incremented, an error
280
               indication is returned to the calling module, and
281
               message processing stops. */
282
0
            if (strchr(parms->secName, ':') == 0 ||
283
0
                strlen(prefix)+1 >= parms->secNameLen ||
284
0
                strncmp(parms->secName, prefix, strlen(prefix)) != 0 ||
285
0
                parms->secName[strlen(prefix)] != ':') {
286
                /* Note: since we're assigning the prefixes above the
287
                   prefix lengths always meet the 1-4 criteria */
288
0
                snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDPREFIXES);
289
0
                SNMP_FREE(tmStateRef);
290
0
                return SNMPERR_GENERR;
291
0
            }
292
293
            /* 4.2, step 2: Strip the transport-specific prefix and
294
               trailing ':' character (US-ASCII 0x3a) from the
295
               securityName.  Set tmSecurityName to the value of
296
               securityName. */
297
0
            memcpy(tmStateRef->securityName,
298
0
                   parms->secName + strlen(prefix) + 1,
299
0
                   parms->secNameLen - strlen(prefix) - 1);
300
0
            tmStateRef->securityNameLen = parms->secNameLen - strlen(prefix) -1;
301
0
        } else {
302
            /* 4.2, step 2: If the snmpTsmConfigurationUsePrefix object is
303
               set to false, then set tmSecurityName to the value
304
               of securityName. */
305
0
            memcpy(tmStateRef->securityName, parms->secName,
306
0
                   parms->secNameLen);
307
0
            tmStateRef->securityNameLen = parms->secNameLen;
308
0
        }
309
0
    }
310
311
    /* truncate the security name with a '\0' for safety */
312
0
    tmStateRef->securityName[tmStateRef->securityNameLen] = '\0';
313
314
    /* 4.2, step 3: Set securityParameters to a zero-length OCTET
315
     *  STRING ('0400').
316
     */
317
0
    DEBUGDUMPHEADER("send", "tsm security parameters");
318
0
    rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
319
0
                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
320
0
                                             | ASN_OCTET_STR), 0);
321
0
    DEBUGINDENTLESS();
322
0
    if (rc == 0) {
323
0
        DEBUGMSGTL(("tsm", "building msgSecurityParameters failed.\n"));
324
0
        if (tmStateRefLocal)
325
0
            SNMP_FREE(tmStateRef);
326
0
        return SNMPERR_TOO_LONG;
327
0
    }
328
    
329
    /* 4.2, step 4: Combine the message parts into a wholeMsg and
330
       calculate wholeMsgLength.
331
     */
332
0
    while ((*wholeMsgLen - *offset) < parms->globalDataLen) {
333
0
        if (!asn_realloc(wholeMsg, wholeMsgLen)) {
334
0
            DEBUGMSGTL(("tsm", "building global data failed.\n"));
335
0
            if (tmStateRefLocal)
336
0
                SNMP_FREE(tmStateRef);
337
0
            return SNMPERR_TOO_LONG;
338
0
        }
339
0
    }
340
341
0
    *offset += parms->globalDataLen;
342
0
    memcpy(*wholeMsg + *wholeMsgLen - *offset,
343
0
           parms->globalData, parms->globalDataLen);
344
345
    /* 4.2, step 5: The wholeMsg, wholeMsgLength, securityParameters,
346
       and tmStateReference are returned to the calling Message
347
       Processing Model with the statusInformation set to success. */
348
349
    /* For the Net-SNMP implementation that actually means we start
350
       encoding the full packet sequence from here before returning it */
351
352
    /*
353
     * Total packet sequence.  
354
     */
355
0
    rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
356
0
                                     (u_char) (ASN_SEQUENCE |
357
0
                                               ASN_CONSTRUCTOR), *offset);
358
0
    if (rc == 0) {
359
0
        DEBUGMSGTL(("tsm", "building master packet sequence failed.\n"));
360
0
        if (tmStateRefLocal)
361
0
            SNMP_FREE(tmStateRef);
362
0
        return SNMPERR_TOO_LONG;
363
0
    }
364
365
0
    if (parms->pdu->transport_data &&
366
0
        parms->pdu->transport_data != tmStateRef) {
367
0
        snmp_log(LOG_ERR, "tsm: needed to free transport data\n");
368
0
        SNMP_FREE(parms->pdu->transport_data);
369
0
    }
370
371
    /* put the transport state reference into the PDU for the transport */
372
0
    parms->pdu->transport_data = netsnmp_memdup(tmStateRef, sizeof(*tmStateRef));
373
0
    if (tmStateRefLocal)
374
0
        SNMP_FREE(tmStateRef);
375
376
0
    if (!parms->pdu->transport_data) {
377
0
        snmp_log(LOG_ERR, "tsm: malloc failure\n");
378
0
        return SNMPERR_GENERR;
379
0
    }
380
0
    parms->pdu->transport_data_length = sizeof(*tmStateRef);
381
382
0
    DEBUGMSGTL(("tsm", "TSM processing completed.\n"));
383
0
    return SNMPERR_SUCCESS;
384
0
}
385
386
/****************************************************************************
387
 *
388
 * tsm_process_in_msg
389
 *
390
 * Parameters:
391
 *  (See list below...)
392
 *
393
 * Returns:
394
 *  TSM_ERR_NO_ERROR                        On success.
395
 *  TSM_ERR_GENERIC_ERROR
396
 *  TSM_ERR_UNSUPPORTED_SECURITY_LEVEL
397
 *
398
 *
399
 * Processes an incoming message.
400
 *
401
 ****************************************************************************/
402
403
int
404
tsm_process_in_msg(struct snmp_secmod_incoming_params *parms)
405
0
{
406
0
    u_char type_value;
407
0
    size_t remaining;
408
0
    u_char *data_ptr;
409
0
    netsnmp_tmStateReference *tmStateRef;
410
0
    netsnmp_tsmSecurityReference *tsmSecRef;
411
0
    u_char          ourEngineID[SNMP_MAX_ENG_SIZE];
412
0
    static size_t   ourEngineID_len = sizeof(ourEngineID);
413
    
414
    /* Section 5.2, step 1: Set the securityEngineID to the local
415
       snmpEngineID. */
416
0
    ourEngineID_len =
417
0
        snmpv3_get_engineID((u_char*) ourEngineID, ourEngineID_len);
418
0
    netsnmp_assert_or_return(ourEngineID_len != 0 &&
419
0
                             ourEngineID_len <= *parms->secEngineIDLen &&
420
0
                             *parms->secEngineIDLen <= sizeof(ourEngineID),
421
0
                             SNMPERR_GENERR);
422
0
    memcpy(parms->secEngineID, ourEngineID, *parms->secEngineIDLen);
423
424
    /* Section 5.2, step 2: If tmStateReference does not refer to a
425
       cache containing values for tmTransportDomain,
426
       tmTransportAddress, tmSecurityName, and
427
       tmTransportSecurityLevel, then the snmpTsmInvalidCaches counter
428
       is incremented, an error indication is returned to the calling
429
       module, and Security Model processing stops for this
430
       message. */
431
0
    if (!parms->pdu->transport_data ||
432
0
        sizeof(netsnmp_tmStateReference) !=
433
0
        parms->pdu->transport_data_length) {
434
        /* if we're not coming in over a proper transport; bail! */
435
0
        DEBUGMSGTL(("tsm","improper transport data\n"));
436
0
        return -1;
437
0
    }
438
0
    tmStateRef = (netsnmp_tmStateReference *) parms->pdu->transport_data;
439
0
    parms->pdu->transport_data = NULL;
440
441
0
    if (tmStateRef == NULL ||
442
        /* not needed: tmStateRef->transportDomain == NULL || */
443
        /* not needed: tmStateRef->transportAddress == NULL || */
444
0
        tmStateRef->securityName[0] == '\0'
445
0
        ) {
446
0
        snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDCACHES);
447
0
        return SNMPERR_GENERR;
448
0
    }
449
450
    /* Section 5.2, step 3: Copy the tmSecurityName to securityName. */
451
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
452
0
                               NETSNMP_DS_LIB_TSM_USE_PREFIX)) {
453
        /* Section 5.2, step 3:
454
          If the snmpTsmConfigurationUsePrefix object is set to true, then
455
          use the tmTransportDomain to look up the corresponding prefix.
456
        */
457
0
        const char *prefix = NULL;
458
        /*
459
          possibilities:
460
           |--------------------+-------|
461
           | snmpTLSTCPDomain   | tls:  |
462
           | snmpDTLSUDPDomain  | dtls: |
463
           | snmpSSHDomain      | ssh:  |
464
           |--------------------+-------|
465
        */
466
        
467
        /* XXX: cache in session! */
468
#ifdef NETSNMP_TRANSPORT_SSH_DOMAIN
469
        if (netsnmp_oid_equals(netsnmp_snmpSSHDomain,
470
                               netsnmp_snmpSSHDomain_len,
471
                               tmStateRef->transportDomain,
472
                               tmStateRef->transportDomainLen) == 0) {
473
            prefix = "ssh";
474
        }
475
#endif /*  NETSNMP_TRANSPORT_SSH_DOMAIN */
476
477
0
#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
478
0
        if (netsnmp_oid_equals(netsnmpDTLSUDPDomain,
479
0
                               netsnmpDTLSUDPDomain_len,
480
0
                               tmStateRef->transportDomain,
481
0
                               tmStateRef->transportDomainLen) == 0) {
482
            
483
0
            prefix = "dtls";
484
0
        }
485
0
#endif /* NETSNMP_TRANSPORT_DTLSUDP_DOMAIN */
486
487
0
#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
488
0
        if (netsnmp_oid_equals(netsnmpTLSTCPDomain,
489
0
                               netsnmpTLSTCPDomain_len,
490
0
                               tmStateRef->transportDomain,
491
0
                               tmStateRef->transportDomainLen) == 0) {
492
            
493
0
            prefix = "tls";
494
0
        }
495
0
#endif /* NETSNMP_TRANSPORT_TLSTCP_DOMAIN */
496
497
        /* Section 5.2, step 3:
498
          If the prefix lookup fails for any reason, then the
499
          snmpTsmUnknownPrefixes counter is incremented, an error
500
          indication is returned to the calling module, and message
501
          processing stops.
502
        */
503
0
        if (prefix == NULL) {
504
0
            snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
505
0
            return SNMPERR_GENERR;
506
0
        }
507
508
        /* Section 5.2, step 3:
509
          If the lookup succeeds but the prefix length is less than 1 or
510
          greater than 4 octets, then the snmpTsmInvalidPrefixes counter
511
          is incremented, an error indication is returned to the calling
512
          module, and message processing stops.
513
        */
514
#ifdef NOT_USING_HARDCODED_PREFIXES
515
        /* the above code actually ensures this will never happen as
516
           we don't support a dynamic prefix database where this might
517
           happen. */
518
        if (strlen(prefix) < 1 || strlen(prefix) > 4) {
519
            /* XXX: snmpTsmInvalidPrefixes++ */
520
            return SNMPERR_GENERR;
521
        }
522
#endif
523
        
524
        /* Section 5.2, step 3:
525
          Set the securityName to be the concatenation of the prefix, a
526
          ':' character (US-ASCII 0x3a), and the tmSecurityName.
527
        */
528
0
        snprintf(parms->secName, *parms->secNameLen,
529
0
                 "%s:%s", prefix, tmStateRef->securityName);
530
0
    } else {
531
        /* if the use prefix flag wasn't set, do a straight copy */
532
0
        strncpy(parms->secName, tmStateRef->securityName, *parms->secNameLen);
533
0
    }
534
535
    /* set the length of the security name */
536
0
    *parms->secNameLen = strlen(parms->secName);
537
0
    DEBUGMSGTL(("tsm", "user: %s/%d\n", parms->secName, (int)*parms->secNameLen));
538
539
    /* Section 5.2 Step 4:
540
       Compare the value of tmTransportSecurityLevel in the
541
       tmStateReference cache to the value of the securityLevel
542
       parameter passed in the processIncomingMsg ASI.  If securityLevel
543
       specifies privacy (Priv) and tmTransportSecurityLevel specifies
544
       no privacy (noPriv), or if securityLevel specifies authentication
545
       (auth) and tmTransportSecurityLevel specifies no authentication
546
       (noAuth) was provided by the Transport Model, then the
547
       snmpTsmInadequateSecurityLevels counter is incremented, an error
548
       indication (unsupportedSecurityLevel) together with the OID and
549
       value of the incremented counter is returned to the calling
550
       module, and Transport Security Model processing stops for this
551
       message.*/
552
0
    if (parms->secLevel > tmStateRef->transportSecurityLevel) {
553
0
        snmp_increment_statistic(STAT_TSM_SNMPTSMINADEQUATESECURITYLEVELS);
554
0
        DEBUGMSGTL(("tsm", "inadequate security level: %d\n", parms->secLevel));
555
        /* net-snmp returns error codes not OIDs, which are dealt with later */
556
0
        return SNMPERR_UNSUPPORTED_SEC_LEVEL;
557
0
    }
558
559
    /* Section 5.2 Step 5
560
       The tmStateReference is cached as cachedSecurityData so that a
561
       possible response to this message will use the same security
562
       parameters.  Then securityStateReference is set for subsequent
563
       references to this cached data.
564
    */
565
0
    if (NULL == *parms->secStateRef) {
566
0
        tsmSecRef = SNMP_MALLOC_TYPEDEF(netsnmp_tsmSecurityReference);
567
0
    } else {
568
0
        tsmSecRef = *parms->secStateRef;
569
0
    }
570
571
0
    netsnmp_assert_or_return(NULL != tsmSecRef, SNMPERR_GENERR);
572
573
0
    *parms->secStateRef = tsmSecRef;
574
0
    tsmSecRef->tmStateRef = tmStateRef;
575
576
    /* If this did not come through a tunneled connection, this
577
       security model is inappropriate (and would be a HUGE security
578
       hole to assume otherwise).  This is functionally a double check
579
       since the pdu wouldn't have transport data otherwise.  But this
580
       is safer though is functionally an extra step beyond the TSM
581
       RFC. */
582
0
    DEBUGMSGTL(("tsm","checking how we got here\n"));
583
0
    if (!(parms->pdu->flags & UCD_MSG_FLAG_TUNNELED)) {
584
0
        DEBUGMSGTL(("tsm","  pdu not tunneled\n"));
585
0
        if (!(parms->sess->flags & NETSNMP_TRANSPORT_FLAG_TUNNELED)) {
586
0
            DEBUGMSGTL(("tsm","  session not tunneled\n"));
587
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
588
0
        }
589
0
        DEBUGMSGTL(("tsm","  but session is tunneled\n"));
590
0
    } else {
591
0
        DEBUGMSGTL(("tsm","  tunneled\n"));
592
0
    }
593
594
    /* Section 5.2, Step 6:
595
       The scopedPDU component is extracted from the wholeMsg. */
596
    /*
597
     * Eat the first octet header.
598
     */
599
0
    remaining = parms->wholeMsgLen - (parms->secParams - parms->wholeMsg);
600
0
    if ((data_ptr = asn_parse_sequence(parms->secParams, &remaining,
601
0
                                        &type_value,
602
0
                                        (ASN_UNIVERSAL | ASN_PRIMITIVE |
603
0
                                         ASN_OCTET_STR),
604
0
                                        "tsm first octet")) == NULL) {
605
        /*
606
         * RETURN parse error 
607
         */
608
0
        return SNMPERR_ASN_PARSE_ERR;
609
0
    }
610
    
611
0
    *parms->scopedPdu = data_ptr;
612
0
    *parms->scopedPduLen = parms->wholeMsgLen - (data_ptr - parms->wholeMsg);
613
614
    /* Section 5.2, Step 7:
615
       The maxSizeResponseScopedPDU is calculated.  This is the maximum
616
       size allowed for a scopedPDU for a possible Response message.
617
     */
618
0
    *parms->maxSizeResponse = parms->maxMsgSize; /* XXX */
619
620
    /* Section 5.2, Step 8:
621
       The statusInformation is set to success and a return is made to
622
       the calling module passing back the OUT parameters as specified
623
       in the processIncomingMsg ASI.
624
    */
625
0
    return SNMPERR_SUCCESS;
626
0
}