Coverage Report

Created: 2023-09-25 06:06

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