Coverage Report

Created: 2026-07-16 06:27

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