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