Coverage Report

Created: 2026-09-04 09:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmpv3.c
Line
Count
Source
1
/*
2
 * snmpv3.c
3
 *
4
 * Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 *
8
 * Portions of this file are copyrighted by:
9
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
10
 * Use is subject to license terms specified in the COPYING file
11
 * distributed with the Net-SNMP package.
12
 */
13
14
#include <net-snmp/net-snmp-config.h>
15
#include <errno.h>
16
#ifdef HAVE_INTTYPES_H
17
#include <inttypes.h>
18
#endif
19
#ifdef HAVE_LIMITS_H
20
#include <limits.h>
21
#endif
22
#include <stdio.h>
23
#include <sys/types.h>
24
25
#ifdef TIME_WITH_SYS_TIME
26
# include <sys/time.h>
27
# include <time.h>
28
#else
29
# ifdef HAVE_SYS_TIME_H
30
#  include <sys/time.h>
31
# else
32
#  include <time.h>
33
# endif
34
#endif
35
#ifdef HAVE_SYS_TIMES_H
36
#include <sys/times.h>
37
#endif
38
#ifdef HAVE_STRING_H
39
#include <string.h>
40
#else
41
#include <strings.h>
42
#endif
43
#include <ctype.h>
44
#ifdef HAVE_NETINET_IN_H
45
#include <netinet/in.h>
46
#endif
47
#ifdef HAVE_UNISTD_H
48
#include <unistd.h>
49
#endif
50
#ifdef HAVE_SYS_SOCKET_H
51
#include <sys/socket.h>
52
#endif
53
#ifdef HAVE_NETDB_H
54
#include <netdb.h>
55
#endif
56
#ifdef HAVE_STDLIB_H
57
#       include <stdlib.h>
58
#endif
59
60
/*
61
 * Stuff needed for getHwAddress(...) 
62
 */
63
#ifdef HAVE_SYS_IOCTL_H
64
# include <sys/ioctl.h>
65
#endif
66
#ifdef HAVE_NET_IF_H
67
# include <net/if.h>
68
#endif
69
70
#include <net-snmp/types.h>
71
#include <net-snmp/output_api.h>
72
#include <net-snmp/config_api.h>
73
#include <net-snmp/utilities.h>
74
75
#include <net-snmp/library/snmpv3.h>
76
#include <net-snmp/library/callback.h>
77
#include <net-snmp/library/snmp_api.h>
78
#include <net-snmp/library/lcd_time.h>
79
#include <net-snmp/library/scapi.h>
80
#include <net-snmp/library/keytools.h>
81
#include <net-snmp/library/lcd_time.h>
82
#include <net-snmp/library/snmp_secmod.h>
83
#include <net-snmp/library/snmpusm.h>
84
#include <net-snmp/library/transform_oids.h>
85
86
#include <net-snmp/net-snmp-features.h>
87
88
static u_long   engineBoots = 1;
89
static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND;
90
static unsigned char *engineID = NULL;
91
static size_t   engineIDLength = 0;
92
static unsigned char *engineIDNic = NULL;
93
static unsigned int engineIDIsSet = 0;  /* flag if ID set by config */
94
static unsigned char *oldEngineID = NULL;
95
static size_t   oldEngineIDLength = 0;
96
static struct timeval snmpv3starttime;
97
98
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
99
static int      getHwAddress(const char *networkDevice, char *addressOut);
100
#endif
101
102
/*******************************************************************-o-******
103
 * snmpv3_secLevel_conf
104
 *
105
 * Parameters:
106
 *  *word
107
 *  *cptr
108
 *
109
 * Line syntax:
110
 *  defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
111
 */
112
113
int
114
421
parse_secLevel_conf(const char *word, char *cptr) {
115
421
    if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
116
410
  strcasecmp(cptr, "nanp") == 0) {
117
14
        return SNMP_SEC_LEVEL_NOAUTH;
118
407
    } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
119
385
         strcasecmp(cptr, "anp") == 0) {
120
67
        return SNMP_SEC_LEVEL_AUTHNOPRIV;
121
340
    } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
122
316
         strcasecmp(cptr, "ap") == 0) {
123
75
        return SNMP_SEC_LEVEL_AUTHPRIV;
124
265
    } else {
125
265
        return -1;
126
265
    }
127
421
}
128
129
void
130
snmpv3_secLevel_conf(const char *word, char *cptr)
131
421
{
132
421
    int             secLevel;
133
134
421
    if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) {
135
156
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
136
156
         NETSNMP_DS_LIB_SECLEVEL, secLevel);
137
265
    } else {
138
265
  netsnmp_config_error("Unknown security level: %s", cptr);
139
265
    }
140
421
    DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
141
421
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
142
421
           NETSNMP_DS_LIB_SECLEVEL)));
143
421
}
144
145
146
int
147
snmpv3_parse_arg(int arg, char *optarg, netsnmp_session *session, char **Apsz,
148
                 char **Xpsz, int argc, char *const *argv, int flags)
149
1.46k
{
150
1.46k
    int        priv_type;
151
1.46k
    char      *cp;
152
1.46k
    int        zero_sensitive = !( flags & NETSNMP_PARSE_ARGS_NOZERO );
153
154
1.46k
    switch (arg) {
155
156
77
    case 'Z':
157
77
        errno=0;
158
77
        session->engineBoots = strtoul(optarg, &cp, 10);
159
77
        if (errno || cp == optarg) {
160
2
            fprintf(stderr, "Need engine boots value after -3Z flag.\n");
161
2
            return (-1);
162
2
        }
163
75
        if (*cp == ',') {
164
47
            char *endptr;
165
47
            cp++;
166
47
            session->engineTime = strtoul(cp, &endptr, 10);
167
47
            if (errno || cp == endptr) {
168
2
                fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
169
2
                return (-1);
170
2
            }
171
47
        }
172
        /*
173
         * Handle previous '-Z boot time' syntax
174
         */
175
28
        else if (optind < argc) {
176
26
            session->engineTime = strtoul(argv[optind], &cp, 10);
177
26
            if (errno || cp == argv[optind]) {
178
7
                fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
179
7
                return (-1);
180
7
            }
181
26
        } else {
182
2
            fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
183
2
            return (-1);
184
2
        }
185
64
        break;
186
187
87
    case 'e':{
188
87
            size_t          ebuf_len = 32, eout_len = 0;
189
87
            u_char         *ebuf = (u_char *) malloc(ebuf_len);
190
191
87
            if (ebuf == NULL) {
192
0
                fprintf(stderr, "malloc failure processing -3e flag.\n");
193
0
                return (-1);
194
0
            }
195
87
            if (!snmp_hex_to_binary
196
87
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
197
28
                fprintf(stderr, "Bad engine ID value after -3e flag.\n");
198
28
                SNMP_FREE(ebuf);
199
28
                return (-1);
200
28
            }
201
59
            if ((eout_len < 5) || (eout_len > 32)) {
202
5
                fprintf(stderr, "Invalid engine ID value after -e flag.\n");
203
5
                free(ebuf);
204
5
                return (-1);
205
5
            }
206
54
      free(session->securityEngineID);
207
54
            session->securityEngineID = ebuf;
208
54
            session->securityEngineIDLen = eout_len;
209
54
            break;
210
59
        }
211
212
47
    case 'E':{
213
47
            size_t          ebuf_len = 32, eout_len = 0;
214
47
            u_char         *ebuf = (u_char *) malloc(ebuf_len);
215
216
47
            if (ebuf == NULL) {
217
0
                fprintf(stderr, "malloc failure processing -3E flag.\n");
218
0
                return (-1);
219
0
            }
220
47
            if (!snmp_hex_to_binary
221
47
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
222
2
                fprintf(stderr, "Bad engine ID value after -3E flag.\n");
223
2
                SNMP_FREE(ebuf);
224
2
                return (-1);
225
2
            }
226
45
            if ((eout_len < 5) || (eout_len > 32)) {
227
5
                fprintf(stderr, "Invalid engine ID value after -E flag.\n");
228
5
                free(ebuf);
229
5
                return (-1);
230
5
            }
231
40
      free(session->contextEngineID);
232
40
            session->contextEngineID = ebuf;
233
40
            session->contextEngineIDLen = eout_len;
234
40
            break;
235
45
        }
236
237
81
    case 'n':
238
81
        free(session->contextName);
239
81
        session->contextName = strdup(optarg);
240
81
        session->contextNameLen = strlen(optarg);
241
81
        break;
242
243
77
    case 'u':
244
77
        free(session->securityName);
245
77
        session->securityName = strdup(optarg);
246
77
        session->securityNameLen = strlen(optarg);
247
77
        break;
248
249
507
    case 'l':
250
507
        if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
251
453
            !strcasecmp(optarg, "noauth") || !strcasecmp(optarg, "nanp")) {
252
77
            session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
253
430
        } else if (!strcasecmp(optarg, "authNoPriv")
254
412
                   || !strcasecmp(optarg, "auth")
255
402
                   || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
256
81
            session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
257
349
        } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
258
312
                   || !strcasecmp(optarg, "priv")
259
302
                   || !strcasecmp(optarg, "ap")) {
260
66
            session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
261
283
        } else {
262
283
            fprintf(stderr,
263
283
                    "Invalid security level specified after -3l flag: %s\n",
264
283
                    optarg);
265
283
            return (-1);
266
283
        }
267
224
        break;
268
269
224
#ifdef NETSNMP_SECMOD_USM
270
224
    case 'a': {
271
79
        int auth_type = usm_lookup_auth_type(optarg);
272
79
        if (auth_type > 0) {
273
40
            const oid *auth_proto;
274
275
40
            auth_proto = sc_get_auth_oid(auth_type,
276
40
                                         &session->securityAuthProtoLen);
277
40
            free(session->securityAuthProto);
278
40
            session->securityAuthProto = snmp_duplicate_objid(auth_proto,
279
40
                                             session->securityAuthProtoLen);
280
40
         } else {
281
39
            fprintf(stderr,
282
39
                    "Invalid authentication protocol specified after -3a flag: %s\n",
283
39
                    optarg);
284
39
            return (-1);
285
39
        }
286
79
    }
287
40
        break;
288
289
170
    case 'x': {
290
170
        const oid *priv_proto;
291
292
170
        priv_type = usm_lookup_priv_type(optarg);
293
170
        if (priv_type < 0) {
294
61
            fprintf(stderr,
295
61
                    "Invalid privacy protocol specified after -3x flag: %s\n",
296
61
                    optarg);
297
61
            return (-1);
298
61
        }
299
109
        priv_proto = sc_get_priv_oid(priv_type, &session->securityPrivProtoLen);
300
109
        free(session->securityPrivProto);
301
109
        session->securityPrivProto = snmp_duplicate_objid(priv_proto,
302
109
                                         session->securityPrivProtoLen);
303
109
        break;
304
170
    }
305
100
    case 'A':
306
100
        if (*Apsz && zero_sensitive) {
307
73
            memset(*Apsz, 0x0, strlen(*Apsz));
308
73
        }
309
100
        free(*Apsz);
310
100
        *Apsz = strdup(optarg);
311
100
        if (NULL == *Apsz) {
312
0
            fprintf(stderr, "malloc failure processing -%c flag.\n",
313
0
                    (char)arg);
314
0
            return -1;
315
0
        }
316
100
        if (zero_sensitive)
317
100
            memset(optarg, 0x0, strlen(optarg));
318
100
        break;
319
320
149
    case 'X':
321
149
        if (*Xpsz && zero_sensitive) {
322
121
            memset(*Xpsz, 0x0, strlen(*Xpsz));
323
121
        }
324
149
        free(*Xpsz);
325
149
        *Xpsz = strdup(optarg);
326
149
        if (NULL == *Xpsz) {
327
0
            fprintf(stderr, "malloc failure processing -%c flag.\n",
328
0
                    (char)arg);
329
0
            return -1;
330
0
        }
331
149
        if (zero_sensitive)
332
149
            memset(optarg, 0x0, strlen(optarg));
333
149
        break;
334
0
#endif /* NETSNMP_SECMOD_USM */
335
336
24
    case 'm': {
337
24
        size_t bufSize = sizeof(session->securityAuthKey);
338
24
        u_char *tmpp = session->securityAuthKey;
339
24
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
340
24
                                &session->securityAuthKeyLen, 0, optarg)) {
341
4
            fprintf(stderr, "Bad key value after -3m flag.\n");
342
4
            return (-1);
343
4
        }
344
20
        break;
345
24
    }
346
347
22
    case 'M': {
348
22
        size_t bufSize = sizeof(session->securityPrivKey);
349
22
        u_char *tmpp = session->securityPrivKey;
350
22
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
351
22
             &session->securityPrivKeyLen, 0, optarg)) {
352
1
            fprintf(stderr, "Bad key value after -3M flag.\n");
353
1
            return (-1);
354
1
        }
355
21
        break;
356
22
    }
357
358
21
    case 'k': {
359
11
        size_t          kbuf_len = 32, kout_len = 0;
360
11
        u_char         *kbuf = (u_char *) malloc(kbuf_len);
361
362
11
        if (kbuf == NULL) {
363
0
            fprintf(stderr, "malloc failure processing -3k flag.\n");
364
0
            return (-1);
365
0
        }
366
11
        if (!snmp_hex_to_binary
367
11
            (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
368
1
            fprintf(stderr, "Bad key value after -3k flag.\n");
369
1
            SNMP_FREE(kbuf);
370
1
            return (-1);
371
1
        }
372
10
        free(session->securityAuthLocalKey);
373
10
        session->securityAuthLocalKey = kbuf;
374
10
        session->securityAuthLocalKeyLen = kout_len;
375
10
        break;
376
11
    }
377
378
25
    case 'K': {
379
25
        size_t          kbuf_len = 32, kout_len = 0;
380
25
        u_char         *kbuf = (u_char *) malloc(kbuf_len);
381
382
25
        if (kbuf == NULL) {
383
0
            fprintf(stderr, "malloc failure processing -3K flag.\n");
384
0
            return (-1);
385
0
        }
386
25
        if (!snmp_hex_to_binary
387
25
            (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
388
8
            fprintf(stderr, "Bad key value after -3K flag.\n");
389
8
            SNMP_FREE(kbuf);
390
8
            return (-1);
391
8
        }
392
17
        free(session->securityPrivLocalKey);
393
17
        session->securityPrivLocalKey = kbuf;
394
17
        session->securityPrivLocalKeyLen = kout_len;
395
17
        break;
396
25
    }
397
        
398
7
    default:
399
7
        fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", arg);
400
7
        return -1;
401
1.46k
    }
402
1.00k
    return 0;
403
1.46k
}
404
405
int
406
snmpv3_parse_args(char *optarg, netsnmp_session * session, char **Apsz,
407
                  char **Xpsz, int argc, char *const *argv, int flags)
408
98
{
409
98
    char           *cp = optarg;
410
98
    optarg++;
411
    /*
412
     * Support '... -3x=value ....' syntax
413
     */
414
98
    if (*optarg == '=') {
415
12
        optarg++;
416
12
    }
417
    /*
418
     * and '.... "-3x value" ....'  (*with* the quotes)
419
     */
420
414
    while (*optarg && isspace((unsigned char)(*optarg))) {
421
316
        optarg++;
422
316
    }
423
    /*
424
     * Finally, handle ".... -3x value ...." syntax
425
     *   (*without* surrounding quotes)
426
     */
427
98
    if (!*optarg) {
428
        /*
429
         * We've run off the end of the argument
430
         *  so move on the the next.
431
         */
432
30
        if (optind >= argc) {
433
3
            fprintf(stderr,
434
3
                    "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
435
3
            return (-1);
436
3
        }
437
27
        optarg = argv[optind++];
438
27
    }
439
440
95
    return snmpv3_parse_arg(*cp, optarg, session, Apsz, Xpsz, argc, argv,
441
95
                            flags);
442
98
}
443
444
/*******************************************************************-o-******
445
 * setup_engineID
446
 *
447
 * Parameters:
448
 *  **eidp
449
 *   *text  Printable (?) text to be plugged into the snmpEngineID.
450
 *
451
 * Return:
452
 *  Length of allocated engineID string in bytes,  -OR-
453
 *  -1 on error.
454
 *
455
 *
456
 * Create an snmpEngineID using text and the local IP address.  If eidp
457
 * is defined, use it to return a pointer to the newly allocated data.
458
 * Otherwise, use the result to define engineID defined in this module.
459
 *
460
 * Line syntax:
461
 *  engineID <text> | NULL
462
 *
463
 * XXX  What if a node has multiple interfaces?
464
 * XXX  What if multiple engines all choose the same address?
465
 *      (answer:  You're screwed, because you might need a kul database
466
 *       which is dependent on the current engineID.  Enumeration and other
467
 *       tricks won't work). 
468
 */
469
int
470
setup_engineID(u_char ** eidp, const char *text)
471
3.40k
{
472
3.40k
    int             enterpriseid = htonl(NETSNMP_ENTERPRISE_OID),
473
3.40k
        netsnmpoid = htonl(NETSNMP_OID),
474
3.40k
        localsetup = (eidp) ? 0 : 1;
475
476
    /*
477
     * Use local engineID if *eidp == NULL.  
478
     */
479
3.40k
#ifdef HAVE_GETHOSTNAME
480
3.40k
    u_char          buf[SNMP_MAXBUF_SMALL];
481
3.40k
    struct hostent *hent = NULL;
482
3.40k
#endif
483
3.40k
    u_char         *bufp = NULL;
484
3.40k
    size_t          len;
485
3.40k
    int             localEngineIDType = engineIDType;
486
3.40k
    int             tmpint;
487
3.40k
    time_t          tmptime;
488
489
3.40k
    engineIDIsSet = 1;
490
491
3.40k
#ifdef HAVE_GETHOSTNAME
492
3.40k
#ifdef AF_INET6
493
    /*
494
     * see if they selected IPV4 or IPV6 support 
495
     */
496
3.40k
    if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
497
3.40k
        (ENGINEID_TYPE_IPV4 == localEngineIDType)) {
498
        /*
499
         * get the host name and save the information 
500
         */
501
0
        gethostname((char *) buf, sizeof(buf));
502
0
        hent = netsnmp_gethostbyname((char *) buf);
503
0
        if (hent && hent->h_addrtype == AF_INET6) {
504
0
            localEngineIDType = ENGINEID_TYPE_IPV6;
505
0
        } else {
506
            /*
507
             * Not IPV6 so we go with default 
508
             */
509
0
            localEngineIDType = ENGINEID_TYPE_IPV4;
510
0
        }
511
0
    }
512
#else
513
    /*
514
     * No IPV6 support.  Check if they selected IPV6 engineID type.
515
     *  If so make it IPV4 instead 
516
     */
517
    if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
518
        localEngineIDType = ENGINEID_TYPE_IPV4;
519
    }
520
    if (ENGINEID_TYPE_IPV4 == localEngineIDType) {
521
        /*
522
         * get the host name and save the information 
523
         */
524
        gethostname((char *) buf, sizeof(buf));
525
        hent = netsnmp_gethostbyname((char *) buf);
526
    }
527
#endif
528
3.40k
#endif                          /* HAVE_GETHOSTNAME */
529
530
    /*
531
     * Determine if we have text and if so setup our localEngineIDType
532
     * * appropriately.  
533
     */
534
3.40k
    if (NULL != text) {
535
0
        engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
536
0
    }
537
    /*
538
     * Determine length of the engineID string. 
539
     */
540
3.40k
    len = 5;                    /* always have 5 leading bytes */
541
3.40k
    switch (localEngineIDType) {
542
0
    case ENGINEID_TYPE_TEXT:
543
0
        if (NULL == text) {
544
0
            snmp_log(LOG_ERR,
545
0
                     "Can't set up engineID of type text from an empty string.\n");
546
0
            return -1;
547
0
        }
548
0
        len += strlen(text);    /* 5 leading bytes+text. No NULL char */
549
0
        break;
550
0
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
551
0
    case ENGINEID_TYPE_MACADDR:        /* MAC address */
552
0
        len += 6;               /* + 6 bytes for MAC address */
553
0
        break;
554
0
#endif
555
0
    case ENGINEID_TYPE_IPV4:   /* IPv4 */
556
0
        len += 4;               /* + 4 byte IPV4 address */
557
0
        break;
558
0
    case ENGINEID_TYPE_IPV6:   /* IPv6 */
559
0
        len += 16;              /* + 16 byte IPV6 address */
560
0
        break;
561
3.40k
    case ENGINEID_TYPE_NETSNMP_RND:        /* Net-SNMP specific encoding */
562
3.40k
        if (engineID)           /* already setup, keep current value */
563
0
            return engineIDLength;
564
3.40k
        if (oldEngineID) {
565
3.34k
            len = oldEngineIDLength;
566
3.34k
        } else {
567
59
            len += sizeof(int) + sizeof(time_t);
568
59
        }
569
3.40k
        break;
570
0
    default:
571
0
        snmp_log(LOG_ERR,
572
0
                 "Unknown EngineID type requested for setup (%d).  Using IPv4.\n",
573
0
                 localEngineIDType);
574
0
        localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
575
0
        len += 4;               /* + 4 byte IPv4 address */
576
0
        break;
577
3.40k
    }                           /* switch */
578
579
580
    /*
581
     * Allocate memory and store enterprise ID.
582
     */
583
3.40k
    if (len == 0) {
584
0
        snmp_log(LOG_ERR, "%s(): len == 0\n", __func__);
585
0
        return -1;
586
0
    }
587
3.40k
    bufp = calloc(1, len);
588
3.40k
    if (bufp == NULL) {
589
0
        snmp_log_perror("setup_engineID() calloc()");
590
0
        return -1;
591
0
    }
592
3.40k
    if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
593
        /*
594
         * we must use the net-snmp enterprise id here, regardless 
595
         */
596
3.40k
        memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid));    /* XXX Must be 4 bytes! */
597
0
    else
598
0
        memcpy(bufp, &enterpriseid, sizeof(enterpriseid));      /* XXX Must be 4 bytes! */
599
600
3.40k
    bufp[0] |= 0x80;
601
602
603
    /*
604
     * Store the given text  -OR-   the first found IP address
605
     *  -OR-  the MAC address  -OR-  random elements
606
     * (the latter being the recommended default)
607
     */
608
3.40k
    switch (localEngineIDType) {
609
3.40k
    case ENGINEID_TYPE_NETSNMP_RND:
610
3.40k
        if (oldEngineID) {
611
            /*
612
             * keep our previous notion of the engineID 
613
             */
614
3.34k
            memcpy(bufp, oldEngineID, oldEngineIDLength);
615
3.34k
        } else {
616
            /*
617
             * Here we've desigend our own ENGINEID that is not based on
618
             * an address which may change and may even become conflicting
619
             * in the future like most of the default v3 engineID types
620
             * suffer from.
621
             * 
622
             * Ours is built from 2 fairly random elements: a random number and
623
             * the current time in seconds.  This method suffers from boxes
624
             * that may not have a correct clock setting and random number
625
             * seed at startup, but few OSes should have that problem.
626
             */
627
59
            bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
628
59
            tmpint = netsnmp_random();
629
59
            memcpy(bufp + 5, &tmpint, sizeof(tmpint));
630
59
            tmptime = time(NULL);
631
59
            memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
632
59
        }
633
3.40k
        break;
634
0
    case ENGINEID_TYPE_TEXT:
635
0
        bufp[4] = ENGINEID_TYPE_TEXT;
636
0
        memcpy((char *) bufp + 5, (text), strlen(text));
637
0
        break;
638
0
#ifdef HAVE_GETHOSTNAME
639
0
#ifdef AF_INET6
640
0
    case ENGINEID_TYPE_IPV6:
641
0
        bufp[4] = ENGINEID_TYPE_IPV6;
642
0
        if (hent)
643
0
            memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
644
0
        break;
645
0
#endif
646
0
#endif
647
0
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
648
0
    case ENGINEID_TYPE_MACADDR:
649
0
        {
650
0
            int             x;
651
0
            bufp[4] = ENGINEID_TYPE_MACADDR;
652
            /*
653
             * use default NIC if none provided 
654
             */
655
0
            if (NULL == engineIDNic) {
656
0
        x = getHwAddress(DEFAULT_NIC, (char *)&bufp[5]);
657
0
            } else {
658
0
        x = getHwAddress((char *)engineIDNic, (char *)&bufp[5]);
659
0
            }
660
0
            if (0 != x)
661
                /*
662
                 * function failed fill MAC address with zeros 
663
                 */
664
0
            {
665
0
                memset(&bufp[5], 0, 6);
666
0
            }
667
0
        }
668
0
        break;
669
0
#endif
670
0
    case ENGINEID_TYPE_IPV4:
671
0
    default:
672
0
        bufp[4] = ENGINEID_TYPE_IPV4;
673
0
#ifdef HAVE_GETHOSTNAME
674
0
        if (hent && hent->h_addrtype == AF_INET) {
675
0
            memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
676
0
        } else {                /* Unknown address type.  Default to 127.0.0.1. */
677
678
0
            bufp[5] = 127;
679
0
            bufp[6] = 0;
680
0
            bufp[7] = 0;
681
0
            bufp[8] = 1;
682
0
        }
683
#else                           /* HAVE_GETHOSTNAME */
684
        /*
685
         * Unknown address type.  Default to 127.0.0.1. 
686
         */
687
        bufp[5] = 127;
688
        bufp[6] = 0;
689
        bufp[7] = 0;
690
        bufp[8] = 1;
691
#endif                          /* HAVE_GETHOSTNAME */
692
0
        break;
693
3.40k
    }
694
695
    /*
696
     * Pass the string back to the calling environment, or use it for
697
     * our local engineID.
698
     */
699
3.40k
    if (localsetup) {
700
3.40k
        SNMP_FREE(engineID);
701
3.40k
        engineID = bufp;
702
3.40k
        engineIDLength = len;
703
704
3.40k
    } else {
705
0
        *eidp = bufp;
706
0
    }
707
708
709
3.40k
    return len;
710
711
3.40k
}                               /* end setup_engineID() */
712
713
int
714
free_engineID(int majorid, int minorid, void *serverarg,
715
        void *clientarg)
716
3.40k
{
717
3.40k
    SNMP_FREE(engineID);
718
3.40k
    SNMP_FREE(engineIDNic);
719
3.40k
    SNMP_FREE(oldEngineID);
720
3.40k
    engineIDIsSet = 0;
721
3.40k
    return 0;
722
3.40k
}
723
724
/*******************************************************************-o-******
725
 * engineBoots_conf
726
 *
727
 * Parameters:
728
 *  *word
729
 *  *cptr
730
 *
731
 * Line syntax:
732
 *  engineBoots <num_boots>
733
 */
734
void
735
engineBoots_conf(const char *word, char *cptr)
736
3.37k
{
737
3.37k
    engineBoots = atoi(cptr) + 1;
738
3.37k
    DEBUGMSGTL(("snmpv3", "engineBoots: %lu\n", engineBoots));
739
3.37k
}
740
741
/*******************************************************************-o-******
742
 * engineIDType_conf
743
 *
744
 * Parameters:
745
 *  *word
746
 *  *cptr
747
 *
748
 * Line syntax:
749
 *  engineIDType <1 or 3>
750
 *    1 is default for IPv4 engine ID type.  Will automatically
751
 *        chose between IPv4 & IPv6 if either 1 or 2 is specified.
752
 *    2 is for IPv6.
753
 *    3 is hardware (MAC) address, currently supported under Linux
754
 */
755
void
756
engineIDType_conf(const char *word, char *cptr)
757
0
{
758
0
    engineIDType = atoi(cptr);
759
    /*
760
     * verify valid type selected 
761
     */
762
0
    switch (engineIDType) {
763
0
    case ENGINEID_TYPE_IPV4:   /* IPv4 */
764
0
    case ENGINEID_TYPE_IPV6:   /* IPv6 */
765
        /*
766
         * IPV? is always good 
767
         */
768
0
        break;
769
0
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
770
0
    case ENGINEID_TYPE_MACADDR:        /* MAC address */
771
0
        break;
772
0
#endif
773
0
    default:
774
        /*
775
         * unsupported one chosen 
776
         */
777
0
        config_perror("Unsupported enginedIDType, forcing IPv4");
778
0
        engineIDType = ENGINEID_TYPE_IPV4;
779
0
    }
780
0
    DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType));
781
0
}
782
783
/*******************************************************************-o-******
784
 * engineIDNic_conf
785
 *
786
 * Parameters:
787
 *  *word
788
 *  *cptr
789
 *
790
 * Line syntax:
791
 *  engineIDNic <string>
792
 *    eth0 is default
793
 */
794
void
795
engineIDNic_conf(const char *word, char *cptr)
796
0
{
797
    /*
798
     * Make sure they haven't already specified the engineID via the
799
     * * configuration file 
800
     */
801
0
    if (0 == engineIDIsSet)
802
        /*
803
         * engineID has NOT been set via configuration file 
804
         */
805
0
    {
806
        /*
807
         * See if already set if so erase & release it 
808
         */
809
0
        SNMP_FREE(engineIDNic);
810
0
        engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
811
0
        if (NULL != engineIDNic) {
812
0
            strcpy((char *) engineIDNic, cptr);
813
0
            DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n",
814
0
                        engineIDNic));
815
0
        } else {
816
0
            DEBUGMSGTL(("snmpv3",
817
0
                        "Error allocating memory for engineIDNic!\n"));
818
0
        }
819
0
    } else {
820
0
        DEBUGMSGTL(("snmpv3",
821
0
                    "NOT setting engineIDNic, engineID already set\n"));
822
0
    }
823
0
}
824
825
/*******************************************************************-o-******
826
 * engineID_conf
827
 *
828
 * Parameters:
829
 *  *word
830
 *  *cptr
831
 *
832
 * This function reads a string from the configuration file and uses that
833
 * string to initialize the engineID.  It's assumed to be human readable.
834
 */
835
void
836
engineID_conf(const char *word, char *cptr)
837
0
{
838
0
    setup_engineID(NULL, cptr);
839
0
    DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr));
840
0
}
841
842
void
843
version_conf(const char *word, char *cptr)
844
234
{
845
234
    int valid = 0;
846
234
#ifndef NETSNMP_DISABLE_SNMPV1
847
234
    if ((strcmp(cptr,  "1") == 0) ||
848
199
        (strcmp(cptr, "v1") == 0)) {
849
45
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
850
45
         NETSNMP_DS_SNMP_VERSION_1);       /* bogus value */
851
45
        valid = 1;
852
45
    }
853
234
#endif
854
234
#ifndef NETSNMP_DISABLE_SNMPV2C
855
234
    if ((strcasecmp(cptr,  "2c") == 0) ||
856
214
               (strcasecmp(cptr, "v2c") == 0)) {
857
30
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
858
30
         NETSNMP_DS_SNMP_VERSION_2c);
859
30
        valid = 1;
860
30
    }
861
234
#endif
862
234
    if ((strcasecmp(cptr,  "3" ) == 0) ||
863
216
               (strcasecmp(cptr, "v3" ) == 0)) {
864
36
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
865
36
         NETSNMP_DS_SNMP_VERSION_3);
866
36
        valid = 1;
867
36
    }
868
234
    if (!valid) {
869
123
        config_perror("Unknown version specification");
870
123
        return;
871
123
    }
872
111
    DEBUGMSGTL(("snmpv3", "set default version to %d\n",
873
111
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
874
111
           NETSNMP_DS_LIB_SNMPVERSION)));
875
111
}
876
877
/*
878
 * oldengineID_conf(const char *, char *):
879
 * 
880
 * Reads a octet string encoded engineID into the oldEngineID and
881
 * oldEngineIDLen pointers.
882
 */
883
void
884
oldengineID_conf(const char *word, char *cptr)
885
3.34k
{
886
3.34k
    unsigned char *EngineID = NULL;
887
3.34k
    size_t         EngineIDLength = 0;
888
889
3.34k
    read_config_read_octet_string(cptr, &EngineID, &EngineIDLength);
890
3.34k
    if (EngineIDLength < 4) {
891
0
        config_perror("Invalid oldEngineID");
892
0
        free(EngineID);
893
0
        return;
894
0
    }
895
3.34k
    free(oldEngineID);
896
3.34k
    oldEngineID = EngineID;
897
3.34k
    oldEngineIDLength = EngineIDLength;
898
3.34k
}
899
900
/*
901
 * set_exact_engineID_conf(const oid *, size_t):
902
 *
903
 * Specifies an exact engineID OID.
904
 */
905
int
906
set_exact_engineID(const u_char *id, size_t len)
907
0
{
908
0
    int rc = SNMPERR_SUCCESS;
909
0
    u_char *newID = NULL;
910
911
0
    if (NULL == id || 0 == len)
912
0
        return SNMPERR_GENERR;
913
914
0
    if (len > MAX_ENGINEID_LENGTH)
915
0
        return SNMPERR_TOO_LONG;
916
917
0
    newID = malloc(len+1);
918
0
    if (NULL == newID) {
919
0
        snmp_log(LOG_ERR, "malloc failed for engineID\n");
920
0
        return SNMPERR_GENERR;
921
0
    }
922
0
    if (NULL != engineID)
923
0
        free(engineID);
924
925
0
    memcpy(newID, id, len);
926
0
    newID[len] = 0;
927
928
0
    engineID = newID;
929
0
    engineIDLength = len;
930
0
    engineIDIsSet = 1;
931
0
    engineIDType = ENGINEID_TYPE_EXACT;
932
933
0
    return rc;
934
0
}
935
936
/*
937
 * exactEngineID_conf(const char *, char *):
938
 * 
939
 * Reads a octet string encoded engineID into the engineID and
940
 * engineIDLen pointers.
941
 */
942
void
943
exactEngineID_conf(const char *word, char *cptr)
944
0
{
945
    /** we want buf > max so we know if there is truncation */
946
0
    u_char new_engineID[MAX_ENGINEID_LENGTH+2],
947
0
        *new_engineIDptr = new_engineID;
948
0
    size_t new_engineIDLength = sizeof(new_engineID);
949
950
0
    read_config_read_octet_string(cptr, &new_engineIDptr, &new_engineIDLength);
951
0
    if (new_engineIDLength > MAX_ENGINEID_LENGTH) {
952
0
        new_engineIDLength = MAX_ENGINEID_LENGTH;
953
0
  netsnmp_config_error(
954
0
      "exactEngineID '%s' too long; truncating to %d bytes",
955
0
      cptr, MAX_ENGINEID_LENGTH);
956
0
    }
957
958
0
    set_exact_engineID( new_engineIDptr, new_engineIDLength);
959
0
}
960
961
962
/*
963
 * merely call 
964
 */
965
netsnmp_feature_child_of(get_enginetime_alarm, netsnmp_unused);
966
#ifndef NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM
967
void
968
get_enginetime_alarm(unsigned int regnum, void *clientargs)
969
0
{
970
    /* we do this every so (rarely) often just to make sure we watch
971
       wrapping of the times() output */
972
0
    snmpv3_local_snmpEngineTime();
973
0
}
974
#endif /* NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM */
975
976
/*******************************************************************-o-******
977
 * init_snmpv3
978
 *
979
 * Parameters:
980
 *  *type Label for the config file "type" used by calling entity.
981
 *      
982
 * Set time and engineID.
983
 * Set parsing functions for config file tokens.
984
 * Initialize SNMP Crypto API (SCAPI).
985
 */
986
void
987
init_snmpv3(const char *type)
988
3.40k
{
989
3.40k
    netsnmp_get_monotonic_clock(&snmpv3starttime);
990
991
3.40k
    if (!type)
992
0
        type = "__snmpapp__";
993
994
    /*
995
     * we need to be called back later 
996
     */
997
3.40k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
998
3.40k
                           SNMP_CALLBACK_POST_READ_CONFIG,
999
3.40k
                           init_snmpv3_post_config, NULL);
1000
1001
3.40k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1002
3.40k
                           SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
1003
3.40k
                           init_snmpv3_post_premib_config, NULL);
1004
    /*
1005
     * we need to be called back later 
1006
     */
1007
3.40k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
1008
3.40k
                           snmpv3_store, (void *) strdup(type));
1009
1010
    /*
1011
     * initialize submodules 
1012
     */
1013
    /*
1014
     * NOTE: this must be after the callbacks are registered above,
1015
     * since they need to be called before the USM callbacks. 
1016
     */
1017
3.40k
    init_secmod();
1018
1019
    /*
1020
     * register all our configuration handlers (ack, there's a lot) 
1021
     */
1022
1023
    /*
1024
     * handle engineID setup before everything else which may depend on it 
1025
     */
1026
3.40k
    register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
1027
3.40k
                                    "string");
1028
3.40k
    register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
1029
3.40k
                                    NULL, NULL);
1030
3.40k
    register_prenetsnmp_mib_handler(type, "exactEngineID", exactEngineID_conf,
1031
3.40k
                                    NULL, NULL);
1032
3.40k
    register_prenetsnmp_mib_handler(type, "engineIDType",
1033
3.40k
                                    engineIDType_conf, NULL, "num");
1034
3.40k
    register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
1035
3.40k
                                    NULL, "string");
1036
3.40k
    register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
1037
3.40k
                            NULL);
1038
1039
    /*
1040
     * default store config entries 
1041
     */
1042
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
1043
3.40k
             NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
1044
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext", 
1045
3.40k
             NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
1046
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
1047
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1048
3.40k
                               NETSNMP_DS_LIB_PASSPHRASE);
1049
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
1050
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1051
3.40k
                               NETSNMP_DS_LIB_AUTHPASSPHRASE);
1052
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
1053
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1054
3.40k
                               NETSNMP_DS_LIB_PRIVPASSPHRASE);
1055
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
1056
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1057
3.40k
                               NETSNMP_DS_LIB_AUTHMASTERKEY);
1058
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
1059
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1060
3.40k
                               NETSNMP_DS_LIB_PRIVMASTERKEY);
1061
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
1062
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1063
3.40k
                               NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
1064
3.40k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
1065
3.40k
                               NETSNMP_DS_LIBRARY_ID,
1066
3.40k
                               NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
1067
3.40k
    register_config_handler("snmp", "defVersion", version_conf, NULL,
1068
3.40k
                            "1|2c|3");
1069
1070
3.40k
    register_config_handler("snmp", "defSecurityLevel",
1071
3.40k
                            snmpv3_secLevel_conf, NULL,
1072
3.40k
                            "noAuthNoPriv|authNoPriv|authPriv");
1073
3.40k
}
1074
1075
/*
1076
 * initializations for SNMPv3 to be called after the configuration files
1077
 * have been read.
1078
 */
1079
1080
int
1081
init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
1082
                        void *clientarg)
1083
3.40k
{
1084
1085
3.40k
    size_t          engineIDLen;
1086
3.40k
    u_char         *c_engineID;
1087
3.40k
    u_long          localEngineTime;
1088
3.40k
    u_long          localEngineBoots;
1089
1090
3.40k
    c_engineID = snmpv3_generate_engineID(&engineIDLen);
1091
1092
3.40k
    if (!c_engineID || engineIDLen == 0) {
1093
        /*
1094
         * Something went wrong - help! 
1095
         */
1096
0
        SNMP_FREE(c_engineID);
1097
0
        return SNMPERR_GENERR;
1098
0
    }
1099
1100
    /*
1101
     * if our engineID has changed at all, the boots record must be set to 1 
1102
     */
1103
3.40k
    if (engineIDLen != oldEngineIDLength ||
1104
3.34k
        oldEngineID == NULL || c_engineID == NULL ||
1105
3.34k
        memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
1106
59
        engineBoots = 1;
1107
59
    }
1108
1109
3.40k
#ifdef NETSNMP_SECMOD_USM
1110
    /*
1111
     * for USM set our local engineTime in the LCD timing cache 
1112
     */
1113
3.40k
    localEngineTime = snmpv3_local_snmpEngineTime();
1114
3.40k
    localEngineBoots = snmpv3_local_snmpEngineBoots();
1115
3.40k
    set_enginetime(c_engineID, engineIDLen,
1116
3.40k
                   localEngineBoots,
1117
3.40k
                   localEngineTime, TRUE);
1118
3.40k
#endif /* NETSNMP_SECMOD_USM */
1119
1120
3.40k
    SNMP_FREE(c_engineID);
1121
3.40k
    return SNMPERR_SUCCESS;
1122
3.40k
}
1123
1124
int
1125
init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
1126
                               void *clientarg)
1127
3.40k
{
1128
3.40k
    if (!engineIDIsSet)
1129
3.40k
        setup_engineID(NULL, NULL);
1130
1131
3.40k
    return SNMPERR_SUCCESS;
1132
3.40k
}
1133
1134
/*******************************************************************-o-******
1135
 * store_snmpv3
1136
 *
1137
 * Parameters:
1138
 *  *type
1139
 */
1140
int
1141
snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
1142
3.40k
{
1143
3.40k
    char            line[SNMP_MAXBUF_SMALL];
1144
3.40k
    u_char          c_engineID[SNMP_MAXBUF_SMALL];
1145
3.40k
    int             engineIDLen;
1146
3.40k
    const char     *type = (const char *) clientarg;
1147
1148
3.40k
    if (type == NULL)           /* should never happen, since the arg is ours */
1149
0
        type = "unknown";
1150
1151
3.40k
    sprintf(line, "engineBoots %ld", engineBoots);
1152
3.40k
    read_config_store(type, line);
1153
1154
3.40k
    engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
1155
1156
3.40k
    if (engineIDLen) {
1157
        /*
1158
         * store the engineID used for this run 
1159
         */
1160
3.40k
        sprintf(line, "oldEngineID ");
1161
3.40k
        read_config_save_octet_string(line + strlen(line), c_engineID,
1162
3.40k
                                      engineIDLen);
1163
3.40k
        read_config_store(type, line);
1164
3.40k
    }
1165
3.40k
    return SNMPERR_SUCCESS;
1166
3.40k
}                               /* snmpv3_store() */
1167
1168
u_long
1169
snmpv3_local_snmpEngineBoots(void)
1170
3.40k
{
1171
3.40k
    return engineBoots;
1172
3.40k
}
1173
1174
1175
/*******************************************************************-o-******
1176
 * snmpv3_get_engineID
1177
 *
1178
 * Parameters:
1179
 *  *buf
1180
 *   buflen
1181
 *      
1182
 * Returns:
1183
 *  Length of engineID  On Success
1184
 *  SNMPERR_GENERR    Otherwise.
1185
 *
1186
 *
1187
 * Store engineID in buf; return the length.
1188
 *
1189
 */
1190
size_t
1191
snmpv3_get_engineID(u_char * buf, size_t buflen)
1192
13.6k
{
1193
    /*
1194
     * Sanity check.
1195
     */
1196
13.6k
    if (!buf || (buflen < engineIDLength)) {
1197
0
        return 0;
1198
0
    }
1199
13.6k
    if (!engineID) {
1200
3.41k
        return 0;
1201
3.41k
    }
1202
1203
10.2k
    memcpy(buf, engineID, engineIDLength);
1204
10.2k
    return engineIDLength;
1205
1206
13.6k
}                               /* end snmpv3_get_engineID() */
1207
1208
/*******************************************************************-o-******
1209
 * snmpv3_clone_engineID
1210
 *
1211
 * Parameters:
1212
 *  **dest
1213
 *       *dest_len
1214
 *       src
1215
 *   srclen
1216
 *      
1217
 * Returns:
1218
 *  Length of engineID  On Success
1219
 *  0           Otherwise.
1220
 *
1221
 *
1222
 * Clones engineID, creates memory
1223
 *
1224
 */
1225
int
1226
snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
1227
                      size_t srclen)
1228
0
{
1229
0
    if (!dest || !destlen)
1230
0
        return 0;
1231
1232
0
    SNMP_FREE(*dest);
1233
0
    *destlen = 0;
1234
1235
0
    if (srclen && src) {
1236
0
        *dest = netsnmp_memdup(src, srclen);
1237
0
        if (*dest == NULL)
1238
0
            return 0;
1239
0
        *destlen = srclen;
1240
0
    }
1241
0
    return *destlen;
1242
0
}                               /* end snmpv3_clone_engineID() */
1243
1244
1245
/*******************************************************************-o-******
1246
 * snmpv3_generate_engineID
1247
 *
1248
 * Parameters:
1249
 *  *length
1250
 *      
1251
 * Returns:
1252
 *  Pointer to copy of engineID On Success.
1253
 *  NULL        If malloc() or snmpv3_get_engineID()
1254
 *            fail.
1255
 *
1256
 * Generates a malloced copy of our engineID.
1257
 *
1258
 * 'length' is set to the length of engineID  -OR-  < 0 on failure.
1259
 */
1260
u_char         *
1261
snmpv3_generate_engineID(size_t * length)
1262
6.84k
{
1263
6.84k
    u_char         *newID;
1264
6.84k
    newID = (u_char *) malloc(engineIDLength);
1265
1266
6.84k
    if (newID) {
1267
6.84k
        *length = snmpv3_get_engineID(newID, engineIDLength);
1268
6.84k
        if (*length == 0) {
1269
10
            SNMP_FREE(newID);
1270
10
            newID = NULL;
1271
10
        }
1272
6.84k
    }
1273
6.84k
    return newID;
1274
1275
6.84k
}                               /* end snmpv3_generate_engineID() */
1276
1277
/**
1278
 * Return the value of snmpEngineTime. According to RFC 3414 snmpEngineTime
1279
 * is a 31-bit counter. engineBoots must be incremented every time that
1280
 * counter wraps around.
1281
 *
1282
 * @see See also <a href="http://tools.ietf.org/html/rfc3414">RFC 3414</a>.
1283
 *
1284
 * @note It is assumed that this function is called at least once every
1285
 *   2**31 seconds.
1286
 */
1287
u_long
1288
snmpv3_local_snmpEngineTime(void)
1289
6.82k
{
1290
#ifdef NETSNMP_FEATURE_CHECKING
1291
    netsnmp_feature_require(calculate_sectime_diff)
1292
#endif /* NETSNMP_FEATURE_CHECKING */
1293
1294
6.82k
    static uint32_t last_engineTime;
1295
6.82k
    struct timeval  now;
1296
6.82k
    uint32_t engineTime;
1297
1298
6.82k
    netsnmp_get_monotonic_clock(&now);
1299
6.82k
    engineTime = calculate_sectime_diff(&now, &snmpv3starttime) & 0x7fffffffL;
1300
6.82k
    if (engineTime < last_engineTime)
1301
0
        engineBoots++;
1302
6.82k
    last_engineTime = engineTime;
1303
6.82k
    return engineTime;
1304
6.82k
}
1305
1306
1307
1308
/*
1309
 * Code only for Linux systems 
1310
 */
1311
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
1312
static int
1313
getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
1314
             char *addressOut)
1315
0
{                               /* return address. Len=IFHWADDRLEN */
1316
    /*
1317
     * getHwAddress(...)
1318
     * *
1319
     * *  This function will return a Network Interfaces Card's Hardware
1320
     * *  address (aka MAC address).
1321
     * *
1322
     * *  Input Parameter(s):
1323
     * *      networkDevice - a null terminated string with the name of a network
1324
     * *                      device.  Examples: eth0, eth1, etc...
1325
     * *
1326
     * *  Output Parameter(s):
1327
     * *      addressOut -    This is the binary value of the hardware address.
1328
     * *                      This value is NOT converted into a hexadecimal string.
1329
     * *                      The caller must pre-allocate for a return value of
1330
     * *                      length IFHWADDRLEN
1331
     * *
1332
     * *  Return value:   This function will return zero (0) for success.  If
1333
     * *                  an error occurred the function will return -1.
1334
     * *
1335
     * *  Caveats:    This has only been tested on Ethernet networking cards.
1336
     */
1337
0
    NETSNMP_SOCKET  sock;       /* our socket */
1338
0
    struct ifreq    request;    /* struct which will have HW address */
1339
1340
0
    if ((NULL == networkDevice) || (NULL == addressOut)) {
1341
0
        return -1;
1342
0
    }
1343
    /*
1344
     * In order to find out the hardware (MAC) address of our system under
1345
     * * Linux we must do the following:
1346
     * * 1.  Create a socket
1347
     * * 2.  Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
1348
     */
1349
0
    sock = socket(AF_INET, SOCK_DGRAM, 0);
1350
0
    if (!NETSNMP_IS_VALID_SOCKET(sock)) {
1351
0
        return -1;
1352
0
    }
1353
    /*
1354
     * erase the request block 
1355
     */
1356
0
    memset(&request, 0, sizeof(request));
1357
    /*
1358
     * copy the name of the net device we want to find the HW address for 
1359
     */
1360
0
    strlcpy(request.ifr_name, networkDevice, IFNAMSIZ);
1361
    /*
1362
     * Get the HW address 
1363
     */
1364
0
    if (ioctl(sock, SIOCGIFHWADDR, &request)) {
1365
0
        close(sock);
1366
0
        return -1;
1367
0
    }
1368
0
    close(sock);
1369
0
    memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
1370
0
    return 0;
1371
0
}
1372
#endif
1373
1374
#ifdef NETSNMP_ENABLE_TESTING_CODE
1375
/**
1376
 * Set SNMPv3 engineBoots and start time.
1377
 *
1378
 * @note This function does not exist. Go away. It certainly should never be
1379
 *   used, unless in a testing scenario, which is why it was created
1380
 */
1381
void
1382
snmpv3_set_engineBootsAndTime(int boots, int ttime)
1383
{
1384
    engineBoots = boots;
1385
    netsnmp_get_monotonic_clock(&snmpv3starttime);
1386
    snmpv3starttime.tv_sec -= ttime;
1387
}
1388
#endif