blob: e451f3129aec3ce9776a055dd81d8b1bbbf55fe7 [file] [log] [blame]
Dave Shield00ef5692011-02-22 08:55:48 +00001/*
2 * snmpv3.c
3 */
4
5#include <net-snmp/net-snmp-config.h>
6#include <errno.h>
7#ifdef HAVE_LIMITS_H
8#include <limits.h>
9#endif
10#include <stdio.h>
11#include <sys/types.h>
12
13#if TIME_WITH_SYS_TIME
14# ifdef WIN32
15# include <sys/timeb.h>
16# else
17# include <sys/time.h>
18# endif
19# include <time.h>
20#else
21# if HAVE_SYS_TIME_H
22# include <sys/time.h>
23# else
24# include <time.h>
25# endif
26#endif
27#if HAVE_SYS_TIMES_H
28#include <sys/times.h>
29#endif
30#if HAVE_STRING_H
31#include <string.h>
32#else
33#include <strings.h>
34#endif
35#include <ctype.h>
36#if HAVE_NETINET_IN_H
37#include <netinet/in.h>
38#endif
39#if HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#if HAVE_WINSOCK_H
43#include <winsock.h>
44#endif
45#if HAVE_SYS_SOCKET_H
46#include <sys/socket.h>
47#endif
48#if HAVE_NETDB_H
49#include <netdb.h>
50#endif
51#if HAVE_STDLIB_H
52# include <stdlib.h>
53#endif
54
55/*
56 * Stuff needed for getHwAddress(...)
57 */
58#ifdef HAVE_SYS_IOCTL_H
59# include <sys/ioctl.h>
60#endif
61#ifdef HAVE_NET_IF_H
62# include <net/if.h>
63#endif
64
65#if HAVE_DMALLOC_H
66#include <dmalloc.h>
67#endif
68
69#include <net-snmp/types.h>
70#include <net-snmp/output_api.h>
71#include <net-snmp/config_api.h>
72#include <net-snmp/utilities.h>
73
74#include <net-snmp/library/snmpv3.h>
75#include <net-snmp/library/callback.h>
76#include <net-snmp/library/snmp_api.h>
77#include <net-snmp/library/lcd_time.h>
78#include <net-snmp/library/scapi.h>
79#include <net-snmp/library/keytools.h>
80#include <net-snmp/library/lcd_time.h>
81#include <net-snmp/library/snmp_secmod.h>
82#include <net-snmp/library/snmpusm.h>
83#include <net-snmp/library/transform_oids.h>
84
85static u_long engineBoots = 1;
86static unsigned int engineIDType = ENGINEID_TYPE_NETSNMP_RND;
87static unsigned char *engineID = NULL;
88static size_t engineIDLength = 0;
89static unsigned char *engineIDNic = NULL;
90static unsigned int engineIDIsSet = 0; /* flag if ID set by config */
91static unsigned char *oldEngineID = NULL;
92static size_t oldEngineIDLength = 0;
93static struct timeval snmpv3starttime;
94
95/*
96 * Set up default snmpv3 parameter value storage.
97 */
98static const oid *defaultAuthType = NULL;
99static size_t defaultAuthTypeLen = 0;
100static const oid *defaultPrivType = NULL;
101static size_t defaultPrivTypeLen = 0;
102
103/* this is probably an over-kill ifdef, but why not */
104#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_UNISTD_H) && defined(HAVE_TIMES) && defined(_SC_CLK_TCK) && defined(HAVE_SYSCONF) && defined(UINT_MAX)
105
106#define SNMP_USE_TIMES 1
107
108static clock_t snmpv3startClock;
109static long clockticks = 0;
110static unsigned int lastcalltime = 0;
111static unsigned int wrapcounter = 0;
112
113#endif /* times() tests */
114
115#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
116static int getHwAddress(const char *networkDevice, char *addressOut);
117#endif
118
119void
120snmpv3_authtype_conf(const char *word, char *cptr)
121{
122#ifndef NETSNMP_DISABLE_MD5
123 if (strcasecmp(cptr, "MD5") == 0)
124 defaultAuthType = usmHMACMD5AuthProtocol;
125 else
126#endif
127 if (strcasecmp(cptr, "SHA") == 0)
128 defaultAuthType = usmHMACSHA1AuthProtocol;
129 else
130 config_perror("Unknown authentication type");
131 defaultAuthTypeLen = USM_LENGTH_OID_TRANSFORM;
132 DEBUGMSGTL(("snmpv3", "set default authentication type: %s\n", cptr));
133}
134
135const oid *
136get_default_authtype(size_t * len)
137{
138 if (defaultAuthType == NULL) {
139 defaultAuthType = SNMP_DEFAULT_AUTH_PROTO;
140 defaultAuthTypeLen = SNMP_DEFAULT_AUTH_PROTOLEN;
141 }
142 if (len)
143 *len = defaultAuthTypeLen;
144 return defaultAuthType;
145}
146
147void
148snmpv3_privtype_conf(const char *word, char *cptr)
149{
150 int testcase = 0;
151
152#ifndef NETSNMP_DISABLE_DES
153 if (strcasecmp(cptr, "DES") == 0) {
154 testcase = 1;
155 defaultPrivType = usmDESPrivProtocol;
156 }
157#endif
158
159#if HAVE_AES
160 /* XXX AES: assumes oid length == des oid length */
161 if (strcasecmp(cptr, "AES128") == 0 ||
162 strcasecmp(cptr, "AES") == 0) {
163 testcase = 1;
164 defaultPrivType = usmAES128PrivProtocol;
165 }
166#endif
167 if (testcase == 0)
168 config_perror("Unknown privacy type");
169 defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
170 DEBUGMSGTL(("snmpv3", "set default privacy type: %s\n", cptr));
171}
172
173const oid *
174get_default_privtype(size_t * len)
175{
176 if (defaultPrivType == NULL) {
177#ifndef NETSNMP_DISABLE_DES
178 defaultPrivType = usmDESPrivProtocol;
179#else
180 defaultPrivType = usmAESPrivProtocol;
181#endif
182 defaultPrivTypeLen = USM_LENGTH_OID_TRANSFORM;
183 }
184 if (len)
185 *len = defaultPrivTypeLen;
186 return defaultPrivType;
187}
188
189/*******************************************************************-o-******
190 * snmpv3_secLevel_conf
191 *
192 * Parameters:
193 * *word
194 * *cptr
195 *
196 * Line syntax:
197 * defSecurityLevel "noAuthNoPriv" | "authNoPriv" | "authPriv"
198 */
199
200int
201parse_secLevel_conf(const char *word, char *cptr) {
202 if (strcasecmp(cptr, "noAuthNoPriv") == 0 || strcmp(cptr, "1") == 0 ||
203 strcasecmp(cptr, "nanp") == 0) {
204 return SNMP_SEC_LEVEL_NOAUTH;
205 } else if (strcasecmp(cptr, "authNoPriv") == 0 || strcmp(cptr, "2") == 0 ||
206 strcasecmp(cptr, "anp") == 0) {
207 return SNMP_SEC_LEVEL_AUTHNOPRIV;
208 } else if (strcasecmp(cptr, "authPriv") == 0 || strcmp(cptr, "3") == 0 ||
209 strcasecmp(cptr, "ap") == 0) {
210 return SNMP_SEC_LEVEL_AUTHPRIV;
211 } else {
212 return -1;
213 }
214}
215
216void
217snmpv3_secLevel_conf(const char *word, char *cptr)
218{
219 int secLevel;
220
221 if ((secLevel = parse_secLevel_conf( word, cptr )) >= 0 ) {
222 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
223 NETSNMP_DS_LIB_SECLEVEL, secLevel);
224 } else {
225 netsnmp_config_error("Unknown security level: %s", cptr);
226 }
227 DEBUGMSGTL(("snmpv3", "default secLevel set to: %s = %d\n", cptr,
228 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
229 NETSNMP_DS_LIB_SECLEVEL)));
230}
231
232
233int
234snmpv3_options(char *optarg, netsnmp_session * session, char **Apsz,
235 char **Xpsz, int argc, char *const *argv)
236{
237 char *cp = optarg;
238 int testcase;
239 optarg++;
240 /*
241 * Support '... -3x=value ....' syntax
242 */
243 if (*optarg == '=') {
244 optarg++;
245 }
246 /*
247 * and '.... "-3x value" ....' (*with* the quotes)
248 */
249 while (*optarg && isspace(*optarg)) {
250 optarg++;
251 }
252 /*
253 * Finally, handle ".... -3x value ...." syntax
254 * (*without* surrounding quotes)
255 */
256 if (!*optarg) {
257 /*
258 * We've run off the end of the argument
259 * so move on the the next.
260 */
261 optarg = argv[optind++];
262 if (optind > argc) {
263 fprintf(stderr,
264 "Missing argument after SNMPv3 '-3%c' option.\n", *cp);
265 return (-1);
266 }
267 }
268
269 switch (*cp) {
270
271 case 'Z':
272 errno=0;
273 session->engineBoots = strtoul(optarg, &cp, 10);
274 if (errno || cp == optarg) {
275 fprintf(stderr, "Need engine boots value after -3Z flag.\n");
276 return (-1);
277 }
278 if (*cp == ',') {
279 char *endptr;
280 cp++;
281 session->engineTime = strtoul(cp, &endptr, 10);
282 if (errno || cp == endptr) {
283 fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
284 return (-1);
285 }
286 } else {
287 fprintf(stderr, "Need engine time after \"-3Z engineBoot,\".\n");
288 return (-1);
289 }
290 break;
291
292 case 'e':{
293 size_t ebuf_len = 32, eout_len = 0;
294 u_char *ebuf = (u_char *) malloc(ebuf_len);
295
296 if (ebuf == NULL) {
297 fprintf(stderr, "malloc failure processing -3e flag.\n");
298 return (-1);
299 }
300 if (!snmp_hex_to_binary
301 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
302 fprintf(stderr, "Bad engine ID value after -3e flag.\n");
303 SNMP_FREE(ebuf);
304 return (-1);
305 }
306 session->securityEngineID = ebuf;
307 session->securityEngineIDLen = eout_len;
308 break;
309 }
310
311 case 'E':{
312 size_t ebuf_len = 32, eout_len = 0;
313 u_char *ebuf = (u_char *) malloc(ebuf_len);
314
315 if (ebuf == NULL) {
316 fprintf(stderr, "malloc failure processing -3E flag.\n");
317 return (-1);
318 }
319 if (!snmp_hex_to_binary
320 (&ebuf, &ebuf_len, &eout_len, 1, optarg)) {
321 fprintf(stderr, "Bad engine ID value after -3E flag.\n");
322 SNMP_FREE(ebuf);
323 return (-1);
324 }
325 session->contextEngineID = ebuf;
326 session->contextEngineIDLen = eout_len;
327 break;
328 }
329
330 case 'n':
331 session->contextName = optarg;
332 session->contextNameLen = strlen(optarg);
333 break;
334
335 case 'u':
336 session->securityName = optarg;
337 session->securityNameLen = strlen(optarg);
338 break;
339
340 case 'l':
341 if (!strcasecmp(optarg, "noAuthNoPriv") || !strcmp(optarg, "1") ||
342 !strcasecmp(optarg, "nanp")) {
343 session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
344 } else if (!strcasecmp(optarg, "authNoPriv")
345 || !strcmp(optarg, "2") || !strcasecmp(optarg, "anp")) {
346 session->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
347 } else if (!strcasecmp(optarg, "authPriv") || !strcmp(optarg, "3")
348 || !strcasecmp(optarg, "ap")) {
349 session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
350 } else {
351 fprintf(stderr,
352 "Invalid security level specified after -3l flag: %s\n",
353 optarg);
354 return (-1);
355 }
356
357 break;
358
359 case 'a':
360#ifndef NETSNMP_DISABLE_MD5
361 if (!strcasecmp(optarg, "MD5")) {
362 session->securityAuthProto = usmHMACMD5AuthProtocol;
363 session->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
364 } else
365#endif
366 if (!strcasecmp(optarg, "SHA")) {
367 session->securityAuthProto = usmHMACSHA1AuthProtocol;
368 session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
369 } else {
370 fprintf(stderr,
371 "Invalid authentication protocol specified after -3a flag: %s\n",
372 optarg);
373 return (-1);
374 }
375 break;
376
377 case 'x':
378 testcase = 0;
379#ifndef NETSNMP_DISABLE_DES
380 if (!strcasecmp(optarg, "DES")) {
381 session->securityPrivProto = usmDESPrivProtocol;
382 session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
383 testcase = 1;
384 }
385#endif
386#ifdef HAVE_AES
387 if (!strcasecmp(optarg, "AES128") ||
388 strcasecmp(optarg, "AES")) {
389 session->securityPrivProto = usmAES128PrivProtocol;
390 session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
391 testcase = 1;
392 }
393#endif
394 if (testcase == 0) {
395 fprintf(stderr,
396 "Invalid privacy protocol specified after -3x flag: %s\n",
397 optarg);
398 return (-1);
399 }
400 break;
401
402 case 'A':
403 *Apsz = optarg;
404 break;
405
406 case 'X':
407 *Xpsz = optarg;
408 break;
409
410 case 'm': {
411 size_t bufSize = sizeof(session->securityAuthKey);
412 u_char *tmpp = session->securityAuthKey;
413 if (!snmp_hex_to_binary(&tmpp, &bufSize,
414 &session->securityAuthKeyLen, 0, optarg)) {
415 fprintf(stderr, "Bad key value after -3m flag.\n");
416 return (-1);
417 }
418 break;
419 }
420
421 case 'M': {
422 size_t bufSize = sizeof(session->securityPrivKey);
423 u_char *tmpp = session->securityPrivKey;
424 if (!snmp_hex_to_binary(&tmpp, &bufSize,
425 &session->securityPrivKeyLen, 0, optarg)) {
426 fprintf(stderr, "Bad key value after -3M flag.\n");
427 return (-1);
428 }
429 break;
430 }
431
432 case 'k': {
433 size_t kbuf_len = 32, kout_len = 0;
434 u_char *kbuf = (u_char *) malloc(kbuf_len);
435
436 if (kbuf == NULL) {
437 fprintf(stderr, "malloc failure processing -3k flag.\n");
438 return (-1);
439 }
440 if (!snmp_hex_to_binary
441 (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
442 fprintf(stderr, "Bad key value after -3k flag.\n");
443 SNMP_FREE(kbuf);
444 return (-1);
445 }
446 session->securityAuthLocalKey = kbuf;
447 session->securityAuthLocalKeyLen = kout_len;
448 break;
449 }
450
451 case 'K': {
452 size_t kbuf_len = 32, kout_len = 0;
453 u_char *kbuf = (u_char *) malloc(kbuf_len);
454
455 if (kbuf == NULL) {
456 fprintf(stderr, "malloc failure processing -3K flag.\n");
457 return (-1);
458 }
459 if (!snmp_hex_to_binary
460 (&kbuf, &kbuf_len, &kout_len, 1, optarg)) {
461 fprintf(stderr, "Bad key value after -3K flag.\n");
462 SNMP_FREE(kbuf);
463 return (-1);
464 }
465 session->securityPrivLocalKey = kbuf;
466 session->securityPrivLocalKeyLen = kout_len;
467 break;
468 }
469
470 default:
471 fprintf(stderr, "Unknown SNMPv3 option passed to -3: %c.\n", *cp);
472 return -1;
473 }
474 return 0;
475}
476
477/*******************************************************************-o-******
478 * setup_engineID
479 *
480 * Parameters:
481 * **eidp
482 * *text Printable (?) text to be plugged into the snmpEngineID.
483 *
484 * Return:
485 * Length of allocated engineID string in bytes, -OR-
486 * -1 on error.
487 *
488 *
489 * Create an snmpEngineID using text and the local IP address. If eidp
490 * is defined, use it to return a pointer to the newly allocated data.
491 * Otherwise, use the result to define engineID defined in this module.
492 *
493 * Line syntax:
494 * engineID <text> | NULL
495 *
496 * XXX What if a node has multiple interfaces?
497 * XXX What if multiple engines all choose the same address?
498 * (answer: You're screwed, because you might need a kul database
499 * which is dependant on the current engineID. Enumeration and other
500 * tricks won't work).
501 */
502int
503setup_engineID(u_char ** eidp, const char *text)
504{
505 int enterpriseid = htonl(NETSNMP_ENTERPRISE_OID),
506 netsnmpoid = htonl(NETSNMP_OID),
507 localsetup = (eidp) ? 0 : 1;
508
509 /*
510 * Use local engineID if *eidp == NULL.
511 */
512#ifdef HAVE_GETHOSTNAME
513 u_char buf[SNMP_MAXBUF_SMALL];
514 struct hostent *hent = NULL;
515#endif
516 u_char *bufp = NULL;
517 size_t len;
518 int localEngineIDType = engineIDType;
519 int tmpint;
520 time_t tmptime;
521
522 engineIDIsSet = 1;
523
524#ifdef HAVE_GETHOSTNAME
525#ifdef AF_INET6
526 /*
527 * see if they selected IPV4 or IPV6 support
528 */
529 if ((ENGINEID_TYPE_IPV6 == localEngineIDType) ||
530 (ENGINEID_TYPE_IPV4 == localEngineIDType)) {
531 /*
532 * get the host name and save the information
533 */
534 gethostname((char *) buf, sizeof(buf));
535 hent = gethostbyname((char *) buf);
536 if (hent && hent->h_addrtype == AF_INET6) {
537 localEngineIDType = ENGINEID_TYPE_IPV6;
538 } else {
539 /*
540 * Not IPV6 so we go with default
541 */
542 localEngineIDType = ENGINEID_TYPE_IPV4;
543 }
544 }
545#else
546 /*
547 * No IPV6 support. Check if they selected IPV6 engineID type.
548 * If so make it IPV4 instead
549 */
550 if (ENGINEID_TYPE_IPV6 == localEngineIDType) {
551 localEngineIDType = ENGINEID_TYPE_IPV4;
552 }
553 if (ENGINEID_TYPE_IPV4 == localEngineIDType) {
554 /*
555 * get the host name and save the information
556 */
557 gethostname((char *) buf, sizeof(buf));
558 hent = gethostbyname((char *) buf);
559 }
560#endif
561#endif /* HAVE_GETHOSTNAME */
562
563 /*
564 * Determine if we have text and if so setup our localEngineIDType
565 * * appropriately.
566 */
567 if (NULL != text) {
568 engineIDType = localEngineIDType = ENGINEID_TYPE_TEXT;
569 }
570 /*
571 * Determine length of the engineID string.
572 */
573 len = 5; /* always have 5 leading bytes */
574 switch (localEngineIDType) {
575 case ENGINEID_TYPE_TEXT:
576 if (NULL == text) {
577 snmp_log(LOG_ERR,
578 "Can't set up engineID of type text from an empty string.\n");
579 return -1;
580 }
581 len += strlen(text); /* 5 leading bytes+text. No NULL char */
582 break;
583#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
584 case ENGINEID_TYPE_MACADDR: /* MAC address */
585 len += 6; /* + 6 bytes for MAC address */
586 break;
587#endif
588 case ENGINEID_TYPE_IPV4: /* IPv4 */
589 len += 4; /* + 4 byte IPV4 address */
590 break;
591 case ENGINEID_TYPE_IPV6: /* IPv6 */
592 len += 16; /* + 16 byte IPV6 address */
593 break;
594 case ENGINEID_TYPE_NETSNMP_RND: /* Net-SNMP specific encoding */
595 if (engineID) /* already setup, keep current value */
596 return engineIDLength;
597 if (oldEngineID) {
598 len = oldEngineIDLength;
599 } else {
600 len += sizeof(int) + sizeof(time_t);
601 }
602 break;
603 default:
604 snmp_log(LOG_ERR,
605 "Unknown EngineID type requested for setup (%d). Using IPv4.\n",
606 localEngineIDType);
607 localEngineIDType = ENGINEID_TYPE_IPV4; /* make into IPV4 */
608 len += 4; /* + 4 byte IPv4 address */
609 break;
610 } /* switch */
611
612
613 /*
614 * Allocate memory and store enterprise ID.
615 */
616 if ((bufp = (u_char *) malloc(len)) == NULL) {
617 snmp_log_perror("setup_engineID malloc");
618 return -1;
619 }
620 if (localEngineIDType == ENGINEID_TYPE_NETSNMP_RND)
621 /*
622 * we must use the net-snmp enterprise id here, regardless
623 */
624 memcpy(bufp, &netsnmpoid, sizeof(netsnmpoid)); /* XXX Must be 4 bytes! */
625 else
626 memcpy(bufp, &enterpriseid, sizeof(enterpriseid)); /* XXX Must be 4 bytes! */
627
628 bufp[0] |= 0x80;
629
630
631 /*
632 * Store the given text -OR- the first found IP address
633 * -OR- the MAC address -OR- random elements
634 * (the latter being the recommended default)
635 */
636 switch (localEngineIDType) {
637 case ENGINEID_TYPE_NETSNMP_RND:
638 if (oldEngineID) {
639 /*
640 * keep our previous notion of the engineID
641 */
642 memcpy(bufp, oldEngineID, oldEngineIDLength);
643 } else {
644 /*
645 * Here we've desigend our own ENGINEID that is not based on
646 * an address which may change and may even become conflicting
647 * in the future like most of the default v3 engineID types
648 * suffer from.
649 *
650 * Ours is built from 2 fairly random elements: a random number and
651 * the current time in seconds. This method suffers from boxes
652 * that may not have a correct clock setting and random number
653 * seed at startup, but few OSes should have that problem.
654 */
655 bufp[4] = ENGINEID_TYPE_NETSNMP_RND;
656 tmpint = random();
657 memcpy(bufp + 5, &tmpint, sizeof(tmpint));
658 tmptime = time(NULL);
659 memcpy(bufp + 5 + sizeof(tmpint), &tmptime, sizeof(tmptime));
660 }
661 break;
662 case ENGINEID_TYPE_TEXT:
663 bufp[4] = ENGINEID_TYPE_TEXT;
664 memcpy((char *) bufp + 5, (text), strlen(text));
665 break;
666#ifdef HAVE_GETHOSTNAME
667#ifdef AF_INET6
668 case ENGINEID_TYPE_IPV6:
669 bufp[4] = ENGINEID_TYPE_IPV6;
670 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
671 break;
672#endif
673#endif
674#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
675 case ENGINEID_TYPE_MACADDR:
676 {
677 int x;
678 bufp[4] = ENGINEID_TYPE_MACADDR;
679 /*
680 * use default NIC if none provided
681 */
682 if (NULL == engineIDNic) {
683 x = getHwAddress(DEFAULT_NIC, (char *)&bufp[5]);
684 } else {
685 x = getHwAddress((char *)engineIDNic, (char *)&bufp[5]);
686 }
687 if (0 != x)
688 /*
689 * function failed fill MAC address with zeros
690 */
691 {
692 memset(&bufp[5], 0, 6);
693 }
694 }
695 break;
696#endif
697 case ENGINEID_TYPE_IPV4:
698 default:
699 bufp[4] = ENGINEID_TYPE_IPV4;
700#ifdef HAVE_GETHOSTNAME
701 if (hent && hent->h_addrtype == AF_INET) {
702 memcpy(bufp + 5, hent->h_addr_list[0], hent->h_length);
703 } else { /* Unknown address type. Default to 127.0.0.1. */
704
705 bufp[5] = 127;
706 bufp[6] = 0;
707 bufp[7] = 0;
708 bufp[8] = 1;
709 }
710#else /* HAVE_GETHOSTNAME */
711 /*
712 * Unknown address type. Default to 127.0.0.1.
713 */
714 bufp[5] = 127;
715 bufp[6] = 0;
716 bufp[7] = 0;
717 bufp[8] = 1;
718#endif /* HAVE_GETHOSTNAME */
719 break;
720 }
721
722 /*
723 * Pass the string back to the calling environment, or use it for
724 * our local engineID.
725 */
726 if (localsetup) {
727 SNMP_FREE(engineID);
728 engineID = bufp;
729 engineIDLength = len;
730
731 } else {
732 *eidp = bufp;
733 }
734
735
736 return len;
737
738} /* end setup_engineID() */
739
740int
741free_engineID(int majorid, int minorid, void *serverarg,
742 void *clientarg)
743{
744 SNMP_FREE(engineID);
745 SNMP_FREE(engineIDNic);
746 SNMP_FREE(oldEngineID);
747 engineIDIsSet = 0;
748 return 0;
749}
750
751int
752free_enginetime_on_shutdown(int majorid, int minorid, void *serverarg,
753 void *clientarg)
754{
755 DEBUGMSGTL(("snmpv3", "free enginetime callback called\n"));
756 if (engineID != NULL)
757 free_enginetime(engineID, engineIDLength);
758 return 0;
759}
760
761void
762usm_parse_create_usmUser(const char *token, char *line)
763{
764 char *cp;
765 char buf[SNMP_MAXBUF_MEDIUM];
766 struct usmUser *newuser;
767 u_char userKey[SNMP_MAXBUF_SMALL], *tmpp;
768 size_t userKeyLen = SNMP_MAXBUF_SMALL;
769 size_t privKeyLen = 0;
770 size_t ret;
771 int ret2;
772 int testcase;
773
774 newuser = usm_create_user();
775
776 /*
777 * READ: Security Name
778 */
779 cp = copy_nword(line, buf, sizeof(buf));
780
781 /*
782 * might be a -e ENGINEID argument
783 */
784 if (strcmp(buf, "-e") == 0) {
785 size_t ebuf_len = 32, eout_len = 0;
786 u_char *ebuf = (u_char *) malloc(ebuf_len);
787
788 if (ebuf == NULL) {
789 config_perror("malloc failure processing -e flag");
790 usm_free_user(newuser);
791 return;
792 }
793
794 /*
795 * Get the specified engineid from the line.
796 */
797 cp = copy_nword(cp, buf, sizeof(buf));
798 if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, buf)) {
799 config_perror("invalid EngineID argument to -e");
800 usm_free_user(newuser);
801 SNMP_FREE(ebuf);
802 return;
803 }
804
805 newuser->engineID = ebuf;
806 newuser->engineIDLen = eout_len;
807 cp = copy_nword(cp, buf, sizeof(buf));
808 } else {
809 newuser->engineID = snmpv3_generate_engineID(&ret);
810 if (ret == 0) {
811 usm_free_user(newuser);
812 return;
813 }
814 newuser->engineIDLen = ret;
815 }
816
817 newuser->secName = strdup(buf);
818 newuser->name = strdup(buf);
819
820 if (!cp)
821 goto add; /* no authentication or privacy type */
822
823 /*
824 * READ: Authentication Type
825 */
826#ifndef NETSNMP_DISABLE_MD5
827 if (strncmp(cp, "MD5", 3) == 0) {
828 memcpy(newuser->authProtocol, usmHMACMD5AuthProtocol,
829 sizeof(usmHMACMD5AuthProtocol));
830 } else
831#endif
832 if (strncmp(cp, "SHA", 3) == 0) {
833 memcpy(newuser->authProtocol, usmHMACSHA1AuthProtocol,
834 sizeof(usmHMACSHA1AuthProtocol));
835 } else {
836 config_perror("Unknown authentication protocol");
837 usm_free_user(newuser);
838 return;
839 }
840
841 cp = skip_token(cp);
842
843 /*
844 * READ: Authentication Pass Phrase or key
845 */
846 if (!cp) {
847 config_perror("no authentication pass phrase");
848 usm_free_user(newuser);
849 return;
850 }
851 cp = copy_nword(cp, buf, sizeof(buf));
852 if (strcmp(buf,"-m") == 0) {
853 /* a master key is specified */
854 cp = copy_nword(cp, buf, sizeof(buf));
855 ret = sizeof(userKey);
856 tmpp = userKey;
857 userKeyLen = 0;
858 if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
859 config_perror("invalid key value argument to -m");
860 usm_free_user(newuser);
861 return;
862 }
863 } else if (strcmp(buf,"-l") != 0) {
864 /* a password is specified */
865 userKeyLen = sizeof(userKey);
866 ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
867 (u_char *) buf, strlen(buf), userKey, &userKeyLen);
868 if (ret2 != SNMPERR_SUCCESS) {
869 config_perror("could not generate the authentication key from the "
870 "supplied pass phrase.");
871 usm_free_user(newuser);
872 return;
873 }
874 }
875
876 /*
877 * And turn it into a localized key
878 */
879 ret2 = sc_get_properlength(newuser->authProtocol,
880 newuser->authProtocolLen);
881 if (ret2 <= 0) {
882 config_perror("Could not get proper authentication protocol key length");
883 usm_free_user(newuser);
884 return;
885 }
886 newuser->authKey = (u_char *) malloc(ret2);
887
888 if (strcmp(buf,"-l") == 0) {
889 /* a local key is directly specified */
890 cp = copy_nword(cp, buf, sizeof(buf));
891 newuser->authKeyLen = 0;
892 ret = ret2;
893 if (!snmp_hex_to_binary(&newuser->authKey, &ret,
894 &newuser->authKeyLen, 0, buf)) {
895 config_perror("invalid key value argument to -l");
896 usm_free_user(newuser);
897 return;
898 }
899 if (ret != newuser->authKeyLen) {
900 config_perror("improper key length to -l");
901 usm_free_user(newuser);
902 return;
903 }
904 } else {
905 newuser->authKeyLen = ret2;
906 ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
907 newuser->engineID, newuser->engineIDLen,
908 userKey, userKeyLen,
909 newuser->authKey, &newuser->authKeyLen);
910 if (ret2 != SNMPERR_SUCCESS) {
911 config_perror("could not generate localized authentication key "
912 "(Kul) from the master key (Ku).");
913 usm_free_user(newuser);
914 return;
915 }
916 }
917
918 if (!cp)
919 goto add; /* no privacy type (which is legal) */
920
921 /*
922 * READ: Privacy Type
923 */
924 testcase = 0;
925#ifndef NETSNMP_DISABLE_DES
926 if (strncmp(cp, "DES", 3) == 0) {
927 memcpy(newuser->privProtocol, usmDESPrivProtocol,
928 sizeof(usmDESPrivProtocol));
929 testcase = 1;
930 /* DES uses a 128 bit key, 64 bits of which is a salt */
931 privKeyLen = 16;
932 }
933#endif
934#ifdef HAVE_AES
935 if (strncmp(cp, "AES128", 6) == 0 ||
936 strncmp(cp, "AES", 3) == 0) {
937 memcpy(newuser->privProtocol, usmAESPrivProtocol,
938 sizeof(usmAESPrivProtocol));
939 testcase = 1;
940 privKeyLen = 16;
941 }
942#endif
943 if (testcase == 0) {
944 config_perror("Unknown privacy protocol");
945 usm_free_user(newuser);
946 return;
947 }
948
949 cp = skip_token(cp);
950 /*
951 * READ: Encryption Pass Phrase or key
952 */
953 if (!cp) {
954 /*
955 * assume the same as the authentication key
956 */
Bart Van Assche9a6f5662013-08-25 10:18:53 +0200957 newuser->privKey = netsnmp_memdup(newuser->authKey,
958 newuser->authKeyLen);
Dave Shield00ef5692011-02-22 08:55:48 +0000959 newuser->privKeyLen = newuser->authKeyLen;
960 } else {
961 cp = copy_nword(cp, buf, sizeof(buf));
962
963 if (strcmp(buf,"-m") == 0) {
964 /* a master key is specified */
965 cp = copy_nword(cp, buf, sizeof(buf));
966 ret = sizeof(userKey);
967 tmpp = userKey;
968 userKeyLen = 0;
969 if (!snmp_hex_to_binary(&tmpp, &ret, &userKeyLen, 0, buf)) {
970 config_perror("invalid key value argument to -m");
971 usm_free_user(newuser);
972 return;
973 }
974 } else if (strcmp(buf,"-l") != 0) {
975 /* a password is specified */
976 userKeyLen = sizeof(userKey);
977 ret2 = generate_Ku(newuser->authProtocol, newuser->authProtocolLen,
978 (u_char *) buf, strlen(buf), userKey, &userKeyLen);
979 if (ret2 != SNMPERR_SUCCESS) {
980 config_perror("could not generate the privacy key from the "
981 "supplied pass phrase.");
982 usm_free_user(newuser);
983 return;
984 }
985 }
986
987 /*
988 * And turn it into a localized key
989 */
990 ret2 = sc_get_properlength(newuser->authProtocol,
991 newuser->authProtocolLen);
992 if (ret2 < 0) {
993 config_perror("could not get proper key length to use for the "
994 "privacy algorithm.");
995 usm_free_user(newuser);
996 return;
997 }
998 newuser->privKey = (u_char *) malloc(ret2);
999
1000 if (strcmp(buf,"-l") == 0) {
1001 /* a local key is directly specified */
1002 cp = copy_nword(cp, buf, sizeof(buf));
1003 ret = ret2;
1004 newuser->privKeyLen = 0;
1005 if (!snmp_hex_to_binary(&newuser->privKey, &ret,
1006 &newuser->privKeyLen, 0, buf)) {
1007 config_perror("invalid key value argument to -l");
1008 usm_free_user(newuser);
1009 return;
1010 }
1011 } else {
1012 newuser->privKeyLen = ret2;
1013 ret2 = generate_kul(newuser->authProtocol, newuser->authProtocolLen,
1014 newuser->engineID, newuser->engineIDLen,
1015 userKey, userKeyLen,
1016 newuser->privKey, &newuser->privKeyLen);
1017 if (ret2 != SNMPERR_SUCCESS) {
1018 config_perror("could not generate localized privacy key "
1019 "(Kul) from the master key (Ku).");
1020 usm_free_user(newuser);
1021 return;
1022 }
1023 }
1024 }
1025
1026 if ((newuser->privKeyLen >= privKeyLen) || (privKeyLen == 0)){
1027 newuser->privKeyLen = privKeyLen;
1028 }
1029 else {
1030 /* The privKey length is smaller than required by privProtocol */
1031 usm_free_user(newuser);
1032 return;
1033 }
1034
1035 add:
1036 usm_add_user(newuser);
1037 DEBUGMSGTL(("usmUser", "created a new user %s at ", newuser->secName));
1038 DEBUGMSGHEX(("usmUser", newuser->engineID, newuser->engineIDLen));
1039 DEBUGMSG(("usmUser", "\n"));
1040}
1041
1042/*******************************************************************-o-******
1043 * engineBoots_conf
1044 *
1045 * Parameters:
1046 * *word
1047 * *cptr
1048 *
1049 * Line syntax:
1050 * engineBoots <num_boots>
1051 */
1052void
1053engineBoots_conf(const char *word, char *cptr)
1054{
1055 engineBoots = atoi(cptr) + 1;
1056 DEBUGMSGTL(("snmpv3", "engineBoots: %lu\n", engineBoots));
1057}
1058
1059/*******************************************************************-o-******
1060 * engineIDType_conf
1061 *
1062 * Parameters:
1063 * *word
1064 * *cptr
1065 *
1066 * Line syntax:
1067 * engineIDType <1 or 3>
1068 * 1 is default for IPv4 engine ID type. Will automatically
1069 * chose between IPv4 & IPv6 if either 1 or 2 is specified.
1070 * 2 is for IPv6.
1071 * 3 is hardware (MAC) address, currently supported under Linux
1072 */
1073void
1074engineIDType_conf(const char *word, char *cptr)
1075{
1076 engineIDType = atoi(cptr);
1077 /*
1078 * verify valid type selected
1079 */
1080 switch (engineIDType) {
1081 case ENGINEID_TYPE_IPV4: /* IPv4 */
1082 case ENGINEID_TYPE_IPV6: /* IPv6 */
1083 /*
1084 * IPV? is always good
1085 */
1086 break;
1087#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
1088 case ENGINEID_TYPE_MACADDR: /* MAC address */
1089 break;
1090#endif
1091 default:
1092 /*
1093 * unsupported one chosen
1094 */
1095 config_perror("Unsupported enginedIDType, forcing IPv4");
1096 engineIDType = ENGINEID_TYPE_IPV4;
1097 }
1098 DEBUGMSGTL(("snmpv3", "engineIDType: %d\n", engineIDType));
1099}
1100
1101/*******************************************************************-o-******
1102 * engineIDNic_conf
1103 *
1104 * Parameters:
1105 * *word
1106 * *cptr
1107 *
1108 * Line syntax:
1109 * engineIDNic <string>
1110 * eth0 is default
1111 */
1112void
1113engineIDNic_conf(const char *word, char *cptr)
1114{
1115 /*
1116 * Make sure they haven't already specified the engineID via the
1117 * * configuration file
1118 */
1119 if (0 == engineIDIsSet)
1120 /*
1121 * engineID has NOT been set via configuration file
1122 */
1123 {
1124 /*
1125 * See if already set if so erase & release it
1126 */
1127 if (NULL != engineIDNic) {
1128 SNMP_FREE(engineIDNic);
1129 }
1130 engineIDNic = (u_char *) malloc(strlen(cptr) + 1);
1131 if (NULL != engineIDNic) {
1132 strcpy((char *) engineIDNic, cptr);
1133 DEBUGMSGTL(("snmpv3", "Initializing engineIDNic: %s\n",
1134 engineIDNic));
1135 } else {
1136 DEBUGMSGTL(("snmpv3",
1137 "Error allocating memory for engineIDNic!\n"));
1138 }
1139 } else {
1140 DEBUGMSGTL(("snmpv3",
1141 "NOT setting engineIDNic, engineID already set\n"));
1142 }
1143}
1144
1145/*******************************************************************-o-******
1146 * engineID_conf
1147 *
1148 * Parameters:
1149 * *word
1150 * *cptr
1151 *
1152 * This function reads a string from the configuration file and uses that
1153 * string to initialize the engineID. It's assumed to be human readable.
1154 */
1155void
1156engineID_conf(const char *word, char *cptr)
1157{
1158 setup_engineID(NULL, cptr);
1159 DEBUGMSGTL(("snmpv3", "initialized engineID with: %s\n", cptr));
1160}
1161
1162void
1163version_conf(const char *word, char *cptr)
1164{
1165 int valid = 0;
1166#ifndef NETSNMP_DISABLE_SNMPV1
1167 if ((strcmp(cptr, "1") == 0) ||
1168 (strcmp(cptr, "v1") == 0)) {
1169 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
1170 NETSNMP_DS_SNMP_VERSION_1); /* bogus value */
1171 valid = 1;
1172 }
1173#endif
1174#ifndef NETSNMP_DISABLE_SNMPV2C
1175 if ((strcasecmp(cptr, "2c") == 0) ||
1176 (strcasecmp(cptr, "v2c") == 0)) {
1177 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
1178 NETSNMP_DS_SNMP_VERSION_2c);
1179 valid = 1;
1180 }
1181#endif
1182 if ((strcasecmp(cptr, "3" ) == 0) ||
1183 (strcasecmp(cptr, "v3" ) == 0)) {
1184 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION,
1185 NETSNMP_DS_SNMP_VERSION_3);
1186 valid = 1;
1187 }
1188 if (!valid) {
1189 config_perror("Unknown version specification");
1190 return;
1191 }
1192 DEBUGMSGTL(("snmpv3", "set default version to %d\n",
1193 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1194 NETSNMP_DS_LIB_SNMPVERSION)));
1195}
1196
1197/*
1198 * oldengineID_conf(const char *, char *):
1199 *
1200 * Reads a octet string encoded engineID into the oldEngineID and
1201 * oldEngineIDLen pointers.
1202 */
1203void
1204oldengineID_conf(const char *word, char *cptr)
1205{
1206 read_config_read_octet_string(cptr, &oldEngineID, &oldEngineIDLength);
1207}
1208
1209/*
1210 * exactEngineID_conf(const char *, char *):
1211 *
1212 * Reads a octet string encoded engineID into the engineID and
1213 * engineIDLen pointers.
1214 */
1215void
1216exactEngineID_conf(const char *word, char *cptr)
1217{
1218 read_config_read_octet_string(cptr, &engineID, &engineIDLength);
1219 if (engineIDLength > MAX_ENGINEID_LENGTH) {
1220 netsnmp_config_error(
1221 "exactEngineID '%s' too long; truncating to %d bytes",
1222 cptr, MAX_ENGINEID_LENGTH);
1223 engineID[MAX_ENGINEID_LENGTH - 1] = '\0';
1224 engineIDLength = MAX_ENGINEID_LENGTH;
1225 }
1226 engineIDIsSet = 1;
1227 engineIDType = ENGINEID_TYPE_EXACT;
1228}
1229
1230
1231/*
1232 * merely call
1233 */
1234void
1235get_enginetime_alarm(unsigned int regnum, void *clientargs)
1236{
1237 /* we do this every so (rarely) often just to make sure we watch
1238 wrapping of the times() output */
1239 snmpv3_local_snmpEngineTime();
1240}
1241
1242/*******************************************************************-o-******
1243 * init_snmpv3
1244 *
1245 * Parameters:
1246 * *type Label for the config file "type" used by calling entity.
1247 *
1248 * Set time and engineID.
1249 * Set parsing functions for config file tokens.
1250 * Initialize SNMP Crypto API (SCAPI).
1251 */
1252void
1253init_snmpv3(const char *type)
1254{
1255#if SNMP_USE_TIMES
1256 struct tms dummy;
1257
1258 /* fixme: -1 is fault code... */
1259 snmpv3startClock = times(&dummy);
1260
1261 /* remember how many ticks per second there are, since times() returns this */
1262
1263 clockticks = sysconf(_SC_CLK_TCK);
1264
1265#endif /* SNMP_USE_TIMES */
1266
1267 gettimeofday(&snmpv3starttime, NULL);
1268
1269 if (!type)
1270 type = "__snmpapp__";
1271
1272 /*
1273 * we need to be called back later
1274 */
1275 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1276 SNMP_CALLBACK_POST_READ_CONFIG,
1277 init_snmpv3_post_config, NULL);
1278
1279 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1280 SNMP_CALLBACK_POST_PREMIB_READ_CONFIG,
1281 init_snmpv3_post_premib_config, NULL);
1282 /*
1283 * we need to be called back later
1284 */
1285 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
1286 snmpv3_store, (void *) strdup(type));
1287
1288 /*
1289 * Free stuff at shutdown time
1290 */
1291 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1292 SNMP_CALLBACK_SHUTDOWN,
1293 free_enginetime_on_shutdown, NULL);
1294
1295 /*
1296 * initialize submodules
1297 */
1298 /*
1299 * NOTE: this must be after the callbacks are registered above,
1300 * since they need to be called before the USM callbacks.
1301 */
1302 init_secmod();
1303
1304 /*
1305 * register all our configuration handlers (ack, there's a lot)
1306 */
1307
1308 /*
1309 * handle engineID setup before everything else which may depend on it
1310 */
1311 register_prenetsnmp_mib_handler(type, "engineID", engineID_conf, NULL,
1312 "string");
1313 register_prenetsnmp_mib_handler(type, "oldEngineID", oldengineID_conf,
1314 NULL, NULL);
1315 register_prenetsnmp_mib_handler(type, "exactEngineID", exactEngineID_conf,
1316 NULL, NULL);
1317 register_prenetsnmp_mib_handler(type, "engineIDType",
1318 engineIDType_conf, NULL, "num");
1319 register_prenetsnmp_mib_handler(type, "engineIDNic", engineIDNic_conf,
1320 NULL, "string");
1321 register_config_handler(type, "engineBoots", engineBoots_conf, NULL,
1322 NULL);
1323
1324 /*
1325 * default store config entries
1326 */
1327 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defSecurityName",
1328 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECNAME);
1329 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defContext",
1330 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CONTEXT);
1331 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPassphrase",
1332 NETSNMP_DS_LIBRARY_ID,
1333 NETSNMP_DS_LIB_PASSPHRASE);
1334 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthPassphrase",
1335 NETSNMP_DS_LIBRARY_ID,
1336 NETSNMP_DS_LIB_AUTHPASSPHRASE);
1337 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivPassphrase",
1338 NETSNMP_DS_LIBRARY_ID,
1339 NETSNMP_DS_LIB_PRIVPASSPHRASE);
1340 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthMasterKey",
1341 NETSNMP_DS_LIBRARY_ID,
1342 NETSNMP_DS_LIB_AUTHMASTERKEY);
1343 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivMasterKey",
1344 NETSNMP_DS_LIBRARY_ID,
1345 NETSNMP_DS_LIB_PRIVMASTERKEY);
1346 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defAuthLocalizedKey",
1347 NETSNMP_DS_LIBRARY_ID,
1348 NETSNMP_DS_LIB_AUTHLOCALIZEDKEY);
1349 netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defPrivLocalizedKey",
1350 NETSNMP_DS_LIBRARY_ID,
1351 NETSNMP_DS_LIB_PRIVLOCALIZEDKEY);
1352 register_config_handler("snmp", "defVersion", version_conf, NULL,
1353 "1|2c|3");
1354
1355 register_config_handler("snmp", "defAuthType", snmpv3_authtype_conf,
1356 NULL, "MD5|SHA");
1357 register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
1358 NULL,
1359#ifdef HAVE_AES
1360 "DES|AES");
1361#else
1362 "DES (AES support not available)");
1363#endif
1364 register_config_handler("snmp", "defSecurityLevel",
1365 snmpv3_secLevel_conf, NULL,
1366 "noAuthNoPriv|authNoPriv|authPriv");
1367 register_config_handler(type, "userSetAuthPass", usm_set_password,
1368 NULL, NULL);
1369 register_config_handler(type, "userSetPrivPass", usm_set_password,
1370 NULL, NULL);
1371 register_config_handler(type, "userSetAuthKey", usm_set_password, NULL,
1372 NULL);
1373 register_config_handler(type, "userSetPrivKey", usm_set_password, NULL,
1374 NULL);
1375 register_config_handler(type, "userSetAuthLocalKey", usm_set_password,
1376 NULL, NULL);
1377 register_config_handler(type, "userSetPrivLocalKey", usm_set_password,
1378 NULL, NULL);
1379}
1380
1381/*
1382 * initializations for SNMPv3 to be called after the configuration files
1383 * have been read.
1384 */
1385
1386int
1387init_snmpv3_post_config(int majorid, int minorid, void *serverarg,
1388 void *clientarg)
1389{
1390
1391 size_t engineIDLen;
1392 u_char *c_engineID;
1393
1394 c_engineID = snmpv3_generate_engineID(&engineIDLen);
1395
1396 if (engineIDLen == 0 || !c_engineID) {
1397 /*
1398 * Somethine went wrong - help!
1399 */
1400 SNMP_FREE(c_engineID);
1401 return SNMPERR_GENERR;
1402 }
1403
1404 /*
1405 * if our engineID has changed at all, the boots record must be set to 1
1406 */
1407 if (engineIDLen != (int) oldEngineIDLength ||
1408 oldEngineID == NULL || c_engineID == NULL ||
1409 memcmp(oldEngineID, c_engineID, engineIDLen) != 0) {
1410 engineBoots = 1;
1411 }
1412
1413 /*
1414 * set our local engineTime in the LCD timing cache
1415 */
1416 set_enginetime(c_engineID, engineIDLen,
1417 snmpv3_local_snmpEngineBoots(),
1418 snmpv3_local_snmpEngineTime(), TRUE);
1419
1420 SNMP_FREE(c_engineID);
1421 return SNMPERR_SUCCESS;
1422}
1423
1424int
1425init_snmpv3_post_premib_config(int majorid, int minorid, void *serverarg,
1426 void *clientarg)
1427{
1428 if (!engineIDIsSet)
1429 setup_engineID(NULL, NULL);
1430
1431 return SNMPERR_SUCCESS;
1432}
1433
1434/*******************************************************************-o-******
1435 * store_snmpv3
1436 *
1437 * Parameters:
1438 * *type
1439 */
1440int
1441snmpv3_store(int majorID, int minorID, void *serverarg, void *clientarg)
1442{
1443 char line[SNMP_MAXBUF_SMALL];
1444 u_char c_engineID[SNMP_MAXBUF_SMALL];
1445 int engineIDLen;
1446 const char *type = (const char *) clientarg;
1447
1448 if (type == NULL) /* should never happen, since the arg is ours */
1449 type = "unknown";
1450
1451 sprintf(line, "engineBoots %ld", engineBoots);
1452 read_config_store(type, line);
1453
1454 engineIDLen = snmpv3_get_engineID(c_engineID, SNMP_MAXBUF_SMALL);
1455
1456 if (engineIDLen) {
1457 /*
1458 * store the engineID used for this run
1459 */
1460 sprintf(line, "oldEngineID ");
1461 read_config_save_octet_string(line + strlen(line), c_engineID,
1462 engineIDLen);
1463 read_config_store(type, line);
1464 }
1465 return SNMPERR_SUCCESS;
1466} /* snmpv3_store() */
1467
1468u_long
1469snmpv3_local_snmpEngineBoots(void)
1470{
1471 return engineBoots;
1472}
1473
1474
1475/*******************************************************************-o-******
1476 * snmpv3_get_engineID
1477 *
1478 * Parameters:
1479 * *buf
1480 * buflen
1481 *
1482 * Returns:
1483 * Length of engineID On Success
1484 * SNMPERR_GENERR Otherwise.
1485 *
1486 *
1487 * Store engineID in buf; return the length.
1488 *
1489 */
1490size_t
1491snmpv3_get_engineID(u_char * buf, size_t buflen)
1492{
1493 /*
1494 * Sanity check.
1495 */
1496 if (!buf || (buflen < engineIDLength)) {
1497 return 0;
1498 }
Dave Shield41e26ab2011-02-25 11:10:00 +00001499 if (!engineID) {
1500 return 0;
1501 }
Dave Shield00ef5692011-02-22 08:55:48 +00001502
1503 memcpy(buf, engineID, engineIDLength);
1504 return engineIDLength;
1505
1506} /* end snmpv3_get_engineID() */
1507
1508/*******************************************************************-o-******
1509 * snmpv3_clone_engineID
1510 *
1511 * Parameters:
1512 * **dest
1513 * *dest_len
1514 * src
1515 * srclen
1516 *
1517 * Returns:
1518 * Length of engineID On Success
1519 * 0 Otherwise.
1520 *
1521 *
1522 * Clones engineID, creates memory
1523 *
1524 */
1525int
1526snmpv3_clone_engineID(u_char ** dest, size_t * destlen, u_char * src,
1527 size_t srclen)
1528{
1529 if (!dest || !destlen)
1530 return 0;
1531
1532 if (*dest) {
1533 SNMP_FREE(*dest);
1534 *dest = NULL;
1535 }
1536 *destlen = 0;
1537
1538 if (srclen && src) {
1539 *dest = (u_char *) malloc(srclen);
1540 if (*dest == NULL)
1541 return 0;
1542 memmove(*dest, src, srclen);
1543 *destlen = srclen;
1544 }
1545 return *destlen;
1546} /* end snmpv3_clone_engineID() */
1547
1548
1549/*******************************************************************-o-******
1550 * snmpv3_generate_engineID
1551 *
1552 * Parameters:
1553 * *length
1554 *
1555 * Returns:
1556 * Pointer to copy of engineID On Success.
1557 * NULL If malloc() or snmpv3_get_engineID()
1558 * fail.
1559 *
1560 * Generates a malloced copy of our engineID.
1561 *
1562 * 'length' is set to the length of engineID -OR- < 0 on failure.
1563 */
1564u_char *
1565snmpv3_generate_engineID(size_t * length)
1566{
1567 u_char *newID;
1568 newID = (u_char *) malloc(engineIDLength);
1569
1570 if (newID) {
1571 *length = snmpv3_get_engineID(newID, engineIDLength);
1572 }
1573
1574 if (*length == 0) {
1575 SNMP_FREE(newID);
1576 newID = NULL;
1577 }
1578
1579 return newID;
1580
1581} /* end snmpv3_generate_engineID() */
1582
1583/*
1584 * snmpv3_local_snmpEngineTime(): return the number of seconds since the
1585 * snmpv3 engine last incremented engine_boots
1586 */
1587u_long
1588snmpv3_local_snmpEngineTime(void)
1589{
1590#ifdef SNMP_USE_TIMES
1591 struct tms dummy;
1592 clock_t now = times(&dummy);
1593 /* fixme: -1 is fault code... */
1594 unsigned int result;
1595
1596 if (now < snmpv3startClock) {
1597 result = UINT_MAX - (snmpv3startClock - now);
1598 } else {
1599 result = now - snmpv3startClock;
1600 }
1601 if (result < lastcalltime) {
1602 /* wrapped */
1603 wrapcounter++;
1604 }
1605 lastcalltime = result;
1606 result = (UINT_MAX/clockticks)*wrapcounter + result/clockticks;
1607
1608 return result;
1609#else /* !SNMP_USE_TIMES */
1610 struct timeval now;
1611
1612 gettimeofday(&now, NULL);
1613 return calculate_sectime_diff(&now, &snmpv3starttime);
1614#endif /* HAVE_SYS_TIMES_H */
1615}
1616
1617
1618
1619/*
1620 * Code only for Linux systems
1621 */
1622#if defined(IFHWADDRLEN) && defined(SIOCGIFHWADDR)
1623static int
1624getHwAddress(const char *networkDevice, /* e.g. "eth0", "eth1" */
1625 char *addressOut)
1626{ /* return address. Len=IFHWADDRLEN */
1627 /*
1628 * getHwAddress(...)
1629 * *
1630 * * This function will return a Network Interfaces Card's Hardware
1631 * * address (aka MAC address).
1632 * *
1633 * * Input Parameter(s):
1634 * * networkDevice - a null terminated string with the name of a network
1635 * * device. Examples: eth0, eth1, etc...
1636 * *
1637 * * Output Parameter(s):
1638 * * addressOut - This is the binary value of the hardware address.
1639 * * This value is NOT converted into a hexadecimal string.
1640 * * The caller must pre-allocate for a return value of
1641 * * length IFHWADDRLEN
1642 * *
1643 * * Return value: This function will return zero (0) for success. If
1644 * * an error occurred the function will return -1.
1645 * *
1646 * * Caveats: This has only been tested on Ethernet networking cards.
1647 */
1648 int sock; /* our socket */
1649 struct ifreq request; /* struct which will have HW address */
1650
1651 if ((NULL == networkDevice) || (NULL == addressOut)) {
1652 return -1;
1653 }
1654 /*
1655 * In order to find out the hardware (MAC) address of our system under
1656 * * Linux we must do the following:
1657 * * 1. Create a socket
1658 * * 2. Do an ioctl(...) call with the SIOCGIFHWADDRLEN operation.
1659 */
1660 sock = socket(AF_INET, SOCK_DGRAM, 0);
1661 if (sock < 0) {
1662 return -1;
1663 }
1664 /*
1665 * erase the request block
1666 */
1667 memset(&request, 0, sizeof(request));
1668 /*
1669 * copy the name of the net device we want to find the HW address for
1670 */
Bart Van Asscheb24ee7c2012-01-04 08:40:39 +01001671 strlcpy(request.ifr_name, networkDevice, IFNAMSIZ);
Dave Shield00ef5692011-02-22 08:55:48 +00001672 /*
1673 * Get the HW address
1674 */
1675 if (ioctl(sock, SIOCGIFHWADDR, &request)) {
1676 close(sock);
1677 return -1;
1678 }
1679 close(sock);
1680 memcpy(addressOut, request.ifr_hwaddr.sa_data, IFHWADDRLEN);
1681 return 0;
1682}
1683#endif
1684
1685#ifdef NETSNMP_ENABLE_TESTING_CODE
1686/*
1687 * snmpv3_set_engineBootsAndTime(): this function does not exist. Go away.
1688 */
1689/*
1690 * It certainly should never be used, unless in a testing scenero,
1691 * which is why it was created
1692 */
1693void
1694snmpv3_set_engineBootsAndTime(int boots, int ttime)
1695{
1696 engineBoots = boots;
1697 gettimeofday(&snmpv3starttime, NULL);
1698 snmpv3starttime.tv_sec -= ttime;
1699}
1700#endif