Coverage Report

Created: 2026-10-17 06:54

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
0
{
44
0
    struct snmp_secmod_def *def;
45
0
    int ret;
46
47
0
    def = SNMP_MALLOC_STRUCT(snmp_secmod_def);
48
49
0
    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
0
    def->encode_reverse = tsm_rgenerate_out_msg;
56
0
    def->decode = tsm_process_in_msg;
57
0
    def->session_open = tsm_session_init;
58
0
    def->pdu_free_state_ref = tsm_free_state_ref;
59
0
    def->pdu_clone = tsm_clone_pdu;
60
0
    def->pdu_free = tsm_free_pdu;
61
0
    def->probe_engineid = snmpv3_probe_contextEngineID_rfc5343;
62
63
0
    DEBUGMSGTL(("tsm","registering ourselves\n"));
64
0
    ret = register_sec_mod(SNMP_SEC_MODEL_TSM, "tsm", def);
65
0
    DEBUGMSGTL(("tsm"," returned %d\n", ret));
66
67
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "tsmUseTransportPrefix",
68
0
             NETSNMP_DS_LIBRARY_ID,
69
0
                               NETSNMP_DS_LIB_TSM_USE_PREFIX);
70
0
}
71
72
/** shutdown the TSM security module */
73
void
74
shutdown_tsm(void)
75
0
{
76
0
}
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 (!parms->session || !parms->session->peername) {
257
0
                snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
258
0
                SNMP_FREE(tmStateRef);
259
0
                return SNMPERR_GENERR;
260
0
            }
261
0
            if (strncmp("ssh:",parms->session->peername,4) == 0)
262
0
                prefix = "ssh:";
263
0
            else if (strncmp("dtls:",parms->session->peername,5) == 0)
264
0
                prefix = "dtls:";
265
0
            else if (strncmp("tls:",parms->session->peername,4) == 0)
266
0
                prefix = "tls:";
267
0
            else {
268
                /* 4.2, step 2: If the prefix lookup fails for any
269
                   reason, then the snmpTsmUnknownPrefixes counter is
270
                   incremented, an error indication is returned to the
271
                   calling module, and message processing stops. */
272
0
                snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
273
0
                SNMP_FREE(tmStateRef);
274
0
                return SNMPERR_GENERR;
275
0
            }
276
277
            /* 4.2, step 2: If the lookup succeeds, but there is no
278
               prefix in the securityName, or the prefix returned does
279
               not match the prefix in the securityName, or the length
280
               of the prefix is less than 1 or greater than 4 US-ASCII
281
               alpha-numeric characters, then the
282
               snmpTsmInvalidPrefixes counter is incremented, an error
283
               indication is returned to the calling module, and
284
               message processing stops. */
285
0
            if (!parms->secName ||
286
0
                memchr(parms->secName, ':', parms->secNameLen) == NULL ||
287
0
                strlen(prefix)+1 >= parms->secNameLen ||
288
0
                parms->secNameLen - strlen(prefix) - 1 >=
289
0
                    sizeof(tmStateRef->securityName) ||
290
0
                strncmp(parms->secName, prefix, strlen(prefix)) != 0 ||
291
0
                parms->secName[strlen(prefix)] != ':') {
292
                /* Note: since we're assigning the prefixes above the
293
                   prefix lengths always meet the 1-4 criteria */
294
0
                snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDPREFIXES);
295
0
                SNMP_FREE(tmStateRef);
296
0
                return SNMPERR_GENERR;
297
0
            }
298
299
            /* 4.2, step 2: Strip the transport-specific prefix and
300
               trailing ':' character (US-ASCII 0x3a) from the
301
               securityName.  Set tmSecurityName to the value of
302
               securityName. */
303
0
            memcpy(tmStateRef->securityName,
304
0
                   parms->secName + strlen(prefix) + 1,
305
0
                   parms->secNameLen - strlen(prefix) - 1);
306
0
            tmStateRef->securityNameLen = parms->secNameLen - strlen(prefix) -1;
307
0
        } else {
308
            /* 4.2, step 2: If the snmpTsmConfigurationUsePrefix object is
309
               set to false, then set tmSecurityName to the value
310
               of securityName. */
311
0
            if (!parms->secName ||
312
0
                parms->secNameLen >= sizeof(tmStateRef->securityName)) {
313
0
                SNMP_FREE(tmStateRef);
314
0
                return SNMPERR_GENERR;
315
0
            }
316
0
            memcpy(tmStateRef->securityName, parms->secName,
317
0
                   parms->secNameLen);
318
0
            tmStateRef->securityNameLen = parms->secNameLen;
319
0
        }
320
0
    }
321
322
    /* truncate the security name with a '\0' for safety */
323
0
    if (tmStateRef->securityNameLen >= sizeof(tmStateRef->securityName))
324
0
        tmStateRef->securityNameLen = sizeof(tmStateRef->securityName) - 1;
325
0
    tmStateRef->securityName[tmStateRef->securityNameLen] = '\0';
326
327
    /* 4.2, step 3: Set securityParameters to a zero-length OCTET
328
     *  STRING ('0400').
329
     */
330
0
    DEBUGDUMPHEADER("send", "tsm security parameters");
331
0
    rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1,
332
0
                                     (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
333
0
                                             | ASN_OCTET_STR), 0);
334
0
    DEBUGINDENTLESS();
335
0
    if (rc == 0) {
336
0
        DEBUGMSGTL(("tsm", "building msgSecurityParameters failed.\n"));
337
0
        if (tmStateRefLocal)
338
0
            SNMP_FREE(tmStateRef);
339
0
        if (tsmSecRef)
340
0
            tsm_free_state_ref(tsmSecRef);
341
0
        return SNMPERR_TOO_LONG;
342
0
    }
343
    
344
    /* 4.2, step 4: Combine the message parts into a wholeMsg and
345
       calculate wholeMsgLength.
346
     */
347
0
    while ((*wholeMsgLen - *offset) < parms->globalDataLen) {
348
0
        if (!asn_realloc(wholeMsg, wholeMsgLen)) {
349
0
            DEBUGMSGTL(("tsm", "building global data failed.\n"));
350
0
            if (tmStateRefLocal)
351
0
                SNMP_FREE(tmStateRef);
352
0
            if (tsmSecRef)
353
0
                tsm_free_state_ref(tsmSecRef);
354
0
            return SNMPERR_TOO_LONG;
355
0
        }
356
0
    }
357
358
0
    *offset += parms->globalDataLen;
359
0
    memcpy(*wholeMsg + *wholeMsgLen - *offset,
360
0
           parms->globalData, parms->globalDataLen);
361
362
    /* 4.2, step 5: The wholeMsg, wholeMsgLength, securityParameters,
363
       and tmStateReference are returned to the calling Message
364
       Processing Model with the statusInformation set to success. */
365
366
    /* For the Net-SNMP implementation that actually means we start
367
       encoding the full packet sequence from here before returning it */
368
369
    /*
370
     * Total packet sequence.  
371
     */
372
0
    rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1,
373
0
                                     (u_char) (ASN_SEQUENCE |
374
0
                                               ASN_CONSTRUCTOR), *offset);
375
0
    if (rc == 0) {
376
0
        DEBUGMSGTL(("tsm", "building master packet sequence failed.\n"));
377
0
        if (tmStateRefLocal)
378
0
            SNMP_FREE(tmStateRef);
379
0
        if (tsmSecRef)
380
0
            tsm_free_state_ref(tsmSecRef);
381
0
        return SNMPERR_TOO_LONG;
382
0
    }
383
384
0
    if (parms->pdu->transport_data &&
385
0
        parms->pdu->transport_data != tmStateRef) {
386
0
        snmp_log(LOG_ERR, "tsm: needed to free transport data\n");
387
0
        SNMP_FREE(parms->pdu->transport_data);
388
0
    }
389
390
    /* put the transport state reference into the PDU for the transport */
391
0
    parms->pdu->transport_data = netsnmp_memdup(tmStateRef, sizeof(*tmStateRef));
392
0
    if (tmStateRefLocal)
393
0
        SNMP_FREE(tmStateRef);
394
395
0
    if (!parms->pdu->transport_data) {
396
0
        snmp_log(LOG_ERR, "tsm: malloc failure\n");
397
0
        if (tsmSecRef)
398
0
            tsm_free_state_ref(tsmSecRef);
399
0
        return SNMPERR_GENERR;
400
0
    }
401
0
    parms->pdu->transport_data_length = sizeof(*tmStateRef);
402
403
0
    if (tsmSecRef)
404
0
        tsm_free_state_ref(tsmSecRef);
405
406
0
    DEBUGMSGTL(("tsm", "TSM processing completed.\n"));
407
0
    return SNMPERR_SUCCESS;
408
0
}
409
410
/****************************************************************************
411
 *
412
 * tsm_process_in_msg
413
 *
414
 * Parameters:
415
 *  (See list below...)
416
 *
417
 * Returns:
418
 *  TSM_ERR_NO_ERROR                        On success.
419
 *  TSM_ERR_GENERIC_ERROR
420
 *  TSM_ERR_UNSUPPORTED_SECURITY_LEVEL
421
 *
422
 *
423
 * Processes an incoming message.
424
 *
425
 ****************************************************************************/
426
427
int
428
tsm_process_in_msg(struct snmp_secmod_incoming_params *parms)
429
0
{
430
0
    u_char type_value;
431
0
    size_t remaining;
432
0
    u_char *data_ptr;
433
0
    netsnmp_tmStateReference *tmStateRef;
434
0
    netsnmp_tsmSecurityReference *tsmSecRef;
435
0
    u_char          ourEngineID[SNMP_MAX_ENG_SIZE];
436
0
    size_t          ourEngineID_len = sizeof(ourEngineID);
437
    
438
    /* Section 5.2, step 1: Set the securityEngineID to the local
439
       snmpEngineID. */
440
0
    ourEngineID_len =
441
0
        snmpv3_get_engineID((u_char*) ourEngineID, ourEngineID_len);
442
0
    netsnmp_assert_or_return(ourEngineID_len != 0 &&
443
0
                             ourEngineID_len <= *parms->secEngineIDLen,
444
0
                             SNMPERR_GENERR);
445
0
    memcpy(parms->secEngineID, ourEngineID, ourEngineID_len);
446
0
    *parms->secEngineIDLen = ourEngineID_len;
447
448
    /* Section 5.2, step 2: If tmStateReference does not refer to a
449
       cache containing values for tmTransportDomain,
450
       tmTransportAddress, tmSecurityName, and
451
       tmTransportSecurityLevel, then the snmpTsmInvalidCaches counter
452
       is incremented, an error indication is returned to the calling
453
       module, and Security Model processing stops for this
454
       message. */
455
0
    if (!parms->pdu->transport_data ||
456
0
        sizeof(netsnmp_tmStateReference) !=
457
0
        parms->pdu->transport_data_length) {
458
        /* if we're not coming in over a proper transport; bail! */
459
0
        DEBUGMSGTL(("tsm","improper transport data\n"));
460
0
        return -1;
461
0
    }
462
0
    tmStateRef = (netsnmp_tmStateReference *) parms->pdu->transport_data;
463
0
    parms->pdu->transport_data = NULL;
464
465
0
    if (tmStateRef == NULL ||
466
        /* not needed: tmStateRef->transportDomain == NULL || */
467
        /* not needed: tmStateRef->transportAddress == NULL || */
468
0
        tmStateRef->securityName[0] == '\0'
469
0
        ) {
470
0
        snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDCACHES);
471
0
        SNMP_FREE(tmStateRef);
472
0
        return SNMPERR_GENERR;
473
0
    }
474
475
    /* Section 5.2, step 3: Copy the tmSecurityName to securityName. */
476
0
    if (*parms->secNameLen == 0) {
477
0
        SNMP_FREE(tmStateRef);
478
0
        return SNMPERR_GENERR;
479
0
    }
480
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
481
0
                               NETSNMP_DS_LIB_TSM_USE_PREFIX)) {
482
        /* Section 5.2, step 3:
483
          If the snmpTsmConfigurationUsePrefix object is set to true, then
484
          use the tmTransportDomain to look up the corresponding prefix.
485
        */
486
0
        const char *prefix = NULL;
487
        /*
488
          possibilities:
489
           |--------------------+-------|
490
           | snmpTLSTCPDomain   | tls:  |
491
           | snmpDTLSUDPDomain  | dtls: |
492
           | snmpSSHDomain      | ssh:  |
493
           |--------------------+-------|
494
        */
495
        
496
        /* XXX: cache in session! */
497
#ifdef NETSNMP_TRANSPORT_SSH_DOMAIN
498
        if (netsnmp_oid_equals(netsnmp_snmpSSHDomain,
499
                               netsnmp_snmpSSHDomain_len,
500
                               tmStateRef->transportDomain,
501
                               tmStateRef->transportDomainLen) == 0) {
502
            prefix = "ssh";
503
        }
504
#endif /*  NETSNMP_TRANSPORT_SSH_DOMAIN */
505
506
0
#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
507
0
        if (netsnmp_oid_equals(netsnmpDTLSUDPDomain,
508
0
                               netsnmpDTLSUDPDomain_len,
509
0
                               tmStateRef->transportDomain,
510
0
                               tmStateRef->transportDomainLen) == 0) {
511
            
512
0
            prefix = "dtls";
513
0
        }
514
0
#endif /* NETSNMP_TRANSPORT_DTLSUDP_DOMAIN */
515
516
0
#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
517
0
        if (netsnmp_oid_equals(netsnmpTLSTCPDomain,
518
0
                               netsnmpTLSTCPDomain_len,
519
0
                               tmStateRef->transportDomain,
520
0
                               tmStateRef->transportDomainLen) == 0) {
521
            
522
0
            prefix = "tls";
523
0
        }
524
0
#endif /* NETSNMP_TRANSPORT_TLSTCP_DOMAIN */
525
526
        /* Section 5.2, step 3:
527
          If the prefix lookup fails for any reason, then the
528
          snmpTsmUnknownPrefixes counter is incremented, an error
529
          indication is returned to the calling module, and message
530
          processing stops.
531
        */
532
0
        if (prefix == NULL) {
533
0
            snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES);
534
0
            SNMP_FREE(tmStateRef);
535
0
            return SNMPERR_GENERR;
536
0
        }
537
538
        /* Section 5.2, step 3:
539
          If the lookup succeeds but the prefix length is less than 1 or
540
          greater than 4 octets, then the snmpTsmInvalidPrefixes counter
541
          is incremented, an error indication is returned to the calling
542
          module, and message processing stops.
543
        */
544
#ifdef NOT_USING_HARDCODED_PREFIXES
545
        /* the above code actually ensures this will never happen as
546
           we don't support a dynamic prefix database where this might
547
           happen. */
548
        if (strlen(prefix) < 1 || strlen(prefix) > 4) {
549
            /* XXX: snmpTsmInvalidPrefixes++ */
550
            SNMP_FREE(tmStateRef);
551
            return SNMPERR_GENERR;
552
        }
553
#endif
554
        
555
        /* Section 5.2, step 3:
556
          Set the securityName to be the concatenation of the prefix, a
557
          ':' character (US-ASCII 0x3a), and the tmSecurityName.
558
        */
559
0
        snprintf(parms->secName, *parms->secNameLen,
560
0
                 "%s:%s", prefix, tmStateRef->securityName);
561
0
    } else {
562
        /* if the use prefix flag wasn't set, do a straight copy */
563
0
        strlcpy(parms->secName, tmStateRef->securityName, *parms->secNameLen);
564
0
    }
565
566
    /* set the length of the security name */
567
0
    *parms->secNameLen = strlen(parms->secName);
568
0
    DEBUGMSGTL(("tsm", "user: %s/%d\n", parms->secName, (int)*parms->secNameLen));
569
570
    /* Section 5.2 Step 4:
571
       Compare the value of tmTransportSecurityLevel in the
572
       tmStateReference cache to the value of the securityLevel
573
       parameter passed in the processIncomingMsg ASI.  If securityLevel
574
       specifies privacy (Priv) and tmTransportSecurityLevel specifies
575
       no privacy (noPriv), or if securityLevel specifies authentication
576
       (auth) and tmTransportSecurityLevel specifies no authentication
577
       (noAuth) was provided by the Transport Model, then the
578
       snmpTsmInadequateSecurityLevels counter is incremented, an error
579
       indication (unsupportedSecurityLevel) together with the OID and
580
       value of the incremented counter is returned to the calling
581
       module, and Transport Security Model processing stops for this
582
       message.*/
583
0
    if (parms->secLevel > tmStateRef->transportSecurityLevel) {
584
0
        snmp_increment_statistic(STAT_TSM_SNMPTSMINADEQUATESECURITYLEVELS);
585
0
        DEBUGMSGTL(("tsm", "inadequate security level: %d\n", parms->secLevel));
586
0
        SNMP_FREE(tmStateRef);
587
        /* net-snmp returns error codes not OIDs, which are dealt with later */
588
0
        return SNMPERR_UNSUPPORTED_SEC_LEVEL;
589
0
    }
590
591
    /* Section 5.2 Step 5
592
       The tmStateReference is cached as cachedSecurityData so that a
593
       possible response to this message will use the same security
594
       parameters.  Then securityStateReference is set for subsequent
595
       references to this cached data.
596
    */
597
0
    if (NULL == *parms->secStateRef) {
598
0
        tsmSecRef = SNMP_MALLOC_TYPEDEF(netsnmp_tsmSecurityReference);
599
0
    } else {
600
0
        tsmSecRef = *parms->secStateRef;
601
0
    }
602
603
0
    if (NULL == tsmSecRef) {
604
0
        SNMP_FREE(tmStateRef);
605
0
        return SNMPERR_GENERR;
606
0
    }
607
608
0
    *parms->secStateRef = tsmSecRef;
609
0
    if (tsmSecRef->tmStateRef != tmStateRef)
610
0
        SNMP_FREE(tsmSecRef->tmStateRef);
611
0
    tsmSecRef->tmStateRef = tmStateRef;
612
613
    /* If this did not come through a tunneled connection, this
614
       security model is inappropriate (and would be a HUGE security
615
       hole to assume otherwise).  This is functionally a double check
616
       since the pdu wouldn't have transport data otherwise.  But this
617
       is safer though is functionally an extra step beyond the TSM
618
       RFC. */
619
0
    DEBUGMSGTL(("tsm","checking how we got here\n"));
620
0
    if (!(parms->pdu->flags & UCD_MSG_FLAG_TUNNELED)) {
621
0
        DEBUGMSGTL(("tsm","  pdu not tunneled\n"));
622
0
        if (!(parms->sess->flags & NETSNMP_TRANSPORT_FLAG_TUNNELED)) {
623
0
            DEBUGMSGTL(("tsm","  session not tunneled\n"));
624
0
            return SNMPERR_USM_AUTHENTICATIONFAILURE;
625
0
        }
626
0
        DEBUGMSGTL(("tsm","  but session is tunneled\n"));
627
0
    } else {
628
0
        DEBUGMSGTL(("tsm","  tunneled\n"));
629
0
    }
630
631
    /* Section 5.2, Step 6:
632
       The scopedPDU component is extracted from the wholeMsg. */
633
    /*
634
     * Eat the first octet header.
635
     */
636
0
    remaining = parms->wholeMsgLen - (parms->secParams - parms->wholeMsg);
637
0
    if ((data_ptr = asn_parse_sequence(parms->secParams, &remaining,
638
0
                                        &type_value,
639
0
                                        (ASN_UNIVERSAL | ASN_PRIMITIVE |
640
0
                                         ASN_OCTET_STR),
641
0
                                        "tsm first octet")) == NULL) {
642
        /*
643
         * RETURN parse error 
644
         */
645
0
        return SNMPERR_ASN_PARSE_ERR;
646
0
    }
647
    
648
0
    *parms->scopedPdu = data_ptr;
649
0
    *parms->scopedPduLen = parms->wholeMsgLen - (data_ptr - parms->wholeMsg);
650
651
    /* Section 5.2, Step 7:
652
       The maxSizeResponseScopedPDU is calculated.  This is the maximum
653
       size allowed for a scopedPDU for a possible Response message.
654
     */
655
0
    *parms->maxSizeResponse = parms->maxMsgSize; /* XXX */
656
657
    /* Section 5.2, Step 8:
658
       The statusInformation is set to success and a return is made to
659
       the calling module passing back the OUT parameters as specified
660
       in the processIncomingMsg ASI.
661
    */
662
0
    return SNMPERR_SUCCESS;
663
0
}