Coverage Report

Created: 2024-09-11 06:05

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