Deleted Added
full compact
snmp.c (133211) snmp.c (150920)
1/*
2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1/*
2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: bsnmp/lib/snmp.c,v 1.38 2004/08/06 08:46:53 brandt Exp $
29 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
30 *
31 * SNMP
32 */
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stddef.h>
38#include <stdarg.h>
30 *
31 * SNMP
32 */
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stddef.h>
38#include <stdarg.h>
39#ifdef HAVE_STDINT_H
39#include <stdint.h>
40#include <stdint.h>
41#elif defined(HAVE_INTTYPES_H)
42#include <inttypes.h>
43#endif
40#include <string.h>
41#include <ctype.h>
42#include <netdb.h>
43#include <errno.h>
44
45#include "asn1.h"
46#include "snmp.h"
47#include "snmppriv.h"
48
49static void snmp_error_func(const char *, ...);
50static void snmp_printf_func(const char *, ...);
51
52void (*snmp_error)(const char *, ...) = snmp_error_func;
53void (*snmp_printf)(const char *, ...) = snmp_printf_func;
54
55/*
56 * Get the next variable binding from the list.
57 * ASN errors on the sequence or the OID are always fatal.
58 */
59static enum asn_err
60get_var_binding(struct asn_buf *b, struct snmp_value *binding)
61{
62 u_char type;
63 asn_len_t len, trailer;
64 enum asn_err err;
65
66 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
67 snmp_error("cannot parse varbind header");
68 return (ASN_ERR_FAILED);
69 }
70
71 /* temporary truncate the length so that the parser does not
72 * eat up bytes behind the sequence in the case the encoding is
73 * wrong of inner elements. */
74 trailer = b->asn_len - len;
75 b->asn_len = len;
76
77 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
78 snmp_error("cannot parse binding objid");
79 return (ASN_ERR_FAILED);
80 }
81 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
82 snmp_error("cannot parse binding value header");
83 return (ASN_ERR_FAILED);
84 }
85
86 switch (type) {
87
88 case ASN_TYPE_NULL:
89 binding->syntax = SNMP_SYNTAX_NULL;
90 err = asn_get_null_raw(b, len);
91 break;
92
93 case ASN_TYPE_INTEGER:
94 binding->syntax = SNMP_SYNTAX_INTEGER;
95 err = asn_get_integer_raw(b, len, &binding->v.integer);
96 break;
97
98 case ASN_TYPE_OCTETSTRING:
99 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
100 binding->v.octetstring.octets = malloc(len);
101 if (binding->v.octetstring.octets == NULL) {
102 snmp_error("%s", strerror(errno));
103 return (ASN_ERR_FAILED);
104 }
105 binding->v.octetstring.len = len;
106 err = asn_get_octetstring_raw(b, len,
107 binding->v.octetstring.octets,
108 &binding->v.octetstring.len);
109 if (ASN_ERR_STOPPED(err)) {
110 free(binding->v.octetstring.octets);
111 binding->v.octetstring.octets = NULL;
112 }
113 break;
114
115 case ASN_TYPE_OBJID:
116 binding->syntax = SNMP_SYNTAX_OID;
117 err = asn_get_objid_raw(b, len, &binding->v.oid);
118 break;
119
120 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
121 binding->syntax = SNMP_SYNTAX_IPADDRESS;
122 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
123 break;
124
125 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
126 binding->syntax = SNMP_SYNTAX_TIMETICKS;
127 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
128 break;
129
130 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
131 binding->syntax = SNMP_SYNTAX_COUNTER;
132 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
133 break;
134
135 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
136 binding->syntax = SNMP_SYNTAX_GAUGE;
137 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138 break;
139
140 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
141 binding->syntax = SNMP_SYNTAX_COUNTER64;
142 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
143 break;
144
145 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
146 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
147 err = asn_get_null_raw(b, len);
148 break;
149
150 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
151 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
152 err = asn_get_null_raw(b, len);
153 break;
154
155 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
156 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
157 err = asn_get_null_raw(b, len);
158 break;
159
160 default:
161 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
162 err = ASN_ERR_TAG;
163 snmp_error("bad binding value type 0x%x", type);
164 break;
165 }
166
167 if (ASN_ERR_STOPPED(err)) {
168 snmp_error("cannot parse binding value");
169 return (err);
170 }
171
172 if (b->asn_len != 0)
173 snmp_error("ignoring junk at end of binding");
174
175 b->asn_len = trailer;
176
177 return (err);
178}
179
180/*
181 * Parse the different PDUs contents. Any ASN error in the outer components
182 * are fatal. Only errors in variable values may be tolerated. If all
183 * components can be parsed it returns either ASN_ERR_OK or the first
184 * error that was found.
185 */
186enum asn_err
187snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
188{
189 if (pdu->type == SNMP_PDU_TRAP) {
190 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
191 snmp_error("cannot parse trap enterprise");
192 return (ASN_ERR_FAILED);
193 }
194 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
195 snmp_error("cannot parse trap agent address");
196 return (ASN_ERR_FAILED);
197 }
198 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
199 snmp_error("cannot parse 'generic-trap'");
200 return (ASN_ERR_FAILED);
201 }
202 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
203 snmp_error("cannot parse 'specific-trap'");
204 return (ASN_ERR_FAILED);
205 }
206 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
207 snmp_error("cannot parse trap 'time-stamp'");
208 return (ASN_ERR_FAILED);
209 }
210 } else {
211 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
212 snmp_error("cannot parse 'request-id'");
213 return (ASN_ERR_FAILED);
214 }
215 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
216 snmp_error("cannot parse 'error_status'");
217 return (ASN_ERR_FAILED);
218 }
219 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
220 snmp_error("cannot parse 'error_index'");
221 return (ASN_ERR_FAILED);
222 }
223 }
224
225 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
226 snmp_error("cannot get varlist header");
227 return (ASN_ERR_FAILED);
228 }
229
230 return (ASN_ERR_OK);
231}
232
233static enum asn_err
234parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
235{
236 asn_len_t len, trailer;
237 struct snmp_value *v;
238 enum asn_err err, err1;
239
240 err = snmp_parse_pdus_hdr(b, pdu, &len);
241 if (ASN_ERR_STOPPED(err))
242 return (err);
243
244 trailer = b->asn_len - len;
245
246 v = pdu->bindings;
247 err = ASN_ERR_OK;
248 while (b->asn_len != 0) {
249 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
250 snmp_error("too many bindings (> %u) in PDU",
251 SNMP_MAX_BINDINGS);
252 return (ASN_ERR_FAILED);
253 }
254 err1 = get_var_binding(b, v);
255 if (ASN_ERR_STOPPED(err1))
256 return (ASN_ERR_FAILED);
257 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
258 err = err1;
259 *ip = pdu->nbindings + 1;
260 }
261 pdu->nbindings++;
262 v++;
263 }
264
265 b->asn_len = trailer;
266
267 return (err);
268}
269
270/*
271 * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
272 */
273enum asn_err
274snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
275{
276 int32_t version;
277 u_char type;
278 u_int comm_len;
279
280 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
281 snmp_error("cannot decode version");
282 return (ASN_ERR_FAILED);
283 }
284
285 if (version == 0) {
286 pdu->version = SNMP_V1;
287 } else if (version == 1) {
288 pdu->version = SNMP_V2c;
289 } else {
290 pdu->version = SNMP_Verr;
291 snmp_error("unsupported SNMP version");
292 return (ASN_ERR_TAG);
293 }
294
295 comm_len = SNMP_COMMUNITY_MAXLEN;
296 if (asn_get_octetstring(b, (u_char *)pdu->community,
297 &comm_len) != ASN_ERR_OK) {
298 snmp_error("cannot decode community");
299 return (ASN_ERR_FAILED);
300 }
301 pdu->community[comm_len] = '\0';
302
303 if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
304 snmp_error("cannot get pdu header");
305 return (ASN_ERR_FAILED);
306 }
307 if ((type & ~ASN_TYPE_MASK) !=
308 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
309 snmp_error("bad pdu header tag");
310 return (ASN_ERR_FAILED);
311 }
312 pdu->type = type & ASN_TYPE_MASK;
313
314 switch (pdu->type) {
315
316 case SNMP_PDU_GET:
317 case SNMP_PDU_GETNEXT:
318 case SNMP_PDU_RESPONSE:
319 case SNMP_PDU_SET:
320 break;
321
322 case SNMP_PDU_TRAP:
323 if (pdu->version != SNMP_V1) {
324 snmp_error("bad pdu type %u", pdu->type);
325 return (ASN_ERR_FAILED);
326 }
327 break;
328
329 case SNMP_PDU_GETBULK:
330 case SNMP_PDU_INFORM:
331 case SNMP_PDU_TRAP2:
332 case SNMP_PDU_REPORT:
333 if (pdu->version == SNMP_V1) {
334 snmp_error("bad pdu type %u", pdu->type);
335 return (ASN_ERR_FAILED);
336 }
337 break;
338
339 default:
340 snmp_error("bad pdu type %u", pdu->type);
341 return (ASN_ERR_FAILED);
342 }
343
344
345 if (*lenp > b->asn_len) {
346 snmp_error("pdu length too long");
347 return (ASN_ERR_FAILED);
348 }
349
350 return (ASN_ERR_OK);
351}
352
353static enum asn_err
354parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
355{
356 enum asn_err err;
357 asn_len_t len, trailer;
358
359 err = snmp_parse_message_hdr(b, pdu, &len);
360 if (ASN_ERR_STOPPED(err))
361 return (err);
362
363 trailer = b->asn_len - len;
364 b->asn_len = len;
365
366 err = parse_pdus(b, pdu, ip);
367 if (ASN_ERR_STOPPED(err))
368 return (ASN_ERR_FAILED);
369
370 if (b->asn_len != 0)
371 snmp_error("ignoring trailing junk after pdu");
372
373 b->asn_len = trailer;
374
375 return (err);
376}
377
378/*
379 * Decode the PDU except for the variable bindings itself.
380 * If decoding fails because of a bad binding, but the rest can be
381 * decoded, ip points to the index of the failed variable (errors
382 * OORANGE, BADLEN or BADVERS).
383 */
384enum snmp_code
385snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
386{
387 asn_len_t len;
388
389 memset(pdu, 0, sizeof(*pdu));
390
391 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
392 snmp_error("cannot decode pdu header");
393 return (SNMP_CODE_FAILED);
394 }
395 if (b->asn_len < len) {
396 snmp_error("outer sequence value too short");
397 return (SNMP_CODE_FAILED);
398 }
399 if (b->asn_len != len) {
400 snmp_error("ignoring trailing junk in message");
401 b->asn_len = len;
402 }
403
404 switch (parse_message(b, pdu, ip)) {
405
406 case ASN_ERR_OK:
407 return (SNMP_CODE_OK);
408
409 case ASN_ERR_FAILED:
410 case ASN_ERR_EOBUF:
411 snmp_pdu_free(pdu);
412 return (SNMP_CODE_FAILED);
413
414 case ASN_ERR_BADLEN:
415 return (SNMP_CODE_BADLEN);
416
417 case ASN_ERR_RANGE:
418 return (SNMP_CODE_OORANGE);
419
420 case ASN_ERR_TAG:
421 if (pdu->version == SNMP_Verr)
422 return (SNMP_CODE_BADVERS);
423 else
424 return (SNMP_CODE_BADENC);
425 }
426
427 return (SNMP_CODE_OK);
428}
429
430/*
431 * Check whether what we have is the complete PDU by snooping at the
432 * enclosing structure header. This returns:
433 * -1 if there are ASN.1 errors
434 * 0 if we need more data
435 * > 0 the length of this PDU
436 */
437int
438snmp_pdu_snoop(const struct asn_buf *b0)
439{
440 u_int length;
441 asn_len_t len;
442 struct asn_buf b = *b0;
443
444 /* <0x10|0x20> <len> <data...> */
445
446 if (b.asn_len == 0)
447 return (0);
448 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
449 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
450 return (-1);
451 }
452 b.asn_len--;
453 b.asn_cptr++;
454
455 if (b.asn_len == 0)
456 return (0);
457
458 if (*b.asn_cptr & 0x80) {
459 /* long length */
460 length = *b.asn_cptr++ & 0x7f;
461 b.asn_len--;
462 if (length == 0) {
463 asn_error(&b, "indefinite length not supported");
464 return (-1);
465 }
466 if (length > ASN_MAXLENLEN) {
467 asn_error(&b, "long length too long (%u)", length);
468 return (-1);
469 }
470 if (length > b.asn_len)
471 return (0);
472 len = 0;
473 while (length--) {
474 len = (len << 8) | *b.asn_cptr++;
475 b.asn_len--;
476 }
477 } else {
478 len = *b.asn_cptr++;
479 b.asn_len--;
480 }
481
482 if (len > b.asn_len)
483 return (0);
484
485 return (len + b.asn_cptr - b0->asn_cptr);
486}
487
488/*
489 * Encode the SNMP PDU without the variable bindings field.
490 * We do this the rather uneffective way by
491 * moving things around and assuming that the length field will never
492 * use more than 2 bytes.
493 * We need a number of pointers to apply the fixes afterwards.
494 */
495enum snmp_code
496snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
497{
498 enum asn_err err;
499
500 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
501 &pdu->outer_ptr) != ASN_ERR_OK)
502 return (SNMP_CODE_FAILED);
503
504 if (pdu->version == SNMP_V1)
505 err = asn_put_integer(b, 0);
506 else if (pdu->version == SNMP_V2c)
507 err = asn_put_integer(b, 1);
508 else
509 return (SNMP_CODE_BADVERS);
510 if (err != ASN_ERR_OK)
511 return (SNMP_CODE_FAILED);
512
513 if (asn_put_octetstring(b, (u_char *)pdu->community,
514 strlen(pdu->community)) != ASN_ERR_OK)
515 return (SNMP_CODE_FAILED);
516
517 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
518 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
519 return (SNMP_CODE_FAILED);
520
521 if (pdu->type == SNMP_PDU_TRAP) {
522 if (pdu->version != SNMP_V1 ||
523 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
524 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
525 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
526 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
527 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
528 return (SNMP_CODE_FAILED);
529 } else {
530 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
531 pdu->type == SNMP_PDU_INFORM ||
532 pdu->type == SNMP_PDU_TRAP2 ||
533 pdu->type == SNMP_PDU_REPORT))
534 return (SNMP_CODE_FAILED);
535
536 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
537 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
538 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
539 return (SNMP_CODE_FAILED);
540 }
541
542 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
543 &pdu->vars_ptr) != ASN_ERR_OK)
544 return (SNMP_CODE_FAILED);
545
546 return (SNMP_CODE_OK);
547}
548
549enum snmp_code
550snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu)
551{
552 if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK ||
553 asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK ||
554 asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK)
555 return (SNMP_CODE_FAILED);
556 return (SNMP_CODE_OK);
557}
558
559/*
560 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
561 * Be sure not to cobber b, when something fails.
562 */
563enum asn_err
564snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
565{
566 u_char *ptr;
567 enum asn_err err;
568 struct asn_buf save = *b;
569
570 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
571 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
572 *b = save;
573 return (err);
574 }
575
576 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
577 *b = save;
578 return (err);
579 }
580
581 switch (binding->syntax) {
582
583 case SNMP_SYNTAX_NULL:
584 err = asn_put_null(b);
585 break;
586
587 case SNMP_SYNTAX_INTEGER:
588 err = asn_put_integer(b, binding->v.integer);
589 break;
590
591 case SNMP_SYNTAX_OCTETSTRING:
592 err = asn_put_octetstring(b, binding->v.octetstring.octets,
593 binding->v.octetstring.len);
594 break;
595
596 case SNMP_SYNTAX_OID:
597 err = asn_put_objid(b, &binding->v.oid);
598 break;
599
600 case SNMP_SYNTAX_IPADDRESS:
601 err = asn_put_ipaddress(b, binding->v.ipaddress);
602 break;
603
604 case SNMP_SYNTAX_TIMETICKS:
605 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
606 break;
607
608 case SNMP_SYNTAX_COUNTER:
609 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
610 break;
611
612 case SNMP_SYNTAX_GAUGE:
613 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
614 break;
615
616 case SNMP_SYNTAX_COUNTER64:
617 err = asn_put_counter64(b, binding->v.counter64);
618 break;
619
620 case SNMP_SYNTAX_NOSUCHOBJECT:
621 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
622 break;
623
624 case SNMP_SYNTAX_NOSUCHINSTANCE:
625 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
626 break;
627
628 case SNMP_SYNTAX_ENDOFMIBVIEW:
629 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
630 break;
631 }
632
633 if (err != ASN_ERR_OK) {
634 *b = save;
635 return (err);
636 }
637
638 err = asn_commit_header(b, ptr);
639 if (err != ASN_ERR_OK) {
640 *b = save;
641 return (err);
642 }
643
644 return (ASN_ERR_OK);
645}
646
647/*
648 * Encode an PDU.
649 */
650enum snmp_code
651snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
652{
653 u_int idx;
654 enum snmp_code err;
655
656 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
657 return (err);
658 for (idx = 0; idx < pdu->nbindings; idx++)
659 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
660 != ASN_ERR_OK)
661 return (SNMP_CODE_FAILED);
662
663 return (snmp_fix_encoding(resp_b, pdu));
664}
665
666static void
667dump_binding(const struct snmp_value *b)
668{
669 u_int i;
670 char buf[ASN_OIDSTRLEN];
671
672 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
673 switch (b->syntax) {
674
675 case SNMP_SYNTAX_NULL:
676 snmp_printf("NULL");
677 break;
678
679 case SNMP_SYNTAX_INTEGER:
680 snmp_printf("INTEGER %d", b->v.integer);
681 break;
682
683 case SNMP_SYNTAX_OCTETSTRING:
684 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
685 for (i = 0; i < b->v.octetstring.len; i++)
686 snmp_printf(" %02x", b->v.octetstring.octets[i]);
687 break;
688
689 case SNMP_SYNTAX_OID:
690 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
691 break;
692
693 case SNMP_SYNTAX_IPADDRESS:
694 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
695 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
696 break;
697
698 case SNMP_SYNTAX_COUNTER:
699 snmp_printf("COUNTER %u", b->v.uint32);
700 break;
701
702 case SNMP_SYNTAX_GAUGE:
703 snmp_printf("GAUGE %u", b->v.uint32);
704 break;
705
706 case SNMP_SYNTAX_TIMETICKS:
707 snmp_printf("TIMETICKS %u", b->v.uint32);
708 break;
709
710 case SNMP_SYNTAX_COUNTER64:
711 snmp_printf("COUNTER64 %lld", b->v.counter64);
712 break;
713
714 case SNMP_SYNTAX_NOSUCHOBJECT:
715 snmp_printf("NoSuchObject");
716 break;
717
718 case SNMP_SYNTAX_NOSUCHINSTANCE:
719 snmp_printf("NoSuchInstance");
720 break;
721
722 case SNMP_SYNTAX_ENDOFMIBVIEW:
723 snmp_printf("EndOfMibView");
724 break;
725
726 default:
727 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
728 break;
729 }
730}
731
732static __inline void
733dump_bindings(const struct snmp_pdu *pdu)
734{
735 u_int i;
736
737 for (i = 0; i < pdu->nbindings; i++) {
738 snmp_printf(" [%u]: ", i);
739 dump_binding(&pdu->bindings[i]);
740 snmp_printf("\n");
741 }
742}
743
744static __inline void
745dump_notrap(const struct snmp_pdu *pdu)
746{
747 snmp_printf(" request_id=%d", pdu->request_id);
748 snmp_printf(" error_status=%d", pdu->error_status);
749 snmp_printf(" error_index=%d\n", pdu->error_index);
750 dump_bindings(pdu);
751}
752
753void
754snmp_pdu_dump(const struct snmp_pdu *pdu)
755{
756 char buf[ASN_OIDSTRLEN];
757 const char *vers;
758 static const char *types[] = {
759 [SNMP_PDU_GET] = "GET",
760 [SNMP_PDU_GETNEXT] = "GETNEXT",
761 [SNMP_PDU_RESPONSE] = "RESPONSE",
762 [SNMP_PDU_SET] = "SET",
763 [SNMP_PDU_TRAP] = "TRAPv1",
764 [SNMP_PDU_GETBULK] = "GETBULK",
765 [SNMP_PDU_INFORM] = "INFORM",
766 [SNMP_PDU_TRAP2] = "TRAPv2",
767 [SNMP_PDU_REPORT] = "REPORT",
768 };
769
770 if (pdu->version == SNMP_V1)
771 vers = "SNMPv1";
772 else if (pdu->version == SNMP_V2c)
773 vers = "SNMPv2c";
774 else
775 vers = "v?";
776
777 switch (pdu->type) {
778 case SNMP_PDU_TRAP:
779 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
780 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
781 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
782 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
783 snmp_printf(" generic_trap=%d", pdu->generic_trap);
784 snmp_printf(" specific_trap=%d", pdu->specific_trap);
785 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
786 dump_bindings(pdu);
787 break;
788
789 case SNMP_PDU_GET:
790 case SNMP_PDU_GETNEXT:
791 case SNMP_PDU_RESPONSE:
792 case SNMP_PDU_SET:
793 case SNMP_PDU_GETBULK:
794 case SNMP_PDU_INFORM:
795 case SNMP_PDU_TRAP2:
796 case SNMP_PDU_REPORT:
797 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
798 dump_notrap(pdu);
799 break;
800
801 default:
802 snmp_printf("bad pdu type %u\n", pdu->type);
803 break;
804 }
805}
806
807void
808snmp_value_free(struct snmp_value *value)
809{
810 if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
811 free(value->v.octetstring.octets);
812 value->syntax = SNMP_SYNTAX_NULL;
813}
814
815int
816snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
817{
818 to->var = from->var;
819 to->syntax = from->syntax;
820
821 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
822 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
823 to->v.octetstring.octets = NULL;
824 else {
825 to->v.octetstring.octets = malloc(to->v.octetstring.len);
826 if (to->v.octetstring.octets == NULL)
827 return (-1);
828 (void)memcpy(to->v.octetstring.octets,
829 from->v.octetstring.octets, to->v.octetstring.len);
830 }
831 } else
832 to->v = from->v;
833 return (0);
834}
835
836void
837snmp_pdu_free(struct snmp_pdu *pdu)
838{
839 u_int i;
840
841 for (i = 0; i < pdu->nbindings; i++)
842 snmp_value_free(&pdu->bindings[i]);
843}
844
845/*
846 * Parse an ASCII SNMP value into the binary form
847 */
848int
849snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
850{
851 char *end;
852
853 switch (syntax) {
854
855 case SNMP_SYNTAX_NULL:
856 case SNMP_SYNTAX_NOSUCHOBJECT:
857 case SNMP_SYNTAX_NOSUCHINSTANCE:
858 case SNMP_SYNTAX_ENDOFMIBVIEW:
859 if (*str != '\0')
860 return (-1);
861 return (0);
862
863 case SNMP_SYNTAX_INTEGER:
864 v->integer = strtoll(str, &end, 0);
865 if (*end != '\0')
866 return (-1);
867 return (0);
868
869 case SNMP_SYNTAX_OCTETSTRING:
870 {
871 u_long len; /* actual length of string */
872 u_long alloc; /* allocate length of string */
873 u_char *octs; /* actual octets */
874 u_long oct; /* actual octet */
875 u_char *nocts; /* to avoid memory leak */
876 u_char c; /* actual character */
877
878# define STUFFC(C) \
879 if (alloc == len) { \
880 alloc += 100; \
881 if ((nocts = realloc(octs, alloc)) == NULL) { \
882 free(octs); \
883 return (-1); \
884 } \
885 octs = nocts; \
886 } \
887 octs[len++] = (C);
888
889 len = alloc = 0;
890 octs = NULL;
891
892 if (*str == '"') {
893 str++;
894 while((c = *str++) != '\0') {
895 if (c == '"') {
896 if (*str != '\0') {
897 free(octs);
898 return (-1);
899 }
900 break;
901 }
902 if (c == '\\') {
903 switch (c = *str++) {
904
905 case '\\':
906 break;
907 case 'a':
908 c = '\a';
909 break;
910 case 'b':
911 c = '\b';
912 break;
913 case 'f':
914 c = '\f';
915 break;
916 case 'n':
917 c = '\n';
918 break;
919 case 'r':
920 c = '\r';
921 break;
922 case 't':
923 c = '\t';
924 break;
925 case 'v':
926 c = '\v';
927 break;
928 case 'x':
929 c = 0;
930 if (!isxdigit(*str))
931 break;
932 if (isdigit(*str))
933 c = *str++ - '0';
934 else if (isupper(*str))
935 c = *str++ - 'A' + 10;
936 else
937 c = *str++ - 'a' + 10;
938 if (!isxdigit(*str))
939 break;
940 if (isdigit(*str))
941 c += *str++ - '0';
942 else if (isupper(*str))
943 c += *str++ - 'A' + 10;
944 else
945 c += *str++ - 'a' + 10;
946 break;
947 case '0': case '1': case '2':
948 case '3': case '4': case '5':
949 case '6': case '7':
950 c = *str++ - '0';
951 if (*str < '0' || *str > '7')
952 break;
953 c = *str++ - '0';
954 if (*str < '0' || *str > '7')
955 break;
956 c = *str++ - '0';
957 break;
958 default:
959 break;
960 }
961 }
962 STUFFC(c);
963 }
964 } else {
965 while (*str != '\0') {
966 oct = strtoul(str, &end, 16);
967 str = end;
968 if (oct > 0xff) {
969 free(octs);
970 return (-1);
971 }
972 STUFFC(oct);
973 if (*str == ':')
974 str++;
975 else if(*str != '\0') {
976 free(octs);
977 return (-1);
978 }
979 }
980 }
981 v->octetstring.octets = octs;
982 v->octetstring.len = len;
983 return (0);
984# undef STUFFC
985 }
986
987 case SNMP_SYNTAX_OID:
988 {
989 u_long subid;
990
991 v->oid.len = 0;
992
993 for (;;) {
994 if (v->oid.len == ASN_MAXOIDLEN)
995 return (-1);
996 subid = strtoul(str, &end, 10);
997 str = end;
998 if (subid > ASN_MAXID)
999 return (-1);
1000 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1001 if (*str == '\0')
1002 break;
1003 if (*str != '.')
1004 return (-1);
1005 str++;
1006 }
1007 return (0);
1008 }
1009
1010 case SNMP_SYNTAX_IPADDRESS:
1011 {
1012 struct hostent *he;
1013 u_long ip[4];
1014 int n;
1015
1016 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1017 &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1018 ip[0] <= 0xff && ip[1] <= 0xff &&
1019 ip[2] <= 0xff && ip[3] <= 0xff) {
1020 v->ipaddress[0] = (u_char)ip[0];
1021 v->ipaddress[1] = (u_char)ip[1];
1022 v->ipaddress[2] = (u_char)ip[2];
1023 v->ipaddress[3] = (u_char)ip[3];
1024 return (0);
1025 }
1026
1027 if ((he = gethostbyname(str)) == NULL)
1028 return (-1);
1029 if (he->h_addrtype != AF_INET)
1030 return (-1);
1031
1032 v->ipaddress[0] = he->h_addr[0];
1033 v->ipaddress[1] = he->h_addr[1];
1034 v->ipaddress[2] = he->h_addr[2];
1035 v->ipaddress[3] = he->h_addr[3];
1036 return (0);
1037 }
1038
1039 case SNMP_SYNTAX_COUNTER:
1040 case SNMP_SYNTAX_GAUGE:
1041 case SNMP_SYNTAX_TIMETICKS:
1042 {
1043 uint64_t sub;
1044
1045 sub = strtoull(str, &end, 0);
1046 if (*end != '\0' || sub > 0xffffffff)
1047 return (-1);
1048 v->uint32 = (uint32_t)sub;
1049 return (0);
1050 }
1051
1052 case SNMP_SYNTAX_COUNTER64:
1053 v->counter64 = strtoull(str, &end, 0);
1054 if (*end != '\0')
1055 return (-1);
1056 return (0);
1057 }
1058 abort();
1059}
1060
1061static void
1062snmp_error_func(const char *fmt, ...)
1063{
1064 va_list ap;
1065
1066 va_start(ap, fmt);
1067 fprintf(stderr, "SNMP: ");
1068 vfprintf(stderr, fmt, ap);
1069 fprintf(stderr, "\n");
1070 va_end(ap);
1071}
1072
1073static void
1074snmp_printf_func(const char *fmt, ...)
1075{
1076 va_list ap;
1077
1078 va_start(ap, fmt);
1079 vfprintf(stderr, fmt, ap);
1080 va_end(ap);
1081}
44#include <string.h>
45#include <ctype.h>
46#include <netdb.h>
47#include <errno.h>
48
49#include "asn1.h"
50#include "snmp.h"
51#include "snmppriv.h"
52
53static void snmp_error_func(const char *, ...);
54static void snmp_printf_func(const char *, ...);
55
56void (*snmp_error)(const char *, ...) = snmp_error_func;
57void (*snmp_printf)(const char *, ...) = snmp_printf_func;
58
59/*
60 * Get the next variable binding from the list.
61 * ASN errors on the sequence or the OID are always fatal.
62 */
63static enum asn_err
64get_var_binding(struct asn_buf *b, struct snmp_value *binding)
65{
66 u_char type;
67 asn_len_t len, trailer;
68 enum asn_err err;
69
70 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
71 snmp_error("cannot parse varbind header");
72 return (ASN_ERR_FAILED);
73 }
74
75 /* temporary truncate the length so that the parser does not
76 * eat up bytes behind the sequence in the case the encoding is
77 * wrong of inner elements. */
78 trailer = b->asn_len - len;
79 b->asn_len = len;
80
81 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
82 snmp_error("cannot parse binding objid");
83 return (ASN_ERR_FAILED);
84 }
85 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
86 snmp_error("cannot parse binding value header");
87 return (ASN_ERR_FAILED);
88 }
89
90 switch (type) {
91
92 case ASN_TYPE_NULL:
93 binding->syntax = SNMP_SYNTAX_NULL;
94 err = asn_get_null_raw(b, len);
95 break;
96
97 case ASN_TYPE_INTEGER:
98 binding->syntax = SNMP_SYNTAX_INTEGER;
99 err = asn_get_integer_raw(b, len, &binding->v.integer);
100 break;
101
102 case ASN_TYPE_OCTETSTRING:
103 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
104 binding->v.octetstring.octets = malloc(len);
105 if (binding->v.octetstring.octets == NULL) {
106 snmp_error("%s", strerror(errno));
107 return (ASN_ERR_FAILED);
108 }
109 binding->v.octetstring.len = len;
110 err = asn_get_octetstring_raw(b, len,
111 binding->v.octetstring.octets,
112 &binding->v.octetstring.len);
113 if (ASN_ERR_STOPPED(err)) {
114 free(binding->v.octetstring.octets);
115 binding->v.octetstring.octets = NULL;
116 }
117 break;
118
119 case ASN_TYPE_OBJID:
120 binding->syntax = SNMP_SYNTAX_OID;
121 err = asn_get_objid_raw(b, len, &binding->v.oid);
122 break;
123
124 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
125 binding->syntax = SNMP_SYNTAX_IPADDRESS;
126 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
127 break;
128
129 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
130 binding->syntax = SNMP_SYNTAX_TIMETICKS;
131 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
132 break;
133
134 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
135 binding->syntax = SNMP_SYNTAX_COUNTER;
136 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
137 break;
138
139 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
140 binding->syntax = SNMP_SYNTAX_GAUGE;
141 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
142 break;
143
144 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
145 binding->syntax = SNMP_SYNTAX_COUNTER64;
146 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
147 break;
148
149 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
150 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
151 err = asn_get_null_raw(b, len);
152 break;
153
154 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
155 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
156 err = asn_get_null_raw(b, len);
157 break;
158
159 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
160 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
161 err = asn_get_null_raw(b, len);
162 break;
163
164 default:
165 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
166 err = ASN_ERR_TAG;
167 snmp_error("bad binding value type 0x%x", type);
168 break;
169 }
170
171 if (ASN_ERR_STOPPED(err)) {
172 snmp_error("cannot parse binding value");
173 return (err);
174 }
175
176 if (b->asn_len != 0)
177 snmp_error("ignoring junk at end of binding");
178
179 b->asn_len = trailer;
180
181 return (err);
182}
183
184/*
185 * Parse the different PDUs contents. Any ASN error in the outer components
186 * are fatal. Only errors in variable values may be tolerated. If all
187 * components can be parsed it returns either ASN_ERR_OK or the first
188 * error that was found.
189 */
190enum asn_err
191snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
192{
193 if (pdu->type == SNMP_PDU_TRAP) {
194 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
195 snmp_error("cannot parse trap enterprise");
196 return (ASN_ERR_FAILED);
197 }
198 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
199 snmp_error("cannot parse trap agent address");
200 return (ASN_ERR_FAILED);
201 }
202 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
203 snmp_error("cannot parse 'generic-trap'");
204 return (ASN_ERR_FAILED);
205 }
206 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
207 snmp_error("cannot parse 'specific-trap'");
208 return (ASN_ERR_FAILED);
209 }
210 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
211 snmp_error("cannot parse trap 'time-stamp'");
212 return (ASN_ERR_FAILED);
213 }
214 } else {
215 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
216 snmp_error("cannot parse 'request-id'");
217 return (ASN_ERR_FAILED);
218 }
219 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
220 snmp_error("cannot parse 'error_status'");
221 return (ASN_ERR_FAILED);
222 }
223 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
224 snmp_error("cannot parse 'error_index'");
225 return (ASN_ERR_FAILED);
226 }
227 }
228
229 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
230 snmp_error("cannot get varlist header");
231 return (ASN_ERR_FAILED);
232 }
233
234 return (ASN_ERR_OK);
235}
236
237static enum asn_err
238parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
239{
240 asn_len_t len, trailer;
241 struct snmp_value *v;
242 enum asn_err err, err1;
243
244 err = snmp_parse_pdus_hdr(b, pdu, &len);
245 if (ASN_ERR_STOPPED(err))
246 return (err);
247
248 trailer = b->asn_len - len;
249
250 v = pdu->bindings;
251 err = ASN_ERR_OK;
252 while (b->asn_len != 0) {
253 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
254 snmp_error("too many bindings (> %u) in PDU",
255 SNMP_MAX_BINDINGS);
256 return (ASN_ERR_FAILED);
257 }
258 err1 = get_var_binding(b, v);
259 if (ASN_ERR_STOPPED(err1))
260 return (ASN_ERR_FAILED);
261 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
262 err = err1;
263 *ip = pdu->nbindings + 1;
264 }
265 pdu->nbindings++;
266 v++;
267 }
268
269 b->asn_len = trailer;
270
271 return (err);
272}
273
274/*
275 * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
276 */
277enum asn_err
278snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
279{
280 int32_t version;
281 u_char type;
282 u_int comm_len;
283
284 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
285 snmp_error("cannot decode version");
286 return (ASN_ERR_FAILED);
287 }
288
289 if (version == 0) {
290 pdu->version = SNMP_V1;
291 } else if (version == 1) {
292 pdu->version = SNMP_V2c;
293 } else {
294 pdu->version = SNMP_Verr;
295 snmp_error("unsupported SNMP version");
296 return (ASN_ERR_TAG);
297 }
298
299 comm_len = SNMP_COMMUNITY_MAXLEN;
300 if (asn_get_octetstring(b, (u_char *)pdu->community,
301 &comm_len) != ASN_ERR_OK) {
302 snmp_error("cannot decode community");
303 return (ASN_ERR_FAILED);
304 }
305 pdu->community[comm_len] = '\0';
306
307 if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
308 snmp_error("cannot get pdu header");
309 return (ASN_ERR_FAILED);
310 }
311 if ((type & ~ASN_TYPE_MASK) !=
312 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
313 snmp_error("bad pdu header tag");
314 return (ASN_ERR_FAILED);
315 }
316 pdu->type = type & ASN_TYPE_MASK;
317
318 switch (pdu->type) {
319
320 case SNMP_PDU_GET:
321 case SNMP_PDU_GETNEXT:
322 case SNMP_PDU_RESPONSE:
323 case SNMP_PDU_SET:
324 break;
325
326 case SNMP_PDU_TRAP:
327 if (pdu->version != SNMP_V1) {
328 snmp_error("bad pdu type %u", pdu->type);
329 return (ASN_ERR_FAILED);
330 }
331 break;
332
333 case SNMP_PDU_GETBULK:
334 case SNMP_PDU_INFORM:
335 case SNMP_PDU_TRAP2:
336 case SNMP_PDU_REPORT:
337 if (pdu->version == SNMP_V1) {
338 snmp_error("bad pdu type %u", pdu->type);
339 return (ASN_ERR_FAILED);
340 }
341 break;
342
343 default:
344 snmp_error("bad pdu type %u", pdu->type);
345 return (ASN_ERR_FAILED);
346 }
347
348
349 if (*lenp > b->asn_len) {
350 snmp_error("pdu length too long");
351 return (ASN_ERR_FAILED);
352 }
353
354 return (ASN_ERR_OK);
355}
356
357static enum asn_err
358parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
359{
360 enum asn_err err;
361 asn_len_t len, trailer;
362
363 err = snmp_parse_message_hdr(b, pdu, &len);
364 if (ASN_ERR_STOPPED(err))
365 return (err);
366
367 trailer = b->asn_len - len;
368 b->asn_len = len;
369
370 err = parse_pdus(b, pdu, ip);
371 if (ASN_ERR_STOPPED(err))
372 return (ASN_ERR_FAILED);
373
374 if (b->asn_len != 0)
375 snmp_error("ignoring trailing junk after pdu");
376
377 b->asn_len = trailer;
378
379 return (err);
380}
381
382/*
383 * Decode the PDU except for the variable bindings itself.
384 * If decoding fails because of a bad binding, but the rest can be
385 * decoded, ip points to the index of the failed variable (errors
386 * OORANGE, BADLEN or BADVERS).
387 */
388enum snmp_code
389snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
390{
391 asn_len_t len;
392
393 memset(pdu, 0, sizeof(*pdu));
394
395 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
396 snmp_error("cannot decode pdu header");
397 return (SNMP_CODE_FAILED);
398 }
399 if (b->asn_len < len) {
400 snmp_error("outer sequence value too short");
401 return (SNMP_CODE_FAILED);
402 }
403 if (b->asn_len != len) {
404 snmp_error("ignoring trailing junk in message");
405 b->asn_len = len;
406 }
407
408 switch (parse_message(b, pdu, ip)) {
409
410 case ASN_ERR_OK:
411 return (SNMP_CODE_OK);
412
413 case ASN_ERR_FAILED:
414 case ASN_ERR_EOBUF:
415 snmp_pdu_free(pdu);
416 return (SNMP_CODE_FAILED);
417
418 case ASN_ERR_BADLEN:
419 return (SNMP_CODE_BADLEN);
420
421 case ASN_ERR_RANGE:
422 return (SNMP_CODE_OORANGE);
423
424 case ASN_ERR_TAG:
425 if (pdu->version == SNMP_Verr)
426 return (SNMP_CODE_BADVERS);
427 else
428 return (SNMP_CODE_BADENC);
429 }
430
431 return (SNMP_CODE_OK);
432}
433
434/*
435 * Check whether what we have is the complete PDU by snooping at the
436 * enclosing structure header. This returns:
437 * -1 if there are ASN.1 errors
438 * 0 if we need more data
439 * > 0 the length of this PDU
440 */
441int
442snmp_pdu_snoop(const struct asn_buf *b0)
443{
444 u_int length;
445 asn_len_t len;
446 struct asn_buf b = *b0;
447
448 /* <0x10|0x20> <len> <data...> */
449
450 if (b.asn_len == 0)
451 return (0);
452 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
453 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
454 return (-1);
455 }
456 b.asn_len--;
457 b.asn_cptr++;
458
459 if (b.asn_len == 0)
460 return (0);
461
462 if (*b.asn_cptr & 0x80) {
463 /* long length */
464 length = *b.asn_cptr++ & 0x7f;
465 b.asn_len--;
466 if (length == 0) {
467 asn_error(&b, "indefinite length not supported");
468 return (-1);
469 }
470 if (length > ASN_MAXLENLEN) {
471 asn_error(&b, "long length too long (%u)", length);
472 return (-1);
473 }
474 if (length > b.asn_len)
475 return (0);
476 len = 0;
477 while (length--) {
478 len = (len << 8) | *b.asn_cptr++;
479 b.asn_len--;
480 }
481 } else {
482 len = *b.asn_cptr++;
483 b.asn_len--;
484 }
485
486 if (len > b.asn_len)
487 return (0);
488
489 return (len + b.asn_cptr - b0->asn_cptr);
490}
491
492/*
493 * Encode the SNMP PDU without the variable bindings field.
494 * We do this the rather uneffective way by
495 * moving things around and assuming that the length field will never
496 * use more than 2 bytes.
497 * We need a number of pointers to apply the fixes afterwards.
498 */
499enum snmp_code
500snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
501{
502 enum asn_err err;
503
504 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
505 &pdu->outer_ptr) != ASN_ERR_OK)
506 return (SNMP_CODE_FAILED);
507
508 if (pdu->version == SNMP_V1)
509 err = asn_put_integer(b, 0);
510 else if (pdu->version == SNMP_V2c)
511 err = asn_put_integer(b, 1);
512 else
513 return (SNMP_CODE_BADVERS);
514 if (err != ASN_ERR_OK)
515 return (SNMP_CODE_FAILED);
516
517 if (asn_put_octetstring(b, (u_char *)pdu->community,
518 strlen(pdu->community)) != ASN_ERR_OK)
519 return (SNMP_CODE_FAILED);
520
521 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
522 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
523 return (SNMP_CODE_FAILED);
524
525 if (pdu->type == SNMP_PDU_TRAP) {
526 if (pdu->version != SNMP_V1 ||
527 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
528 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
529 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
530 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
531 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
532 return (SNMP_CODE_FAILED);
533 } else {
534 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
535 pdu->type == SNMP_PDU_INFORM ||
536 pdu->type == SNMP_PDU_TRAP2 ||
537 pdu->type == SNMP_PDU_REPORT))
538 return (SNMP_CODE_FAILED);
539
540 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
541 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
542 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
543 return (SNMP_CODE_FAILED);
544 }
545
546 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
547 &pdu->vars_ptr) != ASN_ERR_OK)
548 return (SNMP_CODE_FAILED);
549
550 return (SNMP_CODE_OK);
551}
552
553enum snmp_code
554snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu)
555{
556 if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK ||
557 asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK ||
558 asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK)
559 return (SNMP_CODE_FAILED);
560 return (SNMP_CODE_OK);
561}
562
563/*
564 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
565 * Be sure not to cobber b, when something fails.
566 */
567enum asn_err
568snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
569{
570 u_char *ptr;
571 enum asn_err err;
572 struct asn_buf save = *b;
573
574 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
575 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
576 *b = save;
577 return (err);
578 }
579
580 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
581 *b = save;
582 return (err);
583 }
584
585 switch (binding->syntax) {
586
587 case SNMP_SYNTAX_NULL:
588 err = asn_put_null(b);
589 break;
590
591 case SNMP_SYNTAX_INTEGER:
592 err = asn_put_integer(b, binding->v.integer);
593 break;
594
595 case SNMP_SYNTAX_OCTETSTRING:
596 err = asn_put_octetstring(b, binding->v.octetstring.octets,
597 binding->v.octetstring.len);
598 break;
599
600 case SNMP_SYNTAX_OID:
601 err = asn_put_objid(b, &binding->v.oid);
602 break;
603
604 case SNMP_SYNTAX_IPADDRESS:
605 err = asn_put_ipaddress(b, binding->v.ipaddress);
606 break;
607
608 case SNMP_SYNTAX_TIMETICKS:
609 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
610 break;
611
612 case SNMP_SYNTAX_COUNTER:
613 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
614 break;
615
616 case SNMP_SYNTAX_GAUGE:
617 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
618 break;
619
620 case SNMP_SYNTAX_COUNTER64:
621 err = asn_put_counter64(b, binding->v.counter64);
622 break;
623
624 case SNMP_SYNTAX_NOSUCHOBJECT:
625 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
626 break;
627
628 case SNMP_SYNTAX_NOSUCHINSTANCE:
629 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
630 break;
631
632 case SNMP_SYNTAX_ENDOFMIBVIEW:
633 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
634 break;
635 }
636
637 if (err != ASN_ERR_OK) {
638 *b = save;
639 return (err);
640 }
641
642 err = asn_commit_header(b, ptr);
643 if (err != ASN_ERR_OK) {
644 *b = save;
645 return (err);
646 }
647
648 return (ASN_ERR_OK);
649}
650
651/*
652 * Encode an PDU.
653 */
654enum snmp_code
655snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
656{
657 u_int idx;
658 enum snmp_code err;
659
660 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
661 return (err);
662 for (idx = 0; idx < pdu->nbindings; idx++)
663 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
664 != ASN_ERR_OK)
665 return (SNMP_CODE_FAILED);
666
667 return (snmp_fix_encoding(resp_b, pdu));
668}
669
670static void
671dump_binding(const struct snmp_value *b)
672{
673 u_int i;
674 char buf[ASN_OIDSTRLEN];
675
676 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
677 switch (b->syntax) {
678
679 case SNMP_SYNTAX_NULL:
680 snmp_printf("NULL");
681 break;
682
683 case SNMP_SYNTAX_INTEGER:
684 snmp_printf("INTEGER %d", b->v.integer);
685 break;
686
687 case SNMP_SYNTAX_OCTETSTRING:
688 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
689 for (i = 0; i < b->v.octetstring.len; i++)
690 snmp_printf(" %02x", b->v.octetstring.octets[i]);
691 break;
692
693 case SNMP_SYNTAX_OID:
694 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
695 break;
696
697 case SNMP_SYNTAX_IPADDRESS:
698 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
699 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
700 break;
701
702 case SNMP_SYNTAX_COUNTER:
703 snmp_printf("COUNTER %u", b->v.uint32);
704 break;
705
706 case SNMP_SYNTAX_GAUGE:
707 snmp_printf("GAUGE %u", b->v.uint32);
708 break;
709
710 case SNMP_SYNTAX_TIMETICKS:
711 snmp_printf("TIMETICKS %u", b->v.uint32);
712 break;
713
714 case SNMP_SYNTAX_COUNTER64:
715 snmp_printf("COUNTER64 %lld", b->v.counter64);
716 break;
717
718 case SNMP_SYNTAX_NOSUCHOBJECT:
719 snmp_printf("NoSuchObject");
720 break;
721
722 case SNMP_SYNTAX_NOSUCHINSTANCE:
723 snmp_printf("NoSuchInstance");
724 break;
725
726 case SNMP_SYNTAX_ENDOFMIBVIEW:
727 snmp_printf("EndOfMibView");
728 break;
729
730 default:
731 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
732 break;
733 }
734}
735
736static __inline void
737dump_bindings(const struct snmp_pdu *pdu)
738{
739 u_int i;
740
741 for (i = 0; i < pdu->nbindings; i++) {
742 snmp_printf(" [%u]: ", i);
743 dump_binding(&pdu->bindings[i]);
744 snmp_printf("\n");
745 }
746}
747
748static __inline void
749dump_notrap(const struct snmp_pdu *pdu)
750{
751 snmp_printf(" request_id=%d", pdu->request_id);
752 snmp_printf(" error_status=%d", pdu->error_status);
753 snmp_printf(" error_index=%d\n", pdu->error_index);
754 dump_bindings(pdu);
755}
756
757void
758snmp_pdu_dump(const struct snmp_pdu *pdu)
759{
760 char buf[ASN_OIDSTRLEN];
761 const char *vers;
762 static const char *types[] = {
763 [SNMP_PDU_GET] = "GET",
764 [SNMP_PDU_GETNEXT] = "GETNEXT",
765 [SNMP_PDU_RESPONSE] = "RESPONSE",
766 [SNMP_PDU_SET] = "SET",
767 [SNMP_PDU_TRAP] = "TRAPv1",
768 [SNMP_PDU_GETBULK] = "GETBULK",
769 [SNMP_PDU_INFORM] = "INFORM",
770 [SNMP_PDU_TRAP2] = "TRAPv2",
771 [SNMP_PDU_REPORT] = "REPORT",
772 };
773
774 if (pdu->version == SNMP_V1)
775 vers = "SNMPv1";
776 else if (pdu->version == SNMP_V2c)
777 vers = "SNMPv2c";
778 else
779 vers = "v?";
780
781 switch (pdu->type) {
782 case SNMP_PDU_TRAP:
783 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
784 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
785 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
786 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
787 snmp_printf(" generic_trap=%d", pdu->generic_trap);
788 snmp_printf(" specific_trap=%d", pdu->specific_trap);
789 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
790 dump_bindings(pdu);
791 break;
792
793 case SNMP_PDU_GET:
794 case SNMP_PDU_GETNEXT:
795 case SNMP_PDU_RESPONSE:
796 case SNMP_PDU_SET:
797 case SNMP_PDU_GETBULK:
798 case SNMP_PDU_INFORM:
799 case SNMP_PDU_TRAP2:
800 case SNMP_PDU_REPORT:
801 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
802 dump_notrap(pdu);
803 break;
804
805 default:
806 snmp_printf("bad pdu type %u\n", pdu->type);
807 break;
808 }
809}
810
811void
812snmp_value_free(struct snmp_value *value)
813{
814 if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
815 free(value->v.octetstring.octets);
816 value->syntax = SNMP_SYNTAX_NULL;
817}
818
819int
820snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
821{
822 to->var = from->var;
823 to->syntax = from->syntax;
824
825 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
826 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
827 to->v.octetstring.octets = NULL;
828 else {
829 to->v.octetstring.octets = malloc(to->v.octetstring.len);
830 if (to->v.octetstring.octets == NULL)
831 return (-1);
832 (void)memcpy(to->v.octetstring.octets,
833 from->v.octetstring.octets, to->v.octetstring.len);
834 }
835 } else
836 to->v = from->v;
837 return (0);
838}
839
840void
841snmp_pdu_free(struct snmp_pdu *pdu)
842{
843 u_int i;
844
845 for (i = 0; i < pdu->nbindings; i++)
846 snmp_value_free(&pdu->bindings[i]);
847}
848
849/*
850 * Parse an ASCII SNMP value into the binary form
851 */
852int
853snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
854{
855 char *end;
856
857 switch (syntax) {
858
859 case SNMP_SYNTAX_NULL:
860 case SNMP_SYNTAX_NOSUCHOBJECT:
861 case SNMP_SYNTAX_NOSUCHINSTANCE:
862 case SNMP_SYNTAX_ENDOFMIBVIEW:
863 if (*str != '\0')
864 return (-1);
865 return (0);
866
867 case SNMP_SYNTAX_INTEGER:
868 v->integer = strtoll(str, &end, 0);
869 if (*end != '\0')
870 return (-1);
871 return (0);
872
873 case SNMP_SYNTAX_OCTETSTRING:
874 {
875 u_long len; /* actual length of string */
876 u_long alloc; /* allocate length of string */
877 u_char *octs; /* actual octets */
878 u_long oct; /* actual octet */
879 u_char *nocts; /* to avoid memory leak */
880 u_char c; /* actual character */
881
882# define STUFFC(C) \
883 if (alloc == len) { \
884 alloc += 100; \
885 if ((nocts = realloc(octs, alloc)) == NULL) { \
886 free(octs); \
887 return (-1); \
888 } \
889 octs = nocts; \
890 } \
891 octs[len++] = (C);
892
893 len = alloc = 0;
894 octs = NULL;
895
896 if (*str == '"') {
897 str++;
898 while((c = *str++) != '\0') {
899 if (c == '"') {
900 if (*str != '\0') {
901 free(octs);
902 return (-1);
903 }
904 break;
905 }
906 if (c == '\\') {
907 switch (c = *str++) {
908
909 case '\\':
910 break;
911 case 'a':
912 c = '\a';
913 break;
914 case 'b':
915 c = '\b';
916 break;
917 case 'f':
918 c = '\f';
919 break;
920 case 'n':
921 c = '\n';
922 break;
923 case 'r':
924 c = '\r';
925 break;
926 case 't':
927 c = '\t';
928 break;
929 case 'v':
930 c = '\v';
931 break;
932 case 'x':
933 c = 0;
934 if (!isxdigit(*str))
935 break;
936 if (isdigit(*str))
937 c = *str++ - '0';
938 else if (isupper(*str))
939 c = *str++ - 'A' + 10;
940 else
941 c = *str++ - 'a' + 10;
942 if (!isxdigit(*str))
943 break;
944 if (isdigit(*str))
945 c += *str++ - '0';
946 else if (isupper(*str))
947 c += *str++ - 'A' + 10;
948 else
949 c += *str++ - 'a' + 10;
950 break;
951 case '0': case '1': case '2':
952 case '3': case '4': case '5':
953 case '6': case '7':
954 c = *str++ - '0';
955 if (*str < '0' || *str > '7')
956 break;
957 c = *str++ - '0';
958 if (*str < '0' || *str > '7')
959 break;
960 c = *str++ - '0';
961 break;
962 default:
963 break;
964 }
965 }
966 STUFFC(c);
967 }
968 } else {
969 while (*str != '\0') {
970 oct = strtoul(str, &end, 16);
971 str = end;
972 if (oct > 0xff) {
973 free(octs);
974 return (-1);
975 }
976 STUFFC(oct);
977 if (*str == ':')
978 str++;
979 else if(*str != '\0') {
980 free(octs);
981 return (-1);
982 }
983 }
984 }
985 v->octetstring.octets = octs;
986 v->octetstring.len = len;
987 return (0);
988# undef STUFFC
989 }
990
991 case SNMP_SYNTAX_OID:
992 {
993 u_long subid;
994
995 v->oid.len = 0;
996
997 for (;;) {
998 if (v->oid.len == ASN_MAXOIDLEN)
999 return (-1);
1000 subid = strtoul(str, &end, 10);
1001 str = end;
1002 if (subid > ASN_MAXID)
1003 return (-1);
1004 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1005 if (*str == '\0')
1006 break;
1007 if (*str != '.')
1008 return (-1);
1009 str++;
1010 }
1011 return (0);
1012 }
1013
1014 case SNMP_SYNTAX_IPADDRESS:
1015 {
1016 struct hostent *he;
1017 u_long ip[4];
1018 int n;
1019
1020 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1021 &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1022 ip[0] <= 0xff && ip[1] <= 0xff &&
1023 ip[2] <= 0xff && ip[3] <= 0xff) {
1024 v->ipaddress[0] = (u_char)ip[0];
1025 v->ipaddress[1] = (u_char)ip[1];
1026 v->ipaddress[2] = (u_char)ip[2];
1027 v->ipaddress[3] = (u_char)ip[3];
1028 return (0);
1029 }
1030
1031 if ((he = gethostbyname(str)) == NULL)
1032 return (-1);
1033 if (he->h_addrtype != AF_INET)
1034 return (-1);
1035
1036 v->ipaddress[0] = he->h_addr[0];
1037 v->ipaddress[1] = he->h_addr[1];
1038 v->ipaddress[2] = he->h_addr[2];
1039 v->ipaddress[3] = he->h_addr[3];
1040 return (0);
1041 }
1042
1043 case SNMP_SYNTAX_COUNTER:
1044 case SNMP_SYNTAX_GAUGE:
1045 case SNMP_SYNTAX_TIMETICKS:
1046 {
1047 uint64_t sub;
1048
1049 sub = strtoull(str, &end, 0);
1050 if (*end != '\0' || sub > 0xffffffff)
1051 return (-1);
1052 v->uint32 = (uint32_t)sub;
1053 return (0);
1054 }
1055
1056 case SNMP_SYNTAX_COUNTER64:
1057 v->counter64 = strtoull(str, &end, 0);
1058 if (*end != '\0')
1059 return (-1);
1060 return (0);
1061 }
1062 abort();
1063}
1064
1065static void
1066snmp_error_func(const char *fmt, ...)
1067{
1068 va_list ap;
1069
1070 va_start(ap, fmt);
1071 fprintf(stderr, "SNMP: ");
1072 vfprintf(stderr, fmt, ap);
1073 fprintf(stderr, "\n");
1074 va_end(ap);
1075}
1076
1077static void
1078snmp_printf_func(const char *fmt, ...)
1079{
1080 va_list ap;
1081
1082 va_start(ap, fmt);
1083 vfprintf(stderr, fmt, ap);
1084 va_end(ap);
1085}