Coverage Report

Created: 2025-07-23 06:49

/src/net-snmp/snmplib/snmpv3.c
Line
Count
Source (jump to first uncovered line)
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
345
parse_secLevel_conf(const char *word, char *cptr) {
115
345
    if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
116
345
  strcasecmp(cptr, "nanp") == 0) {
117
14
        return SNMP_SEC_LEVEL_NOAUTH;
118
331
    } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
119
331
         strcasecmp(cptr, "anp") == 0) {
120
30
        return SNMP_SEC_LEVEL_AUTHNOPRIV;
121
301
    } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
122
301
         strcasecmp(cptr, "ap") == 0) {
123
26
        return SNMP_SEC_LEVEL_AUTHPRIV;
124
275
    } else {
125
275
        return -1;
126
275
    }
127
345
}
128
129
void
130
snmpv3_secLevel_conf(const char *word, char *cptr)
131
345
{
132
345
    int             secLevel;
133
134
345
    if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) {
135
70
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
136
70
         NETSNMP_DS_LIB_SECLEVEL, secLevel);
137
275
    } else {
138
275
  netsnmp_config_error("Unknown security level: %s", cptr);
139
275
    }
140
345
    DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
141
345
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
142
345
           NETSNMP_DS_LIB_SECLEVEL)));
143
345
}
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.11k
{
150
1.11k
    int        priv_type;
151
1.11k
    char      *cp;
152
1.11k
    int        zero_sensitive = !( flags & NETSNMP_PARSE_ARGS_NOZERO );
153
154
1.11k
    switch (arg) {
155
156
39
    case 'Z':
157
39
        errno=0;
158
39
        session->engineBoots = strtoul(optarg, &cp, 10);
159
39
        if (errno || cp == optarg) {
160
2
            fprintf(stderr, "Need engine boots value after -3Z flag.\n");
161
2
            return (-1);
162
2
        }
163
37
        if (*cp == ',') {
164
12
            char *endptr;
165
12
            cp++;
166
12
            session->engineTime = strtoul(cp, &endptr, 10);
167
12
            if (errno || cp == endptr) {
168
2
                fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
169
2
                return (-1);
170
2
            }
171
12
        }
172
        /*
173
         * Handle previous '-Z boot time' syntax
174
         */
175
25
        else if (optind < argc) {
176
17
            session->engineTime = strtoul(argv[optind], &cp, 10);
177
17
            if (errno || cp == argv[optind]) {
178
6
                fprintf(stderr, "Need engine time after \"-Z engineBoot\".\n");
179
6
                return (-1);
180
6
            }
181
17
        } else {
182
8
            fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
183
8
            return (-1);
184
8
        }
185
21
        break;
186
187
68
    case 'e':{
188
68
            size_t          ebuf_len = 32, eout_len = 0;
189
68
            u_char         *ebuf = (u_char *) malloc(ebuf_len);
190
191
68
            if (ebuf == NULL) {
192
0
                fprintf(stderr, "malloc failure processing -3e flag.\n");
193
0
                return (-1);
194
0
            }
195
68
            if (!snmp_hex_to_binary
196
68
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
197
26
                fprintf(stderr, "Bad engine ID value after -3e flag.\n");
198
26
                SNMP_FREE(ebuf);
199
26
                return (-1);
200
26
            }
201
42
            if ((eout_len < 5) || (eout_len > 32)) {
202
6
                fprintf(stderr, "Invalid engine ID value after -e flag.\n");
203
6
                free(ebuf);
204
6
                return (-1);
205
6
            }
206
36
      free(session->securityEngineID);
207
36
            session->securityEngineID = ebuf;
208
36
            session->securityEngineIDLen = eout_len;
209
36
            break;
210
42
        }
211
212
22
    case 'E':{
213
22
            size_t          ebuf_len = 32, eout_len = 0;
214
22
            u_char         *ebuf = (u_char *) malloc(ebuf_len);
215
216
22
            if (ebuf == NULL) {
217
0
                fprintf(stderr, "malloc failure processing -3E flag.\n");
218
0
                return (-1);
219
0
            }
220
22
            if (!snmp_hex_to_binary
221
22
                (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
222
7
                fprintf(stderr, "Bad engine ID value after -3E flag.\n");
223
7
                SNMP_FREE(ebuf);
224
7
                return (-1);
225
7
            }
226
15
            if ((eout_len < 5) || (eout_len > 32)) {
227
3
                fprintf(stderr, "Invalid engine ID value after -E flag.\n");
228
3
                free(ebuf);
229
3
                return (-1);
230
3
            }
231
12
      free(session->contextEngineID);
232
12
            session->contextEngineID = ebuf;
233
12
            session->contextEngineIDLen = eout_len;
234
12
            break;
235
15
        }
236
237
35
    case 'n':
238
35
        free(session->contextName);
239
35
        session->contextName = strdup(optarg);
240
35
        session->contextNameLen = strlen(optarg);
241
35
        break;
242
243
85
    case 'u':
244
85
        free(session->securityName);
245
85
        session->securityName = strdup(optarg);
246
85
        session->securityNameLen = strlen(optarg);
247
85
        break;
248
249
465
    case 'l':
250
465
        if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
251
465
            !strcasecmp(optarg, "noauth") || !strcasecmp(optarg, "nanp")) {
252
74
            session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
253
391
        } else if (!strcasecmp(optarg, "authNoPriv")
254
391
                   || !strcasecmp(optarg, "auth")
255
391
                   || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
256
53
            session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
257
338
        } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
258
338
                   || !strcasecmp(optarg, "priv")
259
338
                   || !strcasecmp(optarg, "ap")) {
260
30
            session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
261
308
        } else {
262
308
            fprintf(stderr,
263
308
                    "Invalid security level specified after -3l flag: %s\n",
264
308
                    optarg);
265
308
            return (-1);
266
308
        }
267
157
        break;
268
269
157
#ifdef NETSNMP_SECMOD_USM
270
157
    case 'a': {
271
80
        int auth_type = usm_lookup_auth_type(optarg);
272
80
        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
40
            fprintf(stderr,
282
40
                    "Invalid authentication protocol specified after -3a flag: %s\n",
283
40
                    optarg);
284
40
            return (-1);
285
40
        }
286
80
    }
287
40
        break;
288
289
77
    case 'x': {
290
77
        const oid *priv_proto;
291
292
77
        priv_type = usm_lookup_priv_type(optarg);
293
77
        if (priv_type < 0) {
294
57
            fprintf(stderr,
295
57
                    "Invalid privacy protocol specified after -3x flag: %s\n",
296
57
                    optarg);
297
57
            return (-1);
298
57
        }
299
20
        priv_proto = sc_get_priv_oid(priv_type, &session->securityPrivProtoLen);
300
20
        free(session->securityPrivProto);
301
20
        session->securityPrivProto = snmp_duplicate_objid(priv_proto,
302
20
                                         session->securityPrivProtoLen);
303
20
        break;
304
77
    }
305
72
    case 'A':
306
72
        if (*Apsz && zero_sensitive) {
307
44
            memset(*Apsz, 0x0, strlen(*Apsz));
308
44
        }
309
72
        free(*Apsz);
310
72
        *Apsz = strdup(optarg);
311
72
        if (NULL == *Apsz) {
312
0
            fprintf(stderr, "malloc failure processing -%c flag.\n",
313
0
                    (char)arg);
314
0
            return -1;
315
0
        }
316
72
        if (zero_sensitive)
317
72
            memset(optarg, 0x0, strlen(optarg));
318
72
        break;
319
320
111
    case 'X':
321
111
        if (*Xpsz && zero_sensitive) {
322
84
            memset(*Xpsz, 0x0, strlen(*Xpsz));
323
84
        }
324
111
        free(*Xpsz);
325
111
        *Xpsz = strdup(optarg);
326
111
        if (NULL == *Xpsz) {
327
0
            fprintf(stderr, "malloc failure processing -%c flag.\n",
328
0
                    (char)arg);
329
0
            return -1;
330
0
        }
331
111
        if (zero_sensitive)
332
111
            memset(optarg, 0x0, strlen(optarg));
333
111
        break;
334
0
#endif /* NETSNMP_SECMOD_USM */
335
336
19
    case 'm': {
337
19
        size_t bufSize = sizeof(session->securityAuthKey);
338
19
        u_char *tmpp = session->securityAuthKey;
339
19
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
340
19
                                &session->securityAuthKeyLen, 0, optarg)) {
341
3
            fprintf(stderr, "Bad key value after -3m flag.\n");
342
3
            return (-1);
343
3
        }
344
16
        break;
345
19
    }
346
347
16
    case 'M': {
348
11
        size_t bufSize = sizeof(session->securityPrivKey);
349
11
        u_char *tmpp = session->securityPrivKey;
350
11
        if (!snmp_hex_to_binary(&tmpp, &bufSize,
351
11
             &session->securityPrivKeyLen, 0, optarg)) {
352
1
            fprintf(stderr, "Bad key value after -3M flag.\n");
353
1
            return (-1);
354
1
        }
355
10
        break;
356
11
    }
357
358
12
    case 'k': {
359
12
        size_t          kbuf_len = 32, kout_len = 0;
360
12
        u_char         *kbuf = (u_char *) malloc(kbuf_len);
361
362
12
        if (kbuf == NULL) {
363
0
            fprintf(stderr, "malloc failure processing -3k flag.\n");
364
0
            return (-1);
365
0
        }
366
12
        if (!snmp_hex_to_binary
367
12
            (&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
11
        free(session->securityAuthLocalKey);
373
11
        session->securityAuthLocalKey = kbuf;
374
11
        session->securityAuthLocalKeyLen = kout_len;
375
11
        break;
376
12
    }
377
378
15
    case 'K': {
379
15
        size_t          kbuf_len = 32, kout_len = 0;
380
15
        u_char         *kbuf = (u_char *) malloc(kbuf_len);
381
382
15
        if (kbuf == NULL) {
383
0
            fprintf(stderr, "malloc failure processing -3K flag.\n");
384
0
            return (-1);
385
0
        }
386
15
        if (!snmp_hex_to_binary
387
15
            (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
388
3
            fprintf(stderr, "Bad key value after -3K flag.\n");
389
3
            SNMP_FREE(kbuf);
390
3
            return (-1);
391
3
        }
392
12
        free(session->securityPrivLocalKey);
393
12
        session->securityPrivLocalKey = kbuf;
394
12
        session->securityPrivLocalKeyLen = kout_len;
395
12
        break;
396
15
    }
397
        
398
6
    default:
399
6
        fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", arg);
400
6
        return -1;
401
1.11k
    }
402
638
    return 0;
403
1.11k
}
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
71
{
409
71
    char           *cp = optarg;
410
71
    optarg++;
411
    /*
412
     * Support '... -3x=value ....' syntax
413
     */
414
71
    if (*optarg == '=') {
415
3
        optarg++;
416
3
    }
417
    /*
418
     * and '.... "-3x value" ....'  (*with* the quotes)
419
     */
420
316
    while (*optarg && isspace((unsigned char)(*optarg))) {
421
245
        optarg++;
422
245
    }
423
    /*
424
     * Finally, handle ".... -3x value ...." syntax
425
     *   (*without* surrounding quotes)
426
     */
427
71
    if (!*optarg) {
428
        /*
429
         * We've run off the end of the argument
430
         *  so move on the the next.
431
         */
432
31
        if (optind >= argc) {
433
4
            fprintf(stderr,
434
4
                    "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
435
4
            return (-1);
436
4
        }
437
27
        optarg = argv[optind++];
438
27
    }
439
440
67
    return snmpv3_parse_arg(*cp, optarg, session, Apsz, Xpsz, argc, argv,
441
67
                            flags);
442
71
}
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.39k
{
472
3.39k
    int             enterpriseid = htonl(NETSNMP_ENTERPRISE_OID),
473
3.39k
        netsnmpoid = htonl(NETSNMP_OID),
474
3.39k
        localsetup = (eidp) ? 0 : 1;
475
476
    /*
477
     * Use local engineID if *eidp == NULL.  
478
     */
479
3.39k
#ifdef HAVE_GETHOSTNAME
480
3.39k
    u_char          buf[SNMP_MAXBUF_SMALL];
481
3.39k
    struct hostent *hent = NULL;
482
3.39k
#endif
483
3.39k
    u_char         *bufp = NULL;
484
3.39k
    size_t          len;
485
3.39k
    int             localEngineIDType = engineIDType;
486
3.39k
    int             tmpint;
487
3.39k
    time_t          tmptime;
488
489
3.39k
    engineIDIsSet = 1;
490
491
3.39k
#ifdef HAVE_GETHOSTNAME
492
3.39k
#ifdef AF_INET6
493
    /*
494
     * see if they selected IPV4 or IPV6 support 
495
     */
496
3.39k
    if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
497
3.39k
        (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.39k
#endif                          /* HAVE_GETHOSTNAME */
529
530
    /*
531
     * Determine if we have text and if so setup our localEngineIDType
532
     * * appropriately.  
533
     */
534
3.39k
    if (NULL != text) {
535
0
        engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
536
0
    }
537
    /*
538
     * Determine length of the engineID string. 
539
     */
540
3.39k
    len = 5;                    /* always have 5 leading bytes */
541
3.39k
    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.39k
    case ENGINEID_TYPE_NETSNMP_RND:        /* Net-SNMP specific encoding */
562
3.39k
        if (engineID)           /* already setup, keep current value */
563
0
            return engineIDLength;
564
3.39k
        if (oldEngineID) {
565
3.39k
            len = oldEngineIDLength;
566
3.39k
        } else {
567
3
            len += sizeof(int) + sizeof(time_t);
568
3
        }
569
3.39k
        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.39k
    }                           /* switch */
578
579
580
    /*
581
     * Allocate memory and store enterprise ID.
582
     */
583
3.39k
    if (len == 0) {
584
0
        snmp_log(LOG_ERR, "%s(): len == 0\n", __func__);
585
0
        return -1;
586
0
    }
587
3.39k
    bufp = calloc(1, len);
588
3.39k
    if (bufp == NULL) {
589
0
        snmp_log_perror("setup_engineID() calloc()");
590
0
        return -1;
591
0
    }
592
3.39k
    if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
593
        /*
594
         * we must use the net-snmp enterprise id here, regardless 
595
         */
596
3.39k
        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.39k
    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.39k
    switch (localEngineIDType) {
609
3.39k
    case ENGINEID_TYPE_NETSNMP_RND:
610
3.39k
        if (oldEngineID) {
611
            /*
612
             * keep our previous notion of the engineID 
613
             */
614
3.39k
            memcpy(bufp, oldEngineID, oldEngineIDLength);
615
3.39k
        } 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
3
            bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
628
3
            tmpint = netsnmp_random();
629
3
            memcpy(bufp + 5, &tmpint, sizeof(tmpint));
630
3
            tmptime = time(NULL);
631
3
            memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
632
3
        }
633
3.39k
        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.39k
    }
694
695
    /*
696
     * Pass the string back to the calling environment, or use it for
697
     * our local engineID.
698
     */
699
3.39k
    if (localsetup) {
700
3.39k
        SNMP_FREE(engineID);
701
3.39k
        engineID = bufp;
702
3.39k
        engineIDLength = len;
703
704
3.39k
    } else {
705
0
        *eidp = bufp;
706
0
    }
707
708
709
3.39k
    return len;
710
711
3.39k
}                               /* end setup_engineID() */
712
713
int
714
free_engineID(int majorid, int minorid, void *serverarg,
715
        void *clientarg)
716
3.39k
{
717
3.39k
    SNMP_FREE(engineID);
718
3.39k
    SNMP_FREE(engineIDNic);
719
3.39k
    SNMP_FREE(oldEngineID);
720
3.39k
    engineIDIsSet = 0;
721
3.39k
    return 0;
722
3.39k
}
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.40k
{
737
3.40k
    engineBoots = atoi(cptr) + 1;
738
3.40k
    DEBUGMSGTL(("snmpv3", "engineBoots: %lu\n", engineBoots));
739
3.40k
}
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
127
{
845
127
    int valid = 0;
846
127
#ifndef NETSNMP_DISABLE_SNMPV1
847
127
    if ((strcmp(cptr,  "1") == 0) ||
848
127
        (strcmp(cptr, "v1") == 0)) {
849
20
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
850
20
         NETSNMP_DS_SNMP_VERSION_1);       /* bogus value */
851
20
        valid = 1;
852
20
    }
853
127
#endif
854
127
#ifndef NETSNMP_DISABLE_SNMPV2C
855
127
    if ((strcasecmp(cptr,  "2c") == 0) ||
856
127
               (strcasecmp(cptr, "v2c") == 0)) {
857
13
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
858
13
         NETSNMP_DS_SNMP_VERSION_2c);
859
13
        valid = 1;
860
13
    }
861
127
#endif
862
127
    if ((strcasecmp(cptr,  "3" ) == 0) ||
863
127
               (strcasecmp(cptr, "v3" ) == 0)) {
864
21
        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 
865
21
         NETSNMP_DS_SNMP_VERSION_3);
866
21
        valid = 1;
867
21
    }
868
127
    if (!valid) {
869
73
        config_perror("Unknown version specification");
870
73
        return;
871
73
    }
872
54
    DEBUGMSGTL(("snmpv3", "set default version to %d\n",
873
54
                netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
874
54
           NETSNMP_DS_LIB_SNMPVERSION)));
875
54
}
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.39k
{
886
3.39k
    unsigned char *EngineID = NULL;
887
3.39k
    size_t         EngineIDLength = 0;
888
889
3.39k
    if (oldEngineID) {
890
0
        free(oldEngineID);
891
0
        oldEngineID = NULL;
892
0
        oldEngineIDLength = 0;
893
0
    }
894
895
3.39k
    read_config_read_octet_string(cptr, &EngineID, &EngineIDLength);
896
3.39k
    if (EngineIDLength < 4) {
897
0
        config_perror("Invalid oldEngineID");
898
0
        free(EngineID);
899
0
        return;
900
0
    }
901
3.39k
    oldEngineID = EngineID;
902
3.39k
    oldEngineIDLength = EngineIDLength;
903
3.39k
}
904
905
/*
906
 * set_exact_engineID_conf(const oid *, size_t):
907
 *
908
 * Specifies an exact engineID OID.
909
 */
910
int
911
set_exact_engineID(const u_char *id, size_t len)
912
0
{
913
0
    int rc = SNMPERR_SUCCESS;
914
0
    u_char *newID = NULL;
915
916
0
    if (NULL == id || 0 == len)
917
0
        return SNMPERR_GENERR;
918
919
0
    if (len > MAX_ENGINEID_LENGTH)
920
0
        return SNMPERR_TOO_LONG;
921
922
0
    newID = malloc(len+1);
923
0
    if (NULL == newID) {
924
0
        snmp_log(LOG_ERR, "malloc failed for engineID\n");
925
0
        return SNMPERR_GENERR;
926
0
    }
927
0
    if (NULL != engineID)
928
0
        free(engineID);
929
930
0
    memcpy(newID, id, len);
931
0
    newID[len] = 0;
932
933
0
    engineID = newID;
934
0
    engineIDLength = len;
935
0
    engineIDIsSet = 1;
936
0
    engineIDType = ENGINEID_TYPE_EXACT;
937
938
0
    return rc;
939
0
}
940
941
/*
942
 * exactEngineID_conf(const char *, char *):
943
 * 
944
 * Reads a octet string encoded engineID into the engineID and
945
 * engineIDLen pointers.
946
 */
947
void
948
exactEngineID_conf(const char *word, char *cptr)
949
0
{
950
    /** we want buf > max so we know if there is truncation */
951
0
    u_char new_engineID[MAX_ENGINEID_LENGTH+2],
952
0
        *new_engineIDptr = new_engineID;
953
0
    size_t new_engineIDLength = sizeof(new_engineID);
954
955
0
    read_config_read_octet_string(cptr, &new_engineIDptr, &new_engineIDLength);
956
0
    if (new_engineIDLength > MAX_ENGINEID_LENGTH) {
957
0
        new_engineIDLength = MAX_ENGINEID_LENGTH;
958
0
  netsnmp_config_error(
959
0
      "exactEngineID '%s' too long; truncating to %d bytes",
960
0
      cptr, MAX_ENGINEID_LENGTH);
961
0
    }
962
963
0
    set_exact_engineID( new_engineIDptr, new_engineIDLength);
964
0
}
965
966
967
/*
968
 * merely call 
969
 */
970
netsnmp_feature_child_of(get_enginetime_alarm, netsnmp_unused);
971
#ifndef NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM
972
void
973
get_enginetime_alarm(unsigned int regnum, void *clientargs)
974
0
{
975
    /* we do this every so (rarely) often just to make sure we watch
976
       wrapping of the times() output */
977
0
    snmpv3_local_snmpEngineTime();
978
0
}
979
#endif /* NETSNMP_FEATURE_REMOVE_GET_ENGINETIME_ALARM */
980
981
/*******************************************************************-o-******
982
 * init_snmpv3
983
 *
984
 * Parameters:
985
 *  *type Label for the config file "type" used by calling entity.
986
 *      
987
 * Set time and engineID.
988
 * Set parsing functions for config file tokens.
989
 * Initialize SNMP Crypto API (SCAPI).
990
 */
991
void
992
init_snmpv3(const char *type)
993
3.39k
{
994
3.39k
    netsnmp_get_monotonic_clock(&snmpv3starttime);
995
996
3.39k
    if (!type)
997
0
        type = "__snmpapp__";
998
999
    /*
1000
     * we need to be called back later 
1001
     */
1002
3.39k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1003
3.39k
                           SNMP_CALLBACK_POST_READ_CONFIG,
1004
3.39k
                           init_snmpv3_post_config, NULL);
1005
1006
3.39k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1007
3.39k
                           SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
1008
3.39k
                           init_snmpv3_post_premib_config, NULL);
1009
    /*
1010
     * we need to be called back later 
1011
     */
1012
3.39k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
1013
3.39k
                           snmpv3_store, (void *) strdup(type));
1014
1015
    /*
1016
     * initialize submodules 
1017
     */
1018
    /*
1019
     * NOTE: this must be after the callbacks are registered above,
1020
     * since they need to be called before the USM callbacks. 
1021
     */
1022
3.39k
    init_secmod();
1023
1024
    /*
1025
     * register all our configuration handlers (ack, there's a lot) 
1026
     */
1027
1028
    /*
1029
     * handle engineID setup before everything else which may depend on it 
1030
     */
1031
3.39k
    register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
1032
3.39k
                                    "string");
1033
3.39k
    register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
1034
3.39k
                                    NULL, NULL);
1035
3.39k
    register_prenetsnmp_mib_handler(type, "exactEngineID", exactEngineID_conf,
1036
3.39k
                                    NULL, NULL);
1037
3.39k
    register_prenetsnmp_mib_handler(type, "engineIDType",
1038
3.39k
                                    engineIDType_conf, NULL, "num");
1039
3.39k
    register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
1040
3.39k
                                    NULL, "string");
1041
3.39k
    register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
1042
3.39k
                            NULL);
1043
1044
    /*
1045
     * default store config entries 
1046
     */
1047
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
1048
3.39k
             NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
1049
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext", 
1050
3.39k
             NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
1051
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
1052
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1053
3.39k
                               NETSNMP_DS_LIB_PASSPHRASE);
1054
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
1055
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1056
3.39k
                               NETSNMP_DS_LIB_AUTHPASSPHRASE);
1057
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
1058
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1059
3.39k
                               NETSNMP_DS_LIB_PRIVPASSPHRASE);
1060
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
1061
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1062
3.39k
                               NETSNMP_DS_LIB_AUTHMASTERKEY);
1063
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
1064
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1065
3.39k
                               NETSNMP_DS_LIB_PRIVMASTERKEY);
1066
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
1067
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1068
3.39k
                               NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
1069
3.39k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
1070
3.39k
                               NETSNMP_DS_LIBRARY_ID,
1071
3.39k
                               NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
1072
3.39k
    register_config_handler("snmp", "defVersion", version_conf, NULL,
1073
3.39k
                            "1|2c|3");
1074
1075
3.39k
    register_config_handler("snmp", "defSecurityLevel",
1076
3.39k
                            snmpv3_secLevel_conf, NULL,
1077
3.39k
                            "noAuthNoPriv|authNoPriv|authPriv");
1078
3.39k
}
1079
1080
/*
1081
 * initializations for SNMPv3 to be called after the configuration files
1082
 * have been read.
1083
 */
1084
1085
int
1086
init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
1087
                        void *clientarg)
1088
3.39k
{
1089
1090
3.39k
    size_t          engineIDLen;
1091
3.39k
    u_char         *c_engineID;
1092
3.39k
    u_long          localEngineTime;
1093
3.39k
    u_long          localEngineBoots;
1094
1095
3.39k
    c_engineID = snmpv3_generate_engineID(&engineIDLen);
1096
1097
3.39k
    if (!c_engineID || engineIDLen == 0) {
1098
        /*
1099
         * Something went wrong - help! 
1100
         */
1101
0
        SNMP_FREE(c_engineID);
1102
0
        return SNMPERR_GENERR;
1103
0
    }
1104
1105
    /*
1106
     * if our engineID has changed at all, the boots record must be set to 1 
1107
     */
1108
3.39k
    if (engineIDLen != oldEngineIDLength ||
1109
3.39k
        oldEngineID == NULL || c_engineID == NULL ||
1110
3.39k
        memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
1111
3
        engineBoots = 1;
1112
3
    }
1113
1114
3.39k
#ifdef NETSNMP_SECMOD_USM
1115
    /*
1116
     * for USM set our local engineTime in the LCD timing cache 
1117
     */
1118
3.39k
    localEngineTime = snmpv3_local_snmpEngineTime();
1119
3.39k
    localEngineBoots = snmpv3_local_snmpEngineBoots();
1120
3.39k
    set_enginetime(c_engineID, engineIDLen,
1121
3.39k
                   localEngineBoots,
1122
3.39k
                   localEngineTime, TRUE);
1123
3.39k
#endif /* NETSNMP_SECMOD_USM */
1124
1125
3.39k
    SNMP_FREE(c_engineID);
1126
3.39k
    return SNMPERR_SUCCESS;
1127
3.39k
}
1128
1129
int
1130
init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
1131
                               void *clientarg)
1132
3.39k
{
1133
3.39k
    if (!engineIDIsSet)
1134
3.39k
        setup_engineID(NULL, NULL);
1135
1136
3.39k
    return SNMPERR_SUCCESS;
1137
3.39k
}
1138
1139
/*******************************************************************-o-******
1140
 * store_snmpv3
1141
 *
1142
 * Parameters:
1143
 *  *type
1144
 */
1145
int
1146
snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
1147
3.39k
{
1148
3.39k
    char            line[SNMP_MAXBUF_SMALL];
1149
3.39k
    u_char          c_engineID[SNMP_MAXBUF_SMALL];
1150
3.39k
    int             engineIDLen;
1151
3.39k
    const char     *type = (const char *) clientarg;
1152
1153
3.39k
    if (type == NULL)           /* should never happen, since the arg is ours */
1154
0
        type = "unknown";
1155
1156
3.39k
    sprintf(line, "engineBoots %ld", engineBoots);
1157
3.39k
    read_config_store(type, line);
1158
1159
3.39k
    engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
1160
1161
3.39k
    if (engineIDLen) {
1162
        /*
1163
         * store the engineID used for this run 
1164
         */
1165
3.39k
        sprintf(line, "oldEngineID ");
1166
3.39k
        read_config_save_octet_string(line + strlen(line), c_engineID,
1167
3.39k
                                      engineIDLen);
1168
3.39k
        read_config_store(type, line);
1169
3.39k
    }
1170
3.39k
    return SNMPERR_SUCCESS;
1171
3.39k
}                               /* snmpv3_store() */
1172
1173
u_long
1174
snmpv3_local_snmpEngineBoots(void)
1175
3.39k
{
1176
3.39k
    return engineBoots;
1177
3.39k
}
1178
1179
1180
/*******************************************************************-o-******
1181
 * snmpv3_get_engineID
1182
 *
1183
 * Parameters:
1184
 *  *buf
1185
 *   buflen
1186
 *      
1187
 * Returns:
1188
 *  Length of engineID  On Success
1189
 *  SNMPERR_GENERR    Otherwise.
1190
 *
1191
 *
1192
 * Store engineID in buf; return the length.
1193
 *
1194
 */
1195
size_t
1196
snmpv3_get_engineID(u_char * buf, size_t buflen)
1197
13.6k
{
1198
    /*
1199
     * Sanity check.
1200
     */
1201
13.6k
    if (!buf || (buflen < engineIDLength)) {
1202
0
        return 0;
1203
0
    }
1204
13.6k
    if (!engineID) {
1205
3.41k
        return 0;
1206
3.41k
    }
1207
1208
10.1k
    memcpy(buf, engineID, engineIDLength);
1209
10.1k
    return engineIDLength;
1210
1211
13.6k
}                               /* end snmpv3_get_engineID() */
1212
1213
/*******************************************************************-o-******
1214
 * snmpv3_clone_engineID
1215
 *
1216
 * Parameters:
1217
 *  **dest
1218
 *       *dest_len
1219
 *       src
1220
 *   srclen
1221
 *      
1222
 * Returns:
1223
 *  Length of engineID  On Success
1224
 *  0           Otherwise.
1225
 *
1226
 *
1227
 * Clones engineID, creates memory
1228
 *
1229
 */
1230
int
1231
snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
1232
                      size_t srclen)
1233
0
{
1234
0
    if (!dest || !destlen)
1235
0
        return 0;
1236
1237
0
    SNMP_FREE(*dest);
1238
0
    *destlen = 0;
1239
1240
0
    if (srclen && src) {
1241
0
        *dest = netsnmp_memdup(src, srclen);
1242
0
        if (*dest == NULL)
1243
0
            return 0;
1244
0
        *destlen = srclen;
1245
0
    }
1246
0
    return *destlen;
1247
0
}                               /* end snmpv3_clone_engineID() */
1248
1249
1250
/*******************************************************************-o-******
1251
 * snmpv3_generate_engineID
1252
 *
1253
 * Parameters:
1254
 *  *length
1255
 *      
1256
 * Returns:
1257
 *  Pointer to copy of engineID On Success.
1258
 *  NULL        If malloc() or snmpv3_get_engineID()
1259
 *            fail.
1260
 *
1261
 * Generates a malloced copy of our engineID.
1262
 *
1263
 * 'length' is set to the length of engineID  -OR-  < 0 on failure.
1264
 */
1265
u_char         *
1266
snmpv3_generate_engineID(size_t * length)
1267
6.81k
{
1268
6.81k
    u_char         *newID;
1269
6.81k
    newID = (u_char *) malloc(engineIDLength);
1270
1271
6.81k
    if (newID) {
1272
6.81k
        *length = snmpv3_get_engineID(newID, engineIDLength);
1273
6.81k
        if (*length == 0) {
1274
14
            SNMP_FREE(newID);
1275
14
            newID = NULL;
1276
14
        }
1277
6.81k
    }
1278
6.81k
    return newID;
1279
1280
6.81k
}                               /* end snmpv3_generate_engineID() */
1281
1282
/**
1283
 * Return the value of snmpEngineTime. According to RFC 3414 snmpEngineTime
1284
 * is a 31-bit counter. engineBoots must be incremented every time that
1285
 * counter wraps around.
1286
 *
1287
 * @see See also <a href="http://tools.ietf.org/html/rfc3414">RFC 3414</a>.
1288
 *
1289
 * @note It is assumed that this function is called at least once every
1290
 *   2**31 seconds.
1291
 */
1292
u_long
1293
snmpv3_local_snmpEngineTime(void)
1294
6.79k
{
1295
#ifdef NETSNMP_FEATURE_CHECKING
1296
    netsnmp_feature_require(calculate_sectime_diff)
1297
#endif /* NETSNMP_FEATURE_CHECKING */
1298
1299
6.79k
    static uint32_t last_engineTime;
1300
6.79k
    struct timeval  now;
1301
6.79k
    uint32_t engineTime;
1302
1303
6.79k
    netsnmp_get_monotonic_clock(&now);
1304
6.79k
    engineTime = calculate_sectime_diff(&now, &snmpv3starttime) & 0x7fffffffL;
1305
6.79k
    if (engineTime < last_engineTime)
1306
0
        engineBoots++;
1307
6.79k
    last_engineTime = engineTime;
1308
6.79k
    return engineTime;
1309
6.79k
}
1310
1311
1312
1313
/*
1314
 * Code only for Linux systems 
1315
 */
1316
#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
1317
static int
1318
getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
1319
             char *addressOut)
1320
0
{                               /* return address. Len=IFHWADDRLEN */
1321
    /*
1322
     * getHwAddress(...)
1323
     * *
1324
     * *  This function will return a Network Interfaces Card's Hardware
1325
     * *  address (aka MAC address).
1326
     * *
1327
     * *  Input Parameter(s):
1328
     * *      networkDevice - a null terminated string with the name of a network
1329
     * *                      device.  Examples: eth0, eth1, etc...
1330
     * *
1331
     * *  Output Parameter(s):
1332
     * *      addressOut -    This is the binary value of the hardware address.
1333
     * *                      This value is NOT converted into a hexadecimal string.
1334
     * *                      The caller must pre-allocate for a return value of
1335
     * *                      length IFHWADDRLEN
1336
     * *
1337
     * *  Return value:   This function will return zero (0) for success.  If
1338
     * *                  an error occurred the function will return -1.
1339
     * *
1340
     * *  Caveats:    This has only been tested on Ethernet networking cards.
1341
     */
1342
0
    int             sock;       /* our socket */
1343
0
    struct ifreq    request;    /* struct which will have HW address */
1344
1345
0
    if ((NULL == networkDevice) || (NULL == addressOut)) {
1346
0
        return -1;
1347
0
    }
1348
    /*
1349
     * In order to find out the hardware (MAC) address of our system under
1350
     * * Linux we must do the following:
1351
     * * 1.  Create a socket
1352
     * * 2.  Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
1353
     */
1354
0
    sock = socket(AF_INET, SOCK_DGRAM, 0);
1355
0
    if (sock < 0) {
1356
0
        return -1;
1357
0
    }
1358
    /*
1359
     * erase the request block 
1360
     */
1361
0
    memset(&request, 0, sizeof(request));
1362
    /*
1363
     * copy the name of the net device we want to find the HW address for 
1364
     */
1365
0
    strlcpy(request.ifr_name, networkDevice, IFNAMSIZ);
1366
    /*
1367
     * Get the HW address 
1368
     */
1369
0
    if (ioctl(sock, SIOCGIFHWADDR, &request)) {
1370
0
        close(sock);
1371
0
        return -1;
1372
0
    }
1373
0
    close(sock);
1374
0
    memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
1375
0
    return 0;
1376
0
}
1377
#endif
1378
1379
#ifdef NETSNMP_ENABLE_TESTING_CODE
1380
/**
1381
 * Set SNMPv3 engineBoots and start time.
1382
 *
1383
 * @note This function does not exist. Go away. It certainly should never be
1384
 *   used, unless in a testing scenario, which is why it was created
1385
 */
1386
void
1387
snmpv3_set_engineBootsAndTime(int boots, int ttime)
1388
{
1389
    engineBoots = boots;
1390
    netsnmp_get_monotonic_clock(&snmpv3starttime);
1391
    snmpv3starttime.tv_sec -= ttime;
1392
}
1393
#endif