2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Copyright (c) 2010 The FreeBSD Foundation
11 * Portions of this software were developed by Shteryana Sotirova Shopova
12 * under sponsorship from the FreeBSD Foundation.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
39 #include <sys/types.h>
40 #include <sys/socket.h>
51 #elif defined(HAVE_INTTYPES_H)
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
61 static void snmp_error_func(const char *, ...);
62 static void snmp_printf_func(const char *, ...);
64 void (*snmp_error)(const char *, ...) = snmp_error_func;
65 void (*snmp_printf)(const char *, ...) = snmp_printf_func;
68 * Get the next variable binding from the list.
69 * ASN errors on the sequence or the OID are always fatal.
72 get_var_binding(struct asn_buf *b, struct snmp_value *binding)
75 asn_len_t len, trailer;
78 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
79 snmp_error("cannot parse varbind header");
80 return (ASN_ERR_FAILED);
83 /* temporary truncate the length so that the parser does not
84 * eat up bytes behind the sequence in the case the encoding is
85 * wrong of inner elements. */
86 trailer = b->asn_len - len;
89 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
90 snmp_error("cannot parse binding objid");
91 return (ASN_ERR_FAILED);
93 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
94 snmp_error("cannot parse binding value header");
95 return (ASN_ERR_FAILED);
101 binding->syntax = SNMP_SYNTAX_NULL;
102 err = asn_get_null_raw(b, len);
105 case ASN_TYPE_INTEGER:
106 binding->syntax = SNMP_SYNTAX_INTEGER;
107 err = asn_get_integer_raw(b, len, &binding->v.integer);
110 case ASN_TYPE_OCTETSTRING:
111 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
112 binding->v.octetstring.octets = malloc(len);
113 if (binding->v.octetstring.octets == NULL) {
114 snmp_error("%s", strerror(errno));
115 return (ASN_ERR_FAILED);
117 binding->v.octetstring.len = len;
118 err = asn_get_octetstring_raw(b, len,
119 binding->v.octetstring.octets,
120 &binding->v.octetstring.len);
121 if (ASN_ERR_STOPPED(err)) {
122 free(binding->v.octetstring.octets);
123 binding->v.octetstring.octets = NULL;
128 binding->syntax = SNMP_SYNTAX_OID;
129 err = asn_get_objid_raw(b, len, &binding->v.oid);
132 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
133 binding->syntax = SNMP_SYNTAX_IPADDRESS;
134 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
137 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
138 binding->syntax = SNMP_SYNTAX_TIMETICKS;
139 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
142 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
143 binding->syntax = SNMP_SYNTAX_COUNTER;
144 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
147 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
148 binding->syntax = SNMP_SYNTAX_GAUGE;
149 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
152 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
153 binding->syntax = SNMP_SYNTAX_COUNTER64;
154 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
157 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
158 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
159 err = asn_get_null_raw(b, len);
162 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
163 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
164 err = asn_get_null_raw(b, len);
167 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
168 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
169 err = asn_get_null_raw(b, len);
173 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
175 snmp_error("bad binding value type 0x%x", type);
179 if (ASN_ERR_STOPPED(err)) {
180 snmp_error("cannot parse binding value");
185 snmp_error("ignoring junk at end of binding");
187 b->asn_len = trailer;
193 * Parse the different PDUs contents. Any ASN error in the outer components
194 * are fatal. Only errors in variable values may be tolerated. If all
195 * components can be parsed it returns either ASN_ERR_OK or the first
196 * error that was found.
199 snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
201 if (pdu->type == SNMP_PDU_TRAP) {
202 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
203 snmp_error("cannot parse trap enterprise");
204 return (ASN_ERR_FAILED);
206 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
207 snmp_error("cannot parse trap agent address");
208 return (ASN_ERR_FAILED);
210 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
211 snmp_error("cannot parse 'generic-trap'");
212 return (ASN_ERR_FAILED);
214 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
215 snmp_error("cannot parse 'specific-trap'");
216 return (ASN_ERR_FAILED);
218 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
219 snmp_error("cannot parse trap 'time-stamp'");
220 return (ASN_ERR_FAILED);
223 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
224 snmp_error("cannot parse 'request-id'");
225 return (ASN_ERR_FAILED);
227 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
228 snmp_error("cannot parse 'error_status'");
229 return (ASN_ERR_FAILED);
231 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
232 snmp_error("cannot parse 'error_index'");
233 return (ASN_ERR_FAILED);
237 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
238 snmp_error("cannot get varlist header");
239 return (ASN_ERR_FAILED);
246 parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
248 asn_len_t len, trailer;
249 struct snmp_value *v;
250 enum asn_err err, err1;
252 err = snmp_parse_pdus_hdr(b, pdu, &len);
253 if (ASN_ERR_STOPPED(err))
256 trailer = b->asn_len - len;
260 while (b->asn_len != 0) {
261 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
262 snmp_error("too many bindings (> %u) in PDU",
264 return (ASN_ERR_FAILED);
266 err1 = get_var_binding(b, v);
267 if (ASN_ERR_STOPPED(err1))
268 return (ASN_ERR_FAILED);
269 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
271 *ip = pdu->nbindings + 1;
277 b->asn_len = trailer;
284 parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
287 u_char buf[256]; /* XXX: calc max possible size here */
295 if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) {
296 snmp_error("cannot parse usm header");
297 return (ASN_ERR_FAILED);
301 if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
302 snmp_error("cannot decode usm header");
303 return (ASN_ERR_FAILED);
306 octs_len = SNMP_ENGINE_ID_SIZ;
307 if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
308 &octs_len) != ASN_ERR_OK) {
309 snmp_error("cannot decode msg engine id");
310 return (ASN_ERR_FAILED);
312 pdu->engine.engine_len = octs_len;
314 if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
315 snmp_error("cannot decode msg engine boots");
316 return (ASN_ERR_FAILED);
319 if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
320 snmp_error("cannot decode msg engine time");
321 return (ASN_ERR_FAILED);
324 octs_len = SNMP_ADM_STR32_SIZ - 1;
325 if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
327 snmp_error("cannot decode msg user name");
328 return (ASN_ERR_FAILED);
330 pdu->user.sec_name[octs_len] = '\0';
332 octs_len = sizeof(pdu->msg_digest);
333 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
334 ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
335 octs_len != sizeof(pdu->msg_digest))) {
336 snmp_error("cannot decode msg authentication param");
337 return (ASN_ERR_FAILED);
340 octs_len = sizeof(pdu->msg_salt);
341 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
342 ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
343 octs_len != sizeof(pdu->msg_salt))) {
344 snmp_error("cannot decode msg authentication param");
345 return (ASN_ERR_FAILED);
348 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
349 pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
350 pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
356 static enum snmp_code
357 pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
359 u_char buf[256], *sptr;
361 size_t auth_off, moved = 0;
368 if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
369 &sptr) != ASN_ERR_OK)
370 return (SNMP_CODE_FAILED);
372 if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
373 pdu->engine.engine_len) != ASN_ERR_OK)
374 return (SNMP_CODE_FAILED);
376 if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
377 return (SNMP_CODE_FAILED);
379 if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
380 return (SNMP_CODE_FAILED);
382 if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
383 strlen(pdu->user.sec_name)) != ASN_ERR_OK)
384 return (SNMP_CODE_FAILED);
386 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
387 auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
388 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
389 sizeof(pdu->msg_digest)) != ASN_ERR_OK)
390 return (SNMP_CODE_FAILED);
392 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
394 return (SNMP_CODE_FAILED);
397 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
398 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
399 sizeof(pdu->msg_salt)) != ASN_ERR_OK)
400 return (SNMP_CODE_FAILED);
402 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
404 return (SNMP_CODE_FAILED);
407 if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
408 return (SNMP_CODE_FAILED);
410 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
411 pdu->digest_ptr = b->asn_ptr + auth_off - moved;
413 if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
414 return (SNMP_CODE_FAILED);
415 pdu->digest_ptr += ASN_MAXLENLEN;
417 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
418 ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
419 return (SNMP_CODE_FAILED);
421 return (SNMP_CODE_OK);
425 * Decode the PDU except for the variable bindings itself.
426 * If decoding fails because of a bad binding, but the rest can be
427 * decoded, ip points to the index of the failed variable (errors
428 * OORANGE, BADLEN or BADVERS).
431 snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
435 if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
438 if (pdu->version == SNMP_V3) {
439 if (pdu->security_model != SNMP_SECMODEL_USM)
440 return (SNMP_CODE_FAILED);
441 if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
445 code = snmp_pdu_decode_scoped(b, pdu, ip);
448 case SNMP_CODE_FAILED:
452 case SNMP_CODE_BADENC:
453 if (pdu->version == SNMP_Verr)
454 return (SNMP_CODE_BADVERS);
464 snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
470 pdu->outer_ptr = b->asn_ptr;
471 pdu->outer_len = b->asn_len;
473 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
474 snmp_error("cannot decode pdu header");
475 return (SNMP_CODE_FAILED);
477 if (b->asn_len < len) {
478 snmp_error("outer sequence value too short");
479 return (SNMP_CODE_FAILED);
481 if (b->asn_len != len) {
482 snmp_error("ignoring trailing junk in message");
486 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
487 snmp_error("cannot decode version");
488 return (SNMP_CODE_FAILED);
492 pdu->version = SNMP_V1;
493 else if (version == 1)
494 pdu->version = SNMP_V2c;
495 else if (version == 3)
496 pdu->version = SNMP_V3;
498 pdu->version = SNMP_Verr;
499 snmp_error("unsupported SNMP version");
500 return (SNMP_CODE_BADENC);
503 if (pdu->version == SNMP_V3) {
504 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
505 snmp_error("cannot decode pdu global data header");
506 return (SNMP_CODE_FAILED);
509 if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
510 snmp_error("cannot decode msg indetifier");
511 return (SNMP_CODE_FAILED);
514 if (asn_get_integer(b, &pdu->engine.max_msg_size)
516 snmp_error("cannot decode msg size");
517 return (SNMP_CODE_FAILED);
521 if (asn_get_octetstring(b, (u_char *)&pdu->flags,
522 &octs_len) != ASN_ERR_OK) {
523 snmp_error("cannot decode msg flags");
524 return (SNMP_CODE_FAILED);
527 if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
528 snmp_error("cannot decode msg size");
529 return (SNMP_CODE_FAILED);
532 if (pdu->security_model != SNMP_SECMODEL_USM)
533 return (SNMP_CODE_FAILED);
535 if (parse_secparams(b, pdu) != ASN_ERR_OK)
536 return (SNMP_CODE_FAILED);
538 octs_len = SNMP_COMMUNITY_MAXLEN;
539 if (asn_get_octetstring(b, (u_char *)pdu->community,
540 &octs_len) != ASN_ERR_OK) {
541 snmp_error("cannot decode community");
542 return (SNMP_CODE_FAILED);
544 pdu->community[octs_len] = '\0';
547 return (SNMP_CODE_OK);
551 snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
554 asn_len_t len, trailer;
557 if (pdu->version == SNMP_V3) {
558 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
559 snmp_error("cannot decode scoped pdu header");
560 return (SNMP_CODE_FAILED);
563 len = SNMP_ENGINE_ID_SIZ;
564 if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
565 &len) != ASN_ERR_OK) {
566 snmp_error("cannot decode msg context engine");
567 return (SNMP_CODE_FAILED);
569 pdu->context_engine_len = len;
571 len = SNMP_CONTEXT_NAME_SIZ;
572 if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
573 &len) != ASN_ERR_OK) {
574 snmp_error("cannot decode msg context name");
575 return (SNMP_CODE_FAILED);
577 pdu->context_name[len] = '\0';
580 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
581 snmp_error("cannot get pdu header");
582 return (SNMP_CODE_FAILED);
584 if ((type & ~ASN_TYPE_MASK) !=
585 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
586 snmp_error("bad pdu header tag");
587 return (SNMP_CODE_FAILED);
589 pdu->type = type & ASN_TYPE_MASK;
594 case SNMP_PDU_GETNEXT:
595 case SNMP_PDU_RESPONSE:
600 if (pdu->version != SNMP_V1) {
601 snmp_error("bad pdu type %u", pdu->type);
602 return (SNMP_CODE_FAILED);
606 case SNMP_PDU_GETBULK:
607 case SNMP_PDU_INFORM:
609 case SNMP_PDU_REPORT:
610 if (pdu->version == SNMP_V1) {
611 snmp_error("bad pdu type %u", pdu->type);
612 return (SNMP_CODE_FAILED);
617 snmp_error("bad pdu type %u", pdu->type);
618 return (SNMP_CODE_FAILED);
621 trailer = b->asn_len - len;
624 err = parse_pdus(b, pdu, ip);
625 if (ASN_ERR_STOPPED(err))
626 return (SNMP_CODE_FAILED);
629 snmp_error("ignoring trailing junk after pdu");
631 b->asn_len = trailer;
633 return (SNMP_CODE_OK);
637 snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
641 uint8_t digest[SNMP_USM_AUTH_SIZE];
643 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
644 (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
645 return (SNMP_CODE_BADSECLEVEL);
647 if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
649 return (SNMP_CODE_FAILED);
651 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
652 memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
653 return (SNMP_CODE_BADDIGEST);
655 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
656 &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
657 snmp_error("cannot decode encrypted pdu");
658 return (SNMP_CODE_FAILED);
660 pdu->scoped_ptr = b->asn_ptr;
662 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
663 (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
664 return (SNMP_CODE_BADSECLEVEL);
666 if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
667 return (SNMP_CODE_FAILED);
673 * Check whether what we have is the complete PDU by snooping at the
674 * enclosing structure header. This returns:
675 * -1 if there are ASN.1 errors
676 * 0 if we need more data
677 * > 0 the length of this PDU
680 snmp_pdu_snoop(const struct asn_buf *b0)
684 struct asn_buf b = *b0;
686 /* <0x10|0x20> <len> <data...> */
690 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
691 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
700 if (*b.asn_cptr & 0x80) {
702 length = *b.asn_cptr++ & 0x7f;
705 asn_error(&b, "indefinite length not supported");
708 if (length > ASN_MAXLENLEN) {
709 asn_error(&b, "long length too long (%u)", length);
712 if (length > b.asn_len)
716 len = (len << 8) | *b.asn_cptr++;
727 return (len + b.asn_cptr - b0->asn_cptr);
731 * Encode the SNMP PDU without the variable bindings field.
732 * We do this the rather uneffective way by
733 * moving things around and assuming that the length field will never
734 * use more than 2 bytes.
735 * We need a number of pointers to apply the fixes afterwards.
738 snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
743 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
744 &pdu->outer_ptr) != ASN_ERR_OK)
745 return (SNMP_CODE_FAILED);
747 if (pdu->version == SNMP_V1)
748 err = asn_put_integer(b, 0);
749 else if (pdu->version == SNMP_V2c)
750 err = asn_put_integer(b, 1);
751 else if (pdu->version == SNMP_V3)
752 err = asn_put_integer(b, 3);
754 return (SNMP_CODE_BADVERS);
755 if (err != ASN_ERR_OK)
756 return (SNMP_CODE_FAILED);
758 if (pdu->version == SNMP_V3) {
759 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
760 ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
761 return (SNMP_CODE_FAILED);
763 if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
764 return (SNMP_CODE_FAILED);
766 if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
767 return (SNMP_CODE_FAILED);
769 if (pdu->type != SNMP_PDU_RESPONSE &&
770 pdu->type != SNMP_PDU_TRAP &&
771 pdu->type != SNMP_PDU_TRAP2 &&
772 pdu->type != SNMP_PDU_REPORT)
773 pdu->flags |= SNMP_MSG_REPORT_FLAG;
775 if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
777 return (SNMP_CODE_FAILED);
779 if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
780 return (SNMP_CODE_FAILED);
782 if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
783 return (SNMP_CODE_FAILED);
785 if (pdu->security_model != SNMP_SECMODEL_USM)
786 return (SNMP_CODE_FAILED);
788 if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
789 return (SNMP_CODE_FAILED);
791 /* View-based Access Conntrol information */
792 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
793 ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
794 return (SNMP_CODE_FAILED);
796 if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
797 pdu->context_engine_len) != ASN_ERR_OK)
798 return (SNMP_CODE_FAILED);
800 if (asn_put_octetstring(b, (u_char *)pdu->context_name,
801 strlen(pdu->context_name)) != ASN_ERR_OK)
802 return (SNMP_CODE_FAILED);
804 if (asn_put_octetstring(b, (u_char *)pdu->community,
805 strlen(pdu->community)) != ASN_ERR_OK)
806 return (SNMP_CODE_FAILED);
809 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
810 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
811 return (SNMP_CODE_FAILED);
813 if (pdu->type == SNMP_PDU_TRAP) {
814 if (pdu->version != SNMP_V1 ||
815 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
816 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
817 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
818 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
819 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
820 return (SNMP_CODE_FAILED);
822 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
823 pdu->type == SNMP_PDU_INFORM ||
824 pdu->type == SNMP_PDU_TRAP2 ||
825 pdu->type == SNMP_PDU_REPORT))
826 return (SNMP_CODE_FAILED);
828 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
829 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
830 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
831 return (SNMP_CODE_FAILED);
834 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
835 &pdu->vars_ptr) != ASN_ERR_OK)
836 return (SNMP_CODE_FAILED);
838 return (SNMP_CODE_OK);
842 snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
846 if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
847 padlen = 8 - (pdu->scoped_len % 8);
848 if (asn_pad(b, padlen) != ASN_ERR_OK)
849 return (ASN_ERR_FAILED);
850 pdu->scoped_len += padlen;
857 snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
862 if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
863 asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
864 return (SNMP_CODE_FAILED);
866 if (pdu->version == SNMP_V3) {
867 if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
868 return (SNMP_CODE_FAILED);
870 pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
871 if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK)
872 return (SNMP_CODE_FAILED);
874 if (pdu->security_model != SNMP_SECMODEL_USM)
875 return (SNMP_CODE_FAILED);
877 if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
878 return (SNMP_CODE_FAILED);
880 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
881 asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
882 return (SNMP_CODE_FAILED);
885 if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
886 return (SNMP_CODE_FAILED);
888 pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
889 pdu->digest_ptr -= moved;
891 if (pdu->version == SNMP_V3) {
892 if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
894 return (SNMP_CODE_FAILED);
896 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
897 memcpy(pdu->digest_ptr, pdu->msg_digest,
898 sizeof(pdu->msg_digest));
901 return (SNMP_CODE_OK);
905 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
906 * Be sure not to cobber b, when something fails.
909 snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
913 struct asn_buf save = *b;
915 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
916 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
921 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
926 switch (binding->syntax) {
928 case SNMP_SYNTAX_NULL:
929 err = asn_put_null(b);
932 case SNMP_SYNTAX_INTEGER:
933 err = asn_put_integer(b, binding->v.integer);
936 case SNMP_SYNTAX_OCTETSTRING:
937 err = asn_put_octetstring(b, binding->v.octetstring.octets,
938 binding->v.octetstring.len);
941 case SNMP_SYNTAX_OID:
942 err = asn_put_objid(b, &binding->v.oid);
945 case SNMP_SYNTAX_IPADDRESS:
946 err = asn_put_ipaddress(b, binding->v.ipaddress);
949 case SNMP_SYNTAX_TIMETICKS:
950 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
953 case SNMP_SYNTAX_COUNTER:
954 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
957 case SNMP_SYNTAX_GAUGE:
958 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
961 case SNMP_SYNTAX_COUNTER64:
962 err = asn_put_counter64(b, binding->v.counter64);
965 case SNMP_SYNTAX_NOSUCHOBJECT:
966 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
969 case SNMP_SYNTAX_NOSUCHINSTANCE:
970 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
973 case SNMP_SYNTAX_ENDOFMIBVIEW:
974 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
978 if (err != ASN_ERR_OK) {
983 err = asn_commit_header(b, ptr, NULL);
984 if (err != ASN_ERR_OK) {
996 snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
1001 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
1003 for (idx = 0; idx < pdu->nbindings; idx++)
1004 if (snmp_binding_encode(resp_b, &pdu->bindings[idx])
1006 return (SNMP_CODE_FAILED);
1008 return (snmp_fix_encoding(resp_b, pdu));
1012 dump_binding(const struct snmp_value *b)
1015 char buf[ASN_OIDSTRLEN];
1017 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1018 switch (b->syntax) {
1020 case SNMP_SYNTAX_NULL:
1021 snmp_printf("NULL");
1024 case SNMP_SYNTAX_INTEGER:
1025 snmp_printf("INTEGER %d", b->v.integer);
1028 case SNMP_SYNTAX_OCTETSTRING:
1029 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1030 for (i = 0; i < b->v.octetstring.len; i++)
1031 snmp_printf(" %02x", b->v.octetstring.octets[i]);
1034 case SNMP_SYNTAX_OID:
1035 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1038 case SNMP_SYNTAX_IPADDRESS:
1039 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1040 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1043 case SNMP_SYNTAX_COUNTER:
1044 snmp_printf("COUNTER %u", b->v.uint32);
1047 case SNMP_SYNTAX_GAUGE:
1048 snmp_printf("GAUGE %u", b->v.uint32);
1051 case SNMP_SYNTAX_TIMETICKS:
1052 snmp_printf("TIMETICKS %u", b->v.uint32);
1055 case SNMP_SYNTAX_COUNTER64:
1056 snmp_printf("COUNTER64 %lld", b->v.counter64);
1059 case SNMP_SYNTAX_NOSUCHOBJECT:
1060 snmp_printf("NoSuchObject");
1063 case SNMP_SYNTAX_NOSUCHINSTANCE:
1064 snmp_printf("NoSuchInstance");
1067 case SNMP_SYNTAX_ENDOFMIBVIEW:
1068 snmp_printf("EndOfMibView");
1072 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1077 static __inline void
1078 dump_bindings(const struct snmp_pdu *pdu)
1082 for (i = 0; i < pdu->nbindings; i++) {
1083 snmp_printf(" [%u]: ", i);
1084 dump_binding(&pdu->bindings[i]);
1089 static __inline void
1090 dump_notrap(const struct snmp_pdu *pdu)
1092 snmp_printf(" request_id=%d", pdu->request_id);
1093 snmp_printf(" error_status=%d", pdu->error_status);
1094 snmp_printf(" error_index=%d\n", pdu->error_index);
1099 snmp_pdu_dump(const struct snmp_pdu *pdu)
1101 char buf[ASN_OIDSTRLEN];
1103 static const char *types[] = {
1104 [SNMP_PDU_GET] = "GET",
1105 [SNMP_PDU_GETNEXT] = "GETNEXT",
1106 [SNMP_PDU_RESPONSE] = "RESPONSE",
1107 [SNMP_PDU_SET] = "SET",
1108 [SNMP_PDU_TRAP] = "TRAPv1",
1109 [SNMP_PDU_GETBULK] = "GETBULK",
1110 [SNMP_PDU_INFORM] = "INFORM",
1111 [SNMP_PDU_TRAP2] = "TRAPv2",
1112 [SNMP_PDU_REPORT] = "REPORT",
1115 if (pdu->version == SNMP_V1)
1117 else if (pdu->version == SNMP_V2c)
1119 else if (pdu->version == SNMP_V3)
1124 switch (pdu->type) {
1126 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1127 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1128 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1129 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1130 snmp_printf(" generic_trap=%d", pdu->generic_trap);
1131 snmp_printf(" specific_trap=%d", pdu->specific_trap);
1132 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1137 case SNMP_PDU_GETNEXT:
1138 case SNMP_PDU_RESPONSE:
1140 case SNMP_PDU_GETBULK:
1141 case SNMP_PDU_INFORM:
1142 case SNMP_PDU_TRAP2:
1143 case SNMP_PDU_REPORT:
1144 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1149 snmp_printf("bad pdu type %u\n", pdu->type);
1155 snmp_value_free(struct snmp_value *value)
1158 if (value->syntax == SNMP_SYNTAX_OCTETSTRING) {
1159 free(value->v.octetstring.octets);
1160 value->v.octetstring.octets = NULL;
1162 value->syntax = SNMP_SYNTAX_NULL;
1166 snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1168 to->var = from->var;
1169 to->syntax = from->syntax;
1171 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1172 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1173 to->v.octetstring.octets = NULL;
1175 to->v.octetstring.octets = malloc(to->v.octetstring.len);
1176 if (to->v.octetstring.octets == NULL)
1178 (void)memcpy(to->v.octetstring.octets,
1179 from->v.octetstring.octets, to->v.octetstring.len);
1187 snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1191 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1192 pdu->flags |= SNMP_MSG_AUTH_FLAG;
1194 switch (pdu->user.priv_proto) {
1196 memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1197 sizeof(pdu->engine.engine_boots));
1199 memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1201 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1205 memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1207 memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1208 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1216 snmp_pdu_free(struct snmp_pdu *pdu)
1220 for (i = 0; i < pdu->nbindings; i++)
1221 snmp_value_free(&pdu->bindings[i]);
1226 * Parse an ASCII SNMP value into the binary form
1229 snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1235 case SNMP_SYNTAX_NULL:
1236 case SNMP_SYNTAX_NOSUCHOBJECT:
1237 case SNMP_SYNTAX_NOSUCHINSTANCE:
1238 case SNMP_SYNTAX_ENDOFMIBVIEW:
1243 case SNMP_SYNTAX_INTEGER:
1244 v->integer = strtoll(str, &end, 0);
1249 case SNMP_SYNTAX_OCTETSTRING:
1251 u_long len; /* actual length of string */
1252 u_long alloc; /* allocate length of string */
1253 u_char *octs; /* actual octets */
1254 u_long oct; /* actual octet */
1255 u_char *nocts; /* to avoid memory leak */
1256 u_char c; /* actual character */
1258 # define STUFFC(C) \
1259 if (alloc == len) { \
1261 if ((nocts = realloc(octs, alloc)) == NULL) { \
1274 while((c = *str++) != '\0') {
1283 switch (c = *str++) {
1310 if (!isxdigit(*str))
1314 else if (isupper(*str))
1315 c = *str++ - 'A' + 10;
1317 c = *str++ - 'a' + 10;
1318 if (!isxdigit(*str))
1322 else if (isupper(*str))
1323 c += *str++ - 'A' + 10;
1325 c += *str++ - 'a' + 10;
1327 case '0': case '1': case '2':
1328 case '3': case '4': case '5':
1331 if (*str < '0' || *str > '7')
1334 if (*str < '0' || *str > '7')
1345 while (*str != '\0') {
1346 oct = strtoul(str, &end, 16);
1355 else if(*str != '\0') {
1361 v->octetstring.octets = octs;
1362 v->octetstring.len = len;
1367 case SNMP_SYNTAX_OID:
1374 if (v->oid.len == ASN_MAXOIDLEN)
1376 subid = strtoul(str, &end, 10);
1378 if (subid > ASN_MAXID)
1380 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1390 case SNMP_SYNTAX_IPADDRESS:
1394 if (inet_pton(AF_INET, str, &v->ipaddress) == 1)
1396 if ((he = gethostbyname2(str, AF_INET)) == NULL)
1398 if (he->h_addrtype != AF_INET)
1401 memcpy(v->ipaddress, he->h_addr, sizeof(v->ipaddress));
1406 case SNMP_SYNTAX_COUNTER:
1407 case SNMP_SYNTAX_GAUGE:
1408 case SNMP_SYNTAX_TIMETICKS:
1412 sub = strtoull(str, &end, 0);
1413 if (*end != '\0' || sub > 0xffffffff)
1415 v->uint32 = (uint32_t)sub;
1419 case SNMP_SYNTAX_COUNTER64:
1420 v->counter64 = strtoull(str, &end, 0);
1429 snmp_error_func(const char *fmt, ...)
1434 fprintf(stderr, "SNMP: ");
1435 vfprintf(stderr, fmt, ap);
1436 fprintf(stderr, "\n");
1441 snmp_printf_func(const char *fmt, ...)
1446 vfprintf(stderr, fmt, ap);