Deleted Added
full compact
snmp.c (216482) snmp.c (216594)
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 * Copyright (c) 2010 The FreeBSD Foundation
9 * All rights reserved.
10 *
11 * Portions of this software were developed by Shteryana Sotirova Shopova
12 * under sponsorship from the FreeBSD Foundation.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
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.
22 *
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
33 * SUCH DAMAGE.
34 *
35 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
36 *
37 * SNMP
38 */
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <stddef.h>
44#include <stdarg.h>
45#ifdef HAVE_STDINT_H
46#include <stdint.h>
47#elif defined(HAVE_INTTYPES_H)
48#include <inttypes.h>
49#endif
50#include <string.h>
51#include <ctype.h>
52#include <netdb.h>
53#include <errno.h>
54
55#include "asn1.h"
56#include "snmp.h"
57#include "snmppriv.h"
58
59static void snmp_error_func(const char *, ...);
60static void snmp_printf_func(const char *, ...);
61
62void (*snmp_error)(const char *, ...) = snmp_error_func;
63void (*snmp_printf)(const char *, ...) = snmp_printf_func;
64
65/*
66 * Get the next variable binding from the list.
67 * ASN errors on the sequence or the OID are always fatal.
68 */
69static enum asn_err
70get_var_binding(struct asn_buf *b, struct snmp_value *binding)
71{
72 u_char type;
73 asn_len_t len, trailer;
74 enum asn_err err;
75
76 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
77 snmp_error("cannot parse varbind header");
78 return (ASN_ERR_FAILED);
79 }
80
81 /* temporary truncate the length so that the parser does not
82 * eat up bytes behind the sequence in the case the encoding is
83 * wrong of inner elements. */
84 trailer = b->asn_len - len;
85 b->asn_len = len;
86
87 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
88 snmp_error("cannot parse binding objid");
89 return (ASN_ERR_FAILED);
90 }
91 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
92 snmp_error("cannot parse binding value header");
93 return (ASN_ERR_FAILED);
94 }
95
96 switch (type) {
97
98 case ASN_TYPE_NULL:
99 binding->syntax = SNMP_SYNTAX_NULL;
100 err = asn_get_null_raw(b, len);
101 break;
102
103 case ASN_TYPE_INTEGER:
104 binding->syntax = SNMP_SYNTAX_INTEGER;
105 err = asn_get_integer_raw(b, len, &binding->v.integer);
106 break;
107
108 case ASN_TYPE_OCTETSTRING:
109 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
110 binding->v.octetstring.octets = malloc(len);
111 if (binding->v.octetstring.octets == NULL) {
112 snmp_error("%s", strerror(errno));
113 return (ASN_ERR_FAILED);
114 }
115 binding->v.octetstring.len = len;
116 err = asn_get_octetstring_raw(b, len,
117 binding->v.octetstring.octets,
118 &binding->v.octetstring.len);
119 if (ASN_ERR_STOPPED(err)) {
120 free(binding->v.octetstring.octets);
121 binding->v.octetstring.octets = NULL;
122 }
123 break;
124
125 case ASN_TYPE_OBJID:
126 binding->syntax = SNMP_SYNTAX_OID;
127 err = asn_get_objid_raw(b, len, &binding->v.oid);
128 break;
129
130 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
131 binding->syntax = SNMP_SYNTAX_IPADDRESS;
132 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
133 break;
134
135 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
136 binding->syntax = SNMP_SYNTAX_TIMETICKS;
137 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138 break;
139
140 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
141 binding->syntax = SNMP_SYNTAX_COUNTER;
142 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
143 break;
144
145 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
146 binding->syntax = SNMP_SYNTAX_GAUGE;
147 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
148 break;
149
150 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
151 binding->syntax = SNMP_SYNTAX_COUNTER64;
152 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
153 break;
154
155 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
156 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
157 err = asn_get_null_raw(b, len);
158 break;
159
160 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
161 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
162 err = asn_get_null_raw(b, len);
163 break;
164
165 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
166 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
167 err = asn_get_null_raw(b, len);
168 break;
169
170 default:
171 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
172 err = ASN_ERR_TAG;
173 snmp_error("bad binding value type 0x%x", type);
174 break;
175 }
176
177 if (ASN_ERR_STOPPED(err)) {
178 snmp_error("cannot parse binding value");
179 return (err);
180 }
181
182 if (b->asn_len != 0)
183 snmp_error("ignoring junk at end of binding");
184
185 b->asn_len = trailer;
186
187 return (err);
188}
189
190/*
191 * Parse the different PDUs contents. Any ASN error in the outer components
192 * are fatal. Only errors in variable values may be tolerated. If all
193 * components can be parsed it returns either ASN_ERR_OK or the first
194 * error that was found.
195 */
196enum asn_err
197snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
198{
199 if (pdu->type == SNMP_PDU_TRAP) {
200 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
201 snmp_error("cannot parse trap enterprise");
202 return (ASN_ERR_FAILED);
203 }
204 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
205 snmp_error("cannot parse trap agent address");
206 return (ASN_ERR_FAILED);
207 }
208 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
209 snmp_error("cannot parse 'generic-trap'");
210 return (ASN_ERR_FAILED);
211 }
212 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
213 snmp_error("cannot parse 'specific-trap'");
214 return (ASN_ERR_FAILED);
215 }
216 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
217 snmp_error("cannot parse trap 'time-stamp'");
218 return (ASN_ERR_FAILED);
219 }
220 } else {
221 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
222 snmp_error("cannot parse 'request-id'");
223 return (ASN_ERR_FAILED);
224 }
225 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
226 snmp_error("cannot parse 'error_status'");
227 return (ASN_ERR_FAILED);
228 }
229 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
230 snmp_error("cannot parse 'error_index'");
231 return (ASN_ERR_FAILED);
232 }
233 }
234
235 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
236 snmp_error("cannot get varlist header");
237 return (ASN_ERR_FAILED);
238 }
239
240 return (ASN_ERR_OK);
241}
242
243static enum asn_err
244parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
245{
246 asn_len_t len, trailer;
247 struct snmp_value *v;
248 enum asn_err err, err1;
249
250 err = snmp_parse_pdus_hdr(b, pdu, &len);
251 if (ASN_ERR_STOPPED(err))
252 return (err);
253
254 trailer = b->asn_len - len;
255
256 v = pdu->bindings;
257 err = ASN_ERR_OK;
258 while (b->asn_len != 0) {
259 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
260 snmp_error("too many bindings (> %u) in PDU",
261 SNMP_MAX_BINDINGS);
262 return (ASN_ERR_FAILED);
263 }
264 err1 = get_var_binding(b, v);
265 if (ASN_ERR_STOPPED(err1))
266 return (ASN_ERR_FAILED);
267 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
268 err = err1;
269 *ip = pdu->nbindings + 1;
270 }
271 pdu->nbindings++;
272 v++;
273 }
274
275 b->asn_len = trailer;
276
277 return (err);
278}
279
280
281static enum asn_err
282parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
283{
284 asn_len_t octs_len;
285 u_char buf[256]; /* XXX: calc max possible size here */
286 struct asn_buf tb;
287
288 memset(buf, 0, 256);
289 tb.asn_ptr = buf;
290 tb.asn_len = 256;
291
292 if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
293 snmp_error("cannot parse usm header");
294 return (ASN_ERR_FAILED);
295 }
296
297 if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
298 snmp_error("cannot decode usm header");
299 return (ASN_ERR_FAILED);
300 }
301
302 octs_len = SNMP_ENGINE_ID_SIZ;
303 if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
304 &octs_len) != ASN_ERR_OK) {
305 snmp_error("cannot decode msg engine id");
306 return (ASN_ERR_FAILED);
307 }
308 pdu->engine.engine_len = octs_len;
309
310 if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
311 snmp_error("cannot decode msg engine boots");
312 return (ASN_ERR_FAILED);
313 }
314
315 if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
316 snmp_error("cannot decode msg engine time");
317 return (ASN_ERR_FAILED);
318 }
319
320 octs_len = SNMP_ADM_STR32_SIZ - 1;
321 if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
322 != ASN_ERR_OK) {
323 snmp_error("cannot decode msg user name");
324 return (ASN_ERR_FAILED);
325 }
326 pdu->user.sec_name[octs_len] = '\0';
327
328 octs_len = sizeof(pdu->msg_digest);
329 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
330 ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
331 octs_len != sizeof(pdu->msg_digest))) {
332 snmp_error("cannot decode msg authentication param");
333 return (ASN_ERR_FAILED);
334 }
335
336 octs_len = sizeof(pdu->msg_salt);
337 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
338 ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
339 octs_len != sizeof(pdu->msg_salt))) {
340 snmp_error("cannot decode msg authentication param");
341 return (ASN_ERR_FAILED);
342 }
343
344 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
345 pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
346 pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
347 }
348
349 return (ASN_ERR_OK);
350}
351
352static enum snmp_code
353pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
354{
355 u_char buf[256], *sptr;
356 struct asn_buf tb;
357 size_t auth_off, moved = 0;
358
359 auth_off = 0;
360 memset(buf, 0, 256);
361 tb.asn_ptr = buf;
362 tb.asn_len = 256;
363
364 if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
365 &sptr) != ASN_ERR_OK)
366 return (SNMP_CODE_FAILED);
367
368 if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
369 pdu->engine.engine_len) != ASN_ERR_OK)
370 return (SNMP_CODE_FAILED);
371
372 if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
373 return (SNMP_CODE_FAILED);
374
375 if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
376 return (SNMP_CODE_FAILED);
377
378 if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
379 strlen(pdu->user.sec_name)) != ASN_ERR_OK)
380 return (SNMP_CODE_FAILED);
381
382 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
383 auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
384 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
385 sizeof(pdu->msg_digest)) != ASN_ERR_OK)
386 return (SNMP_CODE_FAILED);
387 } else {
388 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
389 != ASN_ERR_OK)
390 return (SNMP_CODE_FAILED);
391 }
392
393 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
394 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
395 sizeof(pdu->msg_salt)) != ASN_ERR_OK)
396 return (SNMP_CODE_FAILED);
397 } else {
398 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
399 != ASN_ERR_OK)
400 return (SNMP_CODE_FAILED);
401 }
402
403 if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
404 return (SNMP_CODE_FAILED);
405
406 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
407 pdu->digest_ptr = b->asn_ptr + auth_off - moved;
408
409 if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
410 return (SNMP_CODE_FAILED);
411 pdu->digest_ptr += ASN_MAXLENLEN;
412
413 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
414 ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
415 return (SNMP_CODE_FAILED);
416
417 return (SNMP_CODE_OK);
418}
419
420/*
421 * Decode the PDU except for the variable bindings itself.
422 * If decoding fails because of a bad binding, but the rest can be
423 * decoded, ip points to the index of the failed variable (errors
424 * OORANGE, BADLEN or BADVERS).
425 */
426enum snmp_code
427snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
428{
429 enum snmp_code code;
430
431 if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
432 return (code);
433
434 if (pdu->version == SNMP_V3) {
435 if (pdu->security_model != SNMP_SECMODEL_USM)
436 return (SNMP_CODE_FAILED);
437 if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
438 return (code);
439 }
440
441 code = snmp_pdu_decode_scoped(b, pdu, ip);
442
443 switch (code) {
444 case SNMP_CODE_FAILED:
445 snmp_pdu_free(pdu);
446 break;
447
448 case SNMP_CODE_BADENC:
449 if (pdu->version == SNMP_Verr)
450 return (SNMP_CODE_BADVERS);
451
452 default:
453 break;
454 }
455
456 return (code);
457}
458
459enum snmp_code
460snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
461{
462 int32_t version;
463 u_int octs_len;
464 asn_len_t len;
465
466 pdu->outer_ptr = b->asn_ptr;
467 pdu->outer_len = b->asn_len;
468
469 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
470 snmp_error("cannot decode pdu header");
471 return (SNMP_CODE_FAILED);
472 }
473 if (b->asn_len < len) {
474 snmp_error("outer sequence value too short");
475 return (SNMP_CODE_FAILED);
476 }
477 if (b->asn_len != len) {
478 snmp_error("ignoring trailing junk in message");
479 b->asn_len = len;
480 }
481
482 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
483 snmp_error("cannot decode version");
484 return (SNMP_CODE_FAILED);
485 }
486
487 if (version == 0)
488 pdu->version = SNMP_V1;
489 else if (version == 1)
490 pdu->version = SNMP_V2c;
491 else if (version == 3)
492 pdu->version = SNMP_V3;
493 else {
494 pdu->version = SNMP_Verr;
495 snmp_error("unsupported SNMP version");
496 return (SNMP_CODE_BADENC);
497 }
498
499 if (pdu->version == SNMP_V3) {
500 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
501 snmp_error("cannot decode pdu global data header");
502 return (SNMP_CODE_FAILED);
503 }
504
505 if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
506 snmp_error("cannot decode msg indetifier");
507 return (SNMP_CODE_FAILED);
508 }
509
510 if (asn_get_integer(b, &pdu->engine.max_msg_size)
511 != ASN_ERR_OK) {
512 snmp_error("cannot decode msg size");
513 return (SNMP_CODE_FAILED);
514 }
515
516 octs_len = 1;
517 if (asn_get_octetstring(b, (u_char *)&pdu->flags,
518 &octs_len) != ASN_ERR_OK) {
519 snmp_error("cannot decode msg flags");
520 return (SNMP_CODE_FAILED);
521 }
522
523 if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
524 snmp_error("cannot decode msg size");
525 return (SNMP_CODE_FAILED);
526 }
527
528 if (pdu->security_model != SNMP_SECMODEL_USM)
529 return (SNMP_CODE_FAILED);
530
531 if (parse_secparams(b, pdu) != ASN_ERR_OK)
532 return (SNMP_CODE_FAILED);
533 } else {
534 octs_len = SNMP_COMMUNITY_MAXLEN;
535 if (asn_get_octetstring(b, (u_char *)pdu->community,
536 &octs_len) != ASN_ERR_OK) {
537 snmp_error("cannot decode community");
538 return (SNMP_CODE_FAILED);
539 }
540 pdu->community[octs_len] = '\0';
541 }
542
543 return (SNMP_CODE_OK);
544}
545
546enum snmp_code
547snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
548{
549 u_char type;
550 asn_len_t len, trailer;
551 enum asn_err err;
552
553 if (pdu->version == SNMP_V3) {
554 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
555 snmp_error("cannot decode scoped pdu header");
556 return (SNMP_CODE_FAILED);
557 }
558
559 len = SNMP_ENGINE_ID_SIZ;
560 if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
561 &len) != ASN_ERR_OK) {
562 snmp_error("cannot decode msg context engine");
563 return (SNMP_CODE_FAILED);
564 }
565 pdu->context_engine_len = len;
566
567 len = SNMP_CONTEXT_NAME_SIZ;
568 if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
569 &len) != ASN_ERR_OK) {
570 snmp_error("cannot decode msg context name");
571 return (SNMP_CODE_FAILED);
572 }
573 pdu->context_name[len] = '\0';
574 }
575
576 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
577 snmp_error("cannot get pdu header");
578 return (SNMP_CODE_FAILED);
579 }
580 if ((type & ~ASN_TYPE_MASK) !=
581 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
582 snmp_error("bad pdu header tag");
583 return (SNMP_CODE_FAILED);
584 }
585 pdu->type = type & ASN_TYPE_MASK;
586
587 switch (pdu->type) {
588
589 case SNMP_PDU_GET:
590 case SNMP_PDU_GETNEXT:
591 case SNMP_PDU_RESPONSE:
592 case SNMP_PDU_SET:
593 break;
594
595 case SNMP_PDU_TRAP:
596 if (pdu->version != SNMP_V1) {
597 snmp_error("bad pdu type %u", pdu->type);
598 return (SNMP_CODE_FAILED);
599 }
600 break;
601
602 case SNMP_PDU_GETBULK:
603 case SNMP_PDU_INFORM:
604 case SNMP_PDU_TRAP2:
605 case SNMP_PDU_REPORT:
606 if (pdu->version == SNMP_V1) {
607 snmp_error("bad pdu type %u", pdu->type);
608 return (SNMP_CODE_FAILED);
609 }
610 break;
611
612 default:
613 snmp_error("bad pdu type %u", pdu->type);
614 return (SNMP_CODE_FAILED);
615 }
616
617 trailer = b->asn_len - len;
618 b->asn_len = len;
619
620 err = parse_pdus(b, pdu, ip);
621 if (ASN_ERR_STOPPED(err))
622 return (SNMP_CODE_FAILED);
623
624 if (b->asn_len != 0)
625 snmp_error("ignoring trailing junk after pdu");
626
627 b->asn_len = trailer;
628
629 return (SNMP_CODE_OK);
630}
631
632enum snmp_code
633snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
634{
635 u_char type;
636 enum snmp_code code;
637 uint8_t digest[SNMP_USM_AUTH_SIZE];
638
639 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
640 (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
641 return (SNMP_CODE_BADSECLEVEL);
642
643 if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
644 SNMP_CODE_OK)
645 return (SNMP_CODE_FAILED);
646
647 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
648 memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
649 return (SNMP_CODE_BADDIGEST);
650
651 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
652 &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
653 snmp_error("cannot decode encrypted pdu");
654 return (SNMP_CODE_FAILED);
655 }
656 pdu->scoped_ptr = b->asn_ptr;
657
658 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
659 (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
660 return (SNMP_CODE_BADSECLEVEL);
661
662 if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
663 return (SNMP_CODE_FAILED);
664
665 return (code);
666}
667
668/*
669 * Check whether what we have is the complete PDU by snooping at the
670 * enclosing structure header. This returns:
671 * -1 if there are ASN.1 errors
672 * 0 if we need more data
673 * > 0 the length of this PDU
674 */
675int
676snmp_pdu_snoop(const struct asn_buf *b0)
677{
678 u_int length;
679 asn_len_t len;
680 struct asn_buf b = *b0;
681
682 /* <0x10|0x20> <len> <data...> */
683
684 if (b.asn_len == 0)
685 return (0);
686 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
687 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
688 return (-1);
689 }
690 b.asn_len--;
691 b.asn_cptr++;
692
693 if (b.asn_len == 0)
694 return (0);
695
696 if (*b.asn_cptr & 0x80) {
697 /* long length */
698 length = *b.asn_cptr++ & 0x7f;
699 b.asn_len--;
700 if (length == 0) {
701 asn_error(&b, "indefinite length not supported");
702 return (-1);
703 }
704 if (length > ASN_MAXLENLEN) {
705 asn_error(&b, "long length too long (%u)", length);
706 return (-1);
707 }
708 if (length > b.asn_len)
709 return (0);
710 len = 0;
711 while (length--) {
712 len = (len << 8) | *b.asn_cptr++;
713 b.asn_len--;
714 }
715 } else {
716 len = *b.asn_cptr++;
717 b.asn_len--;
718 }
719
720 if (len > b.asn_len)
721 return (0);
722
723 return (len + b.asn_cptr - b0->asn_cptr);
724}
725
726/*
727 * Encode the SNMP PDU without the variable bindings field.
728 * We do this the rather uneffective way by
729 * moving things around and assuming that the length field will never
730 * use more than 2 bytes.
731 * We need a number of pointers to apply the fixes afterwards.
732 */
733enum snmp_code
734snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
735{
736 enum asn_err err;
737 u_char *v3_hdr_ptr;
738
739 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
740 &pdu->outer_ptr) != ASN_ERR_OK)
741 return (SNMP_CODE_FAILED);
742
743 if (pdu->version == SNMP_V1)
744 err = asn_put_integer(b, 0);
745 else if (pdu->version == SNMP_V2c)
746 err = asn_put_integer(b, 1);
747 else if (pdu->version == SNMP_V3)
748 err = asn_put_integer(b, 3);
749 else
750 return (SNMP_CODE_BADVERS);
751 if (err != ASN_ERR_OK)
752 return (SNMP_CODE_FAILED);
753
754 if (pdu->version == SNMP_V3) {
755 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
756 ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
757 return (SNMP_CODE_FAILED);
758
759 if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
760 return (SNMP_CODE_FAILED);
761
762 if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
763 return (SNMP_CODE_FAILED);
764
765 if (pdu->type != SNMP_PDU_RESPONSE &&
766 pdu->type != SNMP_PDU_TRAP &&
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 * Copyright (c) 2010 The FreeBSD Foundation
9 * All rights reserved.
10 *
11 * Portions of this software were developed by Shteryana Sotirova Shopova
12 * under sponsorship from the FreeBSD Foundation.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
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.
22 *
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
33 * SUCH DAMAGE.
34 *
35 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
36 *
37 * SNMP
38 */
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <stddef.h>
44#include <stdarg.h>
45#ifdef HAVE_STDINT_H
46#include <stdint.h>
47#elif defined(HAVE_INTTYPES_H)
48#include <inttypes.h>
49#endif
50#include <string.h>
51#include <ctype.h>
52#include <netdb.h>
53#include <errno.h>
54
55#include "asn1.h"
56#include "snmp.h"
57#include "snmppriv.h"
58
59static void snmp_error_func(const char *, ...);
60static void snmp_printf_func(const char *, ...);
61
62void (*snmp_error)(const char *, ...) = snmp_error_func;
63void (*snmp_printf)(const char *, ...) = snmp_printf_func;
64
65/*
66 * Get the next variable binding from the list.
67 * ASN errors on the sequence or the OID are always fatal.
68 */
69static enum asn_err
70get_var_binding(struct asn_buf *b, struct snmp_value *binding)
71{
72 u_char type;
73 asn_len_t len, trailer;
74 enum asn_err err;
75
76 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
77 snmp_error("cannot parse varbind header");
78 return (ASN_ERR_FAILED);
79 }
80
81 /* temporary truncate the length so that the parser does not
82 * eat up bytes behind the sequence in the case the encoding is
83 * wrong of inner elements. */
84 trailer = b->asn_len - len;
85 b->asn_len = len;
86
87 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
88 snmp_error("cannot parse binding objid");
89 return (ASN_ERR_FAILED);
90 }
91 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
92 snmp_error("cannot parse binding value header");
93 return (ASN_ERR_FAILED);
94 }
95
96 switch (type) {
97
98 case ASN_TYPE_NULL:
99 binding->syntax = SNMP_SYNTAX_NULL;
100 err = asn_get_null_raw(b, len);
101 break;
102
103 case ASN_TYPE_INTEGER:
104 binding->syntax = SNMP_SYNTAX_INTEGER;
105 err = asn_get_integer_raw(b, len, &binding->v.integer);
106 break;
107
108 case ASN_TYPE_OCTETSTRING:
109 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
110 binding->v.octetstring.octets = malloc(len);
111 if (binding->v.octetstring.octets == NULL) {
112 snmp_error("%s", strerror(errno));
113 return (ASN_ERR_FAILED);
114 }
115 binding->v.octetstring.len = len;
116 err = asn_get_octetstring_raw(b, len,
117 binding->v.octetstring.octets,
118 &binding->v.octetstring.len);
119 if (ASN_ERR_STOPPED(err)) {
120 free(binding->v.octetstring.octets);
121 binding->v.octetstring.octets = NULL;
122 }
123 break;
124
125 case ASN_TYPE_OBJID:
126 binding->syntax = SNMP_SYNTAX_OID;
127 err = asn_get_objid_raw(b, len, &binding->v.oid);
128 break;
129
130 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
131 binding->syntax = SNMP_SYNTAX_IPADDRESS;
132 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
133 break;
134
135 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
136 binding->syntax = SNMP_SYNTAX_TIMETICKS;
137 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138 break;
139
140 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
141 binding->syntax = SNMP_SYNTAX_COUNTER;
142 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
143 break;
144
145 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
146 binding->syntax = SNMP_SYNTAX_GAUGE;
147 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
148 break;
149
150 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
151 binding->syntax = SNMP_SYNTAX_COUNTER64;
152 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
153 break;
154
155 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
156 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
157 err = asn_get_null_raw(b, len);
158 break;
159
160 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
161 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
162 err = asn_get_null_raw(b, len);
163 break;
164
165 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
166 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
167 err = asn_get_null_raw(b, len);
168 break;
169
170 default:
171 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
172 err = ASN_ERR_TAG;
173 snmp_error("bad binding value type 0x%x", type);
174 break;
175 }
176
177 if (ASN_ERR_STOPPED(err)) {
178 snmp_error("cannot parse binding value");
179 return (err);
180 }
181
182 if (b->asn_len != 0)
183 snmp_error("ignoring junk at end of binding");
184
185 b->asn_len = trailer;
186
187 return (err);
188}
189
190/*
191 * Parse the different PDUs contents. Any ASN error in the outer components
192 * are fatal. Only errors in variable values may be tolerated. If all
193 * components can be parsed it returns either ASN_ERR_OK or the first
194 * error that was found.
195 */
196enum asn_err
197snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
198{
199 if (pdu->type == SNMP_PDU_TRAP) {
200 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
201 snmp_error("cannot parse trap enterprise");
202 return (ASN_ERR_FAILED);
203 }
204 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
205 snmp_error("cannot parse trap agent address");
206 return (ASN_ERR_FAILED);
207 }
208 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
209 snmp_error("cannot parse 'generic-trap'");
210 return (ASN_ERR_FAILED);
211 }
212 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
213 snmp_error("cannot parse 'specific-trap'");
214 return (ASN_ERR_FAILED);
215 }
216 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
217 snmp_error("cannot parse trap 'time-stamp'");
218 return (ASN_ERR_FAILED);
219 }
220 } else {
221 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
222 snmp_error("cannot parse 'request-id'");
223 return (ASN_ERR_FAILED);
224 }
225 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
226 snmp_error("cannot parse 'error_status'");
227 return (ASN_ERR_FAILED);
228 }
229 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
230 snmp_error("cannot parse 'error_index'");
231 return (ASN_ERR_FAILED);
232 }
233 }
234
235 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
236 snmp_error("cannot get varlist header");
237 return (ASN_ERR_FAILED);
238 }
239
240 return (ASN_ERR_OK);
241}
242
243static enum asn_err
244parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
245{
246 asn_len_t len, trailer;
247 struct snmp_value *v;
248 enum asn_err err, err1;
249
250 err = snmp_parse_pdus_hdr(b, pdu, &len);
251 if (ASN_ERR_STOPPED(err))
252 return (err);
253
254 trailer = b->asn_len - len;
255
256 v = pdu->bindings;
257 err = ASN_ERR_OK;
258 while (b->asn_len != 0) {
259 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
260 snmp_error("too many bindings (> %u) in PDU",
261 SNMP_MAX_BINDINGS);
262 return (ASN_ERR_FAILED);
263 }
264 err1 = get_var_binding(b, v);
265 if (ASN_ERR_STOPPED(err1))
266 return (ASN_ERR_FAILED);
267 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
268 err = err1;
269 *ip = pdu->nbindings + 1;
270 }
271 pdu->nbindings++;
272 v++;
273 }
274
275 b->asn_len = trailer;
276
277 return (err);
278}
279
280
281static enum asn_err
282parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
283{
284 asn_len_t octs_len;
285 u_char buf[256]; /* XXX: calc max possible size here */
286 struct asn_buf tb;
287
288 memset(buf, 0, 256);
289 tb.asn_ptr = buf;
290 tb.asn_len = 256;
291
292 if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
293 snmp_error("cannot parse usm header");
294 return (ASN_ERR_FAILED);
295 }
296
297 if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
298 snmp_error("cannot decode usm header");
299 return (ASN_ERR_FAILED);
300 }
301
302 octs_len = SNMP_ENGINE_ID_SIZ;
303 if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
304 &octs_len) != ASN_ERR_OK) {
305 snmp_error("cannot decode msg engine id");
306 return (ASN_ERR_FAILED);
307 }
308 pdu->engine.engine_len = octs_len;
309
310 if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
311 snmp_error("cannot decode msg engine boots");
312 return (ASN_ERR_FAILED);
313 }
314
315 if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
316 snmp_error("cannot decode msg engine time");
317 return (ASN_ERR_FAILED);
318 }
319
320 octs_len = SNMP_ADM_STR32_SIZ - 1;
321 if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
322 != ASN_ERR_OK) {
323 snmp_error("cannot decode msg user name");
324 return (ASN_ERR_FAILED);
325 }
326 pdu->user.sec_name[octs_len] = '\0';
327
328 octs_len = sizeof(pdu->msg_digest);
329 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
330 ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
331 octs_len != sizeof(pdu->msg_digest))) {
332 snmp_error("cannot decode msg authentication param");
333 return (ASN_ERR_FAILED);
334 }
335
336 octs_len = sizeof(pdu->msg_salt);
337 if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
338 ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
339 octs_len != sizeof(pdu->msg_salt))) {
340 snmp_error("cannot decode msg authentication param");
341 return (ASN_ERR_FAILED);
342 }
343
344 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
345 pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
346 pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
347 }
348
349 return (ASN_ERR_OK);
350}
351
352static enum snmp_code
353pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
354{
355 u_char buf[256], *sptr;
356 struct asn_buf tb;
357 size_t auth_off, moved = 0;
358
359 auth_off = 0;
360 memset(buf, 0, 256);
361 tb.asn_ptr = buf;
362 tb.asn_len = 256;
363
364 if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
365 &sptr) != ASN_ERR_OK)
366 return (SNMP_CODE_FAILED);
367
368 if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
369 pdu->engine.engine_len) != ASN_ERR_OK)
370 return (SNMP_CODE_FAILED);
371
372 if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
373 return (SNMP_CODE_FAILED);
374
375 if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
376 return (SNMP_CODE_FAILED);
377
378 if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
379 strlen(pdu->user.sec_name)) != ASN_ERR_OK)
380 return (SNMP_CODE_FAILED);
381
382 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
383 auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
384 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
385 sizeof(pdu->msg_digest)) != ASN_ERR_OK)
386 return (SNMP_CODE_FAILED);
387 } else {
388 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
389 != ASN_ERR_OK)
390 return (SNMP_CODE_FAILED);
391 }
392
393 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
394 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
395 sizeof(pdu->msg_salt)) != ASN_ERR_OK)
396 return (SNMP_CODE_FAILED);
397 } else {
398 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
399 != ASN_ERR_OK)
400 return (SNMP_CODE_FAILED);
401 }
402
403 if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
404 return (SNMP_CODE_FAILED);
405
406 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
407 pdu->digest_ptr = b->asn_ptr + auth_off - moved;
408
409 if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
410 return (SNMP_CODE_FAILED);
411 pdu->digest_ptr += ASN_MAXLENLEN;
412
413 if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
414 ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
415 return (SNMP_CODE_FAILED);
416
417 return (SNMP_CODE_OK);
418}
419
420/*
421 * Decode the PDU except for the variable bindings itself.
422 * If decoding fails because of a bad binding, but the rest can be
423 * decoded, ip points to the index of the failed variable (errors
424 * OORANGE, BADLEN or BADVERS).
425 */
426enum snmp_code
427snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
428{
429 enum snmp_code code;
430
431 if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
432 return (code);
433
434 if (pdu->version == SNMP_V3) {
435 if (pdu->security_model != SNMP_SECMODEL_USM)
436 return (SNMP_CODE_FAILED);
437 if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
438 return (code);
439 }
440
441 code = snmp_pdu_decode_scoped(b, pdu, ip);
442
443 switch (code) {
444 case SNMP_CODE_FAILED:
445 snmp_pdu_free(pdu);
446 break;
447
448 case SNMP_CODE_BADENC:
449 if (pdu->version == SNMP_Verr)
450 return (SNMP_CODE_BADVERS);
451
452 default:
453 break;
454 }
455
456 return (code);
457}
458
459enum snmp_code
460snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
461{
462 int32_t version;
463 u_int octs_len;
464 asn_len_t len;
465
466 pdu->outer_ptr = b->asn_ptr;
467 pdu->outer_len = b->asn_len;
468
469 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
470 snmp_error("cannot decode pdu header");
471 return (SNMP_CODE_FAILED);
472 }
473 if (b->asn_len < len) {
474 snmp_error("outer sequence value too short");
475 return (SNMP_CODE_FAILED);
476 }
477 if (b->asn_len != len) {
478 snmp_error("ignoring trailing junk in message");
479 b->asn_len = len;
480 }
481
482 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
483 snmp_error("cannot decode version");
484 return (SNMP_CODE_FAILED);
485 }
486
487 if (version == 0)
488 pdu->version = SNMP_V1;
489 else if (version == 1)
490 pdu->version = SNMP_V2c;
491 else if (version == 3)
492 pdu->version = SNMP_V3;
493 else {
494 pdu->version = SNMP_Verr;
495 snmp_error("unsupported SNMP version");
496 return (SNMP_CODE_BADENC);
497 }
498
499 if (pdu->version == SNMP_V3) {
500 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
501 snmp_error("cannot decode pdu global data header");
502 return (SNMP_CODE_FAILED);
503 }
504
505 if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
506 snmp_error("cannot decode msg indetifier");
507 return (SNMP_CODE_FAILED);
508 }
509
510 if (asn_get_integer(b, &pdu->engine.max_msg_size)
511 != ASN_ERR_OK) {
512 snmp_error("cannot decode msg size");
513 return (SNMP_CODE_FAILED);
514 }
515
516 octs_len = 1;
517 if (asn_get_octetstring(b, (u_char *)&pdu->flags,
518 &octs_len) != ASN_ERR_OK) {
519 snmp_error("cannot decode msg flags");
520 return (SNMP_CODE_FAILED);
521 }
522
523 if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
524 snmp_error("cannot decode msg size");
525 return (SNMP_CODE_FAILED);
526 }
527
528 if (pdu->security_model != SNMP_SECMODEL_USM)
529 return (SNMP_CODE_FAILED);
530
531 if (parse_secparams(b, pdu) != ASN_ERR_OK)
532 return (SNMP_CODE_FAILED);
533 } else {
534 octs_len = SNMP_COMMUNITY_MAXLEN;
535 if (asn_get_octetstring(b, (u_char *)pdu->community,
536 &octs_len) != ASN_ERR_OK) {
537 snmp_error("cannot decode community");
538 return (SNMP_CODE_FAILED);
539 }
540 pdu->community[octs_len] = '\0';
541 }
542
543 return (SNMP_CODE_OK);
544}
545
546enum snmp_code
547snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
548{
549 u_char type;
550 asn_len_t len, trailer;
551 enum asn_err err;
552
553 if (pdu->version == SNMP_V3) {
554 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
555 snmp_error("cannot decode scoped pdu header");
556 return (SNMP_CODE_FAILED);
557 }
558
559 len = SNMP_ENGINE_ID_SIZ;
560 if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
561 &len) != ASN_ERR_OK) {
562 snmp_error("cannot decode msg context engine");
563 return (SNMP_CODE_FAILED);
564 }
565 pdu->context_engine_len = len;
566
567 len = SNMP_CONTEXT_NAME_SIZ;
568 if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
569 &len) != ASN_ERR_OK) {
570 snmp_error("cannot decode msg context name");
571 return (SNMP_CODE_FAILED);
572 }
573 pdu->context_name[len] = '\0';
574 }
575
576 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
577 snmp_error("cannot get pdu header");
578 return (SNMP_CODE_FAILED);
579 }
580 if ((type & ~ASN_TYPE_MASK) !=
581 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
582 snmp_error("bad pdu header tag");
583 return (SNMP_CODE_FAILED);
584 }
585 pdu->type = type & ASN_TYPE_MASK;
586
587 switch (pdu->type) {
588
589 case SNMP_PDU_GET:
590 case SNMP_PDU_GETNEXT:
591 case SNMP_PDU_RESPONSE:
592 case SNMP_PDU_SET:
593 break;
594
595 case SNMP_PDU_TRAP:
596 if (pdu->version != SNMP_V1) {
597 snmp_error("bad pdu type %u", pdu->type);
598 return (SNMP_CODE_FAILED);
599 }
600 break;
601
602 case SNMP_PDU_GETBULK:
603 case SNMP_PDU_INFORM:
604 case SNMP_PDU_TRAP2:
605 case SNMP_PDU_REPORT:
606 if (pdu->version == SNMP_V1) {
607 snmp_error("bad pdu type %u", pdu->type);
608 return (SNMP_CODE_FAILED);
609 }
610 break;
611
612 default:
613 snmp_error("bad pdu type %u", pdu->type);
614 return (SNMP_CODE_FAILED);
615 }
616
617 trailer = b->asn_len - len;
618 b->asn_len = len;
619
620 err = parse_pdus(b, pdu, ip);
621 if (ASN_ERR_STOPPED(err))
622 return (SNMP_CODE_FAILED);
623
624 if (b->asn_len != 0)
625 snmp_error("ignoring trailing junk after pdu");
626
627 b->asn_len = trailer;
628
629 return (SNMP_CODE_OK);
630}
631
632enum snmp_code
633snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
634{
635 u_char type;
636 enum snmp_code code;
637 uint8_t digest[SNMP_USM_AUTH_SIZE];
638
639 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
640 (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
641 return (SNMP_CODE_BADSECLEVEL);
642
643 if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
644 SNMP_CODE_OK)
645 return (SNMP_CODE_FAILED);
646
647 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
648 memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
649 return (SNMP_CODE_BADDIGEST);
650
651 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
652 &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
653 snmp_error("cannot decode encrypted pdu");
654 return (SNMP_CODE_FAILED);
655 }
656 pdu->scoped_ptr = b->asn_ptr;
657
658 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
659 (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
660 return (SNMP_CODE_BADSECLEVEL);
661
662 if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
663 return (SNMP_CODE_FAILED);
664
665 return (code);
666}
667
668/*
669 * Check whether what we have is the complete PDU by snooping at the
670 * enclosing structure header. This returns:
671 * -1 if there are ASN.1 errors
672 * 0 if we need more data
673 * > 0 the length of this PDU
674 */
675int
676snmp_pdu_snoop(const struct asn_buf *b0)
677{
678 u_int length;
679 asn_len_t len;
680 struct asn_buf b = *b0;
681
682 /* <0x10|0x20> <len> <data...> */
683
684 if (b.asn_len == 0)
685 return (0);
686 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
687 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
688 return (-1);
689 }
690 b.asn_len--;
691 b.asn_cptr++;
692
693 if (b.asn_len == 0)
694 return (0);
695
696 if (*b.asn_cptr & 0x80) {
697 /* long length */
698 length = *b.asn_cptr++ & 0x7f;
699 b.asn_len--;
700 if (length == 0) {
701 asn_error(&b, "indefinite length not supported");
702 return (-1);
703 }
704 if (length > ASN_MAXLENLEN) {
705 asn_error(&b, "long length too long (%u)", length);
706 return (-1);
707 }
708 if (length > b.asn_len)
709 return (0);
710 len = 0;
711 while (length--) {
712 len = (len << 8) | *b.asn_cptr++;
713 b.asn_len--;
714 }
715 } else {
716 len = *b.asn_cptr++;
717 b.asn_len--;
718 }
719
720 if (len > b.asn_len)
721 return (0);
722
723 return (len + b.asn_cptr - b0->asn_cptr);
724}
725
726/*
727 * Encode the SNMP PDU without the variable bindings field.
728 * We do this the rather uneffective way by
729 * moving things around and assuming that the length field will never
730 * use more than 2 bytes.
731 * We need a number of pointers to apply the fixes afterwards.
732 */
733enum snmp_code
734snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
735{
736 enum asn_err err;
737 u_char *v3_hdr_ptr;
738
739 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
740 &pdu->outer_ptr) != ASN_ERR_OK)
741 return (SNMP_CODE_FAILED);
742
743 if (pdu->version == SNMP_V1)
744 err = asn_put_integer(b, 0);
745 else if (pdu->version == SNMP_V2c)
746 err = asn_put_integer(b, 1);
747 else if (pdu->version == SNMP_V3)
748 err = asn_put_integer(b, 3);
749 else
750 return (SNMP_CODE_BADVERS);
751 if (err != ASN_ERR_OK)
752 return (SNMP_CODE_FAILED);
753
754 if (pdu->version == SNMP_V3) {
755 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
756 ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
757 return (SNMP_CODE_FAILED);
758
759 if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
760 return (SNMP_CODE_FAILED);
761
762 if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
763 return (SNMP_CODE_FAILED);
764
765 if (pdu->type != SNMP_PDU_RESPONSE &&
766 pdu->type != SNMP_PDU_TRAP &&
767 pdu->type != SNMP_PDU_TRAP2 &&
767 pdu->type != SNMP_PDU_REPORT)
768 pdu->flags |= SNMP_MSG_REPORT_FLAG;
769
770 if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
771 != ASN_ERR_OK)
772 return (SNMP_CODE_FAILED);
773
774 if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
775 return (SNMP_CODE_FAILED);
776
777 if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
778 return (SNMP_CODE_FAILED);
779
780 if (pdu->security_model != SNMP_SECMODEL_USM)
781 return (SNMP_CODE_FAILED);
782
783 if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
784 return (SNMP_CODE_FAILED);
785
786 /* View-based Access Conntrol information */
787 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
788 ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
789 return (SNMP_CODE_FAILED);
790
791 if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
792 pdu->context_engine_len) != ASN_ERR_OK)
793 return (SNMP_CODE_FAILED);
794
795 if (asn_put_octetstring(b, (u_char *)pdu->context_name,
796 strlen(pdu->context_name)) != ASN_ERR_OK)
797 return (SNMP_CODE_FAILED);
798 } else {
799 if (asn_put_octetstring(b, (u_char *)pdu->community,
800 strlen(pdu->community)) != ASN_ERR_OK)
801 return (SNMP_CODE_FAILED);
802 }
803
804 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
805 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
806 return (SNMP_CODE_FAILED);
807
808 if (pdu->type == SNMP_PDU_TRAP) {
809 if (pdu->version != SNMP_V1 ||
810 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
811 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
812 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
813 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
814 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
815 return (SNMP_CODE_FAILED);
816 } else {
817 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
818 pdu->type == SNMP_PDU_INFORM ||
819 pdu->type == SNMP_PDU_TRAP2 ||
820 pdu->type == SNMP_PDU_REPORT))
821 return (SNMP_CODE_FAILED);
822
823 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
824 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
825 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
826 return (SNMP_CODE_FAILED);
827 }
828
829 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
830 &pdu->vars_ptr) != ASN_ERR_OK)
831 return (SNMP_CODE_FAILED);
832
833 return (SNMP_CODE_OK);
834}
835
836static enum asn_err
837snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
838{
839 asn_len_t padlen;
840
841 if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
842 padlen = 8 - (pdu->scoped_len % 8);
843 if (asn_pad(b, padlen) != ASN_ERR_OK)
844 return (ASN_ERR_FAILED);
845 pdu->scoped_len += padlen;
846 }
847
848 return (ASN_ERR_OK);
849}
850
851enum snmp_code
852snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
853{
854 size_t moved = 0;
855 enum snmp_code code;
856
857 if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
858 asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
859 return (SNMP_CODE_FAILED);
860
861 if (pdu->version == SNMP_V3) {
862 if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
863 return (SNMP_CODE_FAILED);
864
865 pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
866 if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
867 return (SNMP_CODE_FAILED);
868
869 if (pdu->security_model != SNMP_SECMODEL_USM)
870 return (SNMP_CODE_FAILED);
871
872 if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
873 return (SNMP_CODE_FAILED);
874
875 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
876 asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
877 return (SNMP_CODE_FAILED);
878 }
879
880 if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
881 return (SNMP_CODE_FAILED);
882
883 pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
884 pdu->digest_ptr -= moved;
885
886 if (pdu->version == SNMP_V3) {
887 if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
888 SNMP_CODE_OK)
889 return (SNMP_CODE_FAILED);
890
891 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
892 memcpy(pdu->digest_ptr, pdu->msg_digest,
893 sizeof(pdu->msg_digest));
894 }
895
896 return (SNMP_CODE_OK);
897}
898
899/*
900 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
901 * Be sure not to cobber b, when something fails.
902 */
903enum asn_err
904snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
905{
906 u_char *ptr;
907 enum asn_err err;
908 struct asn_buf save = *b;
909
910 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
911 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
912 *b = save;
913 return (err);
914 }
915
916 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
917 *b = save;
918 return (err);
919 }
920
921 switch (binding->syntax) {
922
923 case SNMP_SYNTAX_NULL:
924 err = asn_put_null(b);
925 break;
926
927 case SNMP_SYNTAX_INTEGER:
928 err = asn_put_integer(b, binding->v.integer);
929 break;
930
931 case SNMP_SYNTAX_OCTETSTRING:
932 err = asn_put_octetstring(b, binding->v.octetstring.octets,
933 binding->v.octetstring.len);
934 break;
935
936 case SNMP_SYNTAX_OID:
937 err = asn_put_objid(b, &binding->v.oid);
938 break;
939
940 case SNMP_SYNTAX_IPADDRESS:
941 err = asn_put_ipaddress(b, binding->v.ipaddress);
942 break;
943
944 case SNMP_SYNTAX_TIMETICKS:
945 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
946 break;
947
948 case SNMP_SYNTAX_COUNTER:
949 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
950 break;
951
952 case SNMP_SYNTAX_GAUGE:
953 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
954 break;
955
956 case SNMP_SYNTAX_COUNTER64:
957 err = asn_put_counter64(b, binding->v.counter64);
958 break;
959
960 case SNMP_SYNTAX_NOSUCHOBJECT:
961 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
962 break;
963
964 case SNMP_SYNTAX_NOSUCHINSTANCE:
965 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
966 break;
967
968 case SNMP_SYNTAX_ENDOFMIBVIEW:
969 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
970 break;
971 }
972
973 if (err != ASN_ERR_OK) {
974 *b = save;
975 return (err);
976 }
977
978 err = asn_commit_header(b, ptr, NULL);
979 if (err != ASN_ERR_OK) {
980 *b = save;
981 return (err);
982 }
983
984 return (ASN_ERR_OK);
985}
986
987/*
988 * Encode an PDU.
989 */
990enum snmp_code
991snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
992{
993 u_int idx;
994 enum snmp_code err;
995
996 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
997 return (err);
998 for (idx = 0; idx < pdu->nbindings; idx++)
999 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
1000 != ASN_ERR_OK)
1001 return (SNMP_CODE_FAILED);
1002
1003 return (snmp_fix_encoding(resp_b, pdu));
1004}
1005
1006static void
1007dump_binding(const struct snmp_value *b)
1008{
1009 u_int i;
1010 char buf[ASN_OIDSTRLEN];
1011
1012 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1013 switch (b->syntax) {
1014
1015 case SNMP_SYNTAX_NULL:
1016 snmp_printf("NULL");
1017 break;
1018
1019 case SNMP_SYNTAX_INTEGER:
1020 snmp_printf("INTEGER %d", b->v.integer);
1021 break;
1022
1023 case SNMP_SYNTAX_OCTETSTRING:
1024 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1025 for (i = 0; i < b->v.octetstring.len; i++)
1026 snmp_printf(" %02x", b->v.octetstring.octets[i]);
1027 break;
1028
1029 case SNMP_SYNTAX_OID:
1030 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1031 break;
1032
1033 case SNMP_SYNTAX_IPADDRESS:
1034 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1035 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1036 break;
1037
1038 case SNMP_SYNTAX_COUNTER:
1039 snmp_printf("COUNTER %u", b->v.uint32);
1040 break;
1041
1042 case SNMP_SYNTAX_GAUGE:
1043 snmp_printf("GAUGE %u", b->v.uint32);
1044 break;
1045
1046 case SNMP_SYNTAX_TIMETICKS:
1047 snmp_printf("TIMETICKS %u", b->v.uint32);
1048 break;
1049
1050 case SNMP_SYNTAX_COUNTER64:
1051 snmp_printf("COUNTER64 %lld", b->v.counter64);
1052 break;
1053
1054 case SNMP_SYNTAX_NOSUCHOBJECT:
1055 snmp_printf("NoSuchObject");
1056 break;
1057
1058 case SNMP_SYNTAX_NOSUCHINSTANCE:
1059 snmp_printf("NoSuchInstance");
1060 break;
1061
1062 case SNMP_SYNTAX_ENDOFMIBVIEW:
1063 snmp_printf("EndOfMibView");
1064 break;
1065
1066 default:
1067 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1068 break;
1069 }
1070}
1071
1072static __inline void
1073dump_bindings(const struct snmp_pdu *pdu)
1074{
1075 u_int i;
1076
1077 for (i = 0; i < pdu->nbindings; i++) {
1078 snmp_printf(" [%u]: ", i);
1079 dump_binding(&pdu->bindings[i]);
1080 snmp_printf("\n");
1081 }
1082}
1083
1084static __inline void
1085dump_notrap(const struct snmp_pdu *pdu)
1086{
1087 snmp_printf(" request_id=%d", pdu->request_id);
1088 snmp_printf(" error_status=%d", pdu->error_status);
1089 snmp_printf(" error_index=%d\n", pdu->error_index);
1090 dump_bindings(pdu);
1091}
1092
1093void
1094snmp_pdu_dump(const struct snmp_pdu *pdu)
1095{
1096 char buf[ASN_OIDSTRLEN];
1097 const char *vers;
1098 static const char *types[] = {
1099 [SNMP_PDU_GET] = "GET",
1100 [SNMP_PDU_GETNEXT] = "GETNEXT",
1101 [SNMP_PDU_RESPONSE] = "RESPONSE",
1102 [SNMP_PDU_SET] = "SET",
1103 [SNMP_PDU_TRAP] = "TRAPv1",
1104 [SNMP_PDU_GETBULK] = "GETBULK",
1105 [SNMP_PDU_INFORM] = "INFORM",
1106 [SNMP_PDU_TRAP2] = "TRAPv2",
1107 [SNMP_PDU_REPORT] = "REPORT",
1108 };
1109
1110 if (pdu->version == SNMP_V1)
1111 vers = "SNMPv1";
1112 else if (pdu->version == SNMP_V2c)
1113 vers = "SNMPv2c";
1114 else if (pdu->version == SNMP_V3)
1115 vers = "SNMPv3";
1116 else
1117 vers = "v?";
1118
1119 switch (pdu->type) {
1120 case SNMP_PDU_TRAP:
1121 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1122 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1123 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1124 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1125 snmp_printf(" generic_trap=%d", pdu->generic_trap);
1126 snmp_printf(" specific_trap=%d", pdu->specific_trap);
1127 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1128 dump_bindings(pdu);
1129 break;
1130
1131 case SNMP_PDU_GET:
1132 case SNMP_PDU_GETNEXT:
1133 case SNMP_PDU_RESPONSE:
1134 case SNMP_PDU_SET:
1135 case SNMP_PDU_GETBULK:
1136 case SNMP_PDU_INFORM:
1137 case SNMP_PDU_TRAP2:
1138 case SNMP_PDU_REPORT:
1139 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1140 dump_notrap(pdu);
1141 break;
1142
1143 default:
1144 snmp_printf("bad pdu type %u\n", pdu->type);
1145 break;
1146 }
1147}
1148
1149void
1150snmp_value_free(struct snmp_value *value)
1151{
1152 if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1153 free(value->v.octetstring.octets);
1154 value->syntax = SNMP_SYNTAX_NULL;
1155}
1156
1157int
1158snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1159{
1160 to->var = from->var;
1161 to->syntax = from->syntax;
1162
1163 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1164 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1165 to->v.octetstring.octets = NULL;
1166 else {
1167 to->v.octetstring.octets = malloc(to->v.octetstring.len);
1168 if (to->v.octetstring.octets == NULL)
1169 return (-1);
1170 (void)memcpy(to->v.octetstring.octets,
1171 from->v.octetstring.octets, to->v.octetstring.len);
1172 }
1173 } else
1174 to->v = from->v;
1175 return (0);
1176}
1177
1178void
768 pdu->type != SNMP_PDU_REPORT)
769 pdu->flags |= SNMP_MSG_REPORT_FLAG;
770
771 if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
772 != ASN_ERR_OK)
773 return (SNMP_CODE_FAILED);
774
775 if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
776 return (SNMP_CODE_FAILED);
777
778 if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
779 return (SNMP_CODE_FAILED);
780
781 if (pdu->security_model != SNMP_SECMODEL_USM)
782 return (SNMP_CODE_FAILED);
783
784 if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
785 return (SNMP_CODE_FAILED);
786
787 /* View-based Access Conntrol information */
788 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
789 ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
790 return (SNMP_CODE_FAILED);
791
792 if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
793 pdu->context_engine_len) != ASN_ERR_OK)
794 return (SNMP_CODE_FAILED);
795
796 if (asn_put_octetstring(b, (u_char *)pdu->context_name,
797 strlen(pdu->context_name)) != ASN_ERR_OK)
798 return (SNMP_CODE_FAILED);
799 } else {
800 if (asn_put_octetstring(b, (u_char *)pdu->community,
801 strlen(pdu->community)) != ASN_ERR_OK)
802 return (SNMP_CODE_FAILED);
803 }
804
805 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
806 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
807 return (SNMP_CODE_FAILED);
808
809 if (pdu->type == SNMP_PDU_TRAP) {
810 if (pdu->version != SNMP_V1 ||
811 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
812 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
813 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
814 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
815 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
816 return (SNMP_CODE_FAILED);
817 } else {
818 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
819 pdu->type == SNMP_PDU_INFORM ||
820 pdu->type == SNMP_PDU_TRAP2 ||
821 pdu->type == SNMP_PDU_REPORT))
822 return (SNMP_CODE_FAILED);
823
824 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
825 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
826 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
827 return (SNMP_CODE_FAILED);
828 }
829
830 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
831 &pdu->vars_ptr) != ASN_ERR_OK)
832 return (SNMP_CODE_FAILED);
833
834 return (SNMP_CODE_OK);
835}
836
837static enum asn_err
838snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
839{
840 asn_len_t padlen;
841
842 if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
843 padlen = 8 - (pdu->scoped_len % 8);
844 if (asn_pad(b, padlen) != ASN_ERR_OK)
845 return (ASN_ERR_FAILED);
846 pdu->scoped_len += padlen;
847 }
848
849 return (ASN_ERR_OK);
850}
851
852enum snmp_code
853snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
854{
855 size_t moved = 0;
856 enum snmp_code code;
857
858 if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
859 asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
860 return (SNMP_CODE_FAILED);
861
862 if (pdu->version == SNMP_V3) {
863 if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
864 return (SNMP_CODE_FAILED);
865
866 pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
867 if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
868 return (SNMP_CODE_FAILED);
869
870 if (pdu->security_model != SNMP_SECMODEL_USM)
871 return (SNMP_CODE_FAILED);
872
873 if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
874 return (SNMP_CODE_FAILED);
875
876 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
877 asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
878 return (SNMP_CODE_FAILED);
879 }
880
881 if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
882 return (SNMP_CODE_FAILED);
883
884 pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
885 pdu->digest_ptr -= moved;
886
887 if (pdu->version == SNMP_V3) {
888 if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
889 SNMP_CODE_OK)
890 return (SNMP_CODE_FAILED);
891
892 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
893 memcpy(pdu->digest_ptr, pdu->msg_digest,
894 sizeof(pdu->msg_digest));
895 }
896
897 return (SNMP_CODE_OK);
898}
899
900/*
901 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
902 * Be sure not to cobber b, when something fails.
903 */
904enum asn_err
905snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
906{
907 u_char *ptr;
908 enum asn_err err;
909 struct asn_buf save = *b;
910
911 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
912 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
913 *b = save;
914 return (err);
915 }
916
917 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
918 *b = save;
919 return (err);
920 }
921
922 switch (binding->syntax) {
923
924 case SNMP_SYNTAX_NULL:
925 err = asn_put_null(b);
926 break;
927
928 case SNMP_SYNTAX_INTEGER:
929 err = asn_put_integer(b, binding->v.integer);
930 break;
931
932 case SNMP_SYNTAX_OCTETSTRING:
933 err = asn_put_octetstring(b, binding->v.octetstring.octets,
934 binding->v.octetstring.len);
935 break;
936
937 case SNMP_SYNTAX_OID:
938 err = asn_put_objid(b, &binding->v.oid);
939 break;
940
941 case SNMP_SYNTAX_IPADDRESS:
942 err = asn_put_ipaddress(b, binding->v.ipaddress);
943 break;
944
945 case SNMP_SYNTAX_TIMETICKS:
946 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
947 break;
948
949 case SNMP_SYNTAX_COUNTER:
950 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
951 break;
952
953 case SNMP_SYNTAX_GAUGE:
954 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
955 break;
956
957 case SNMP_SYNTAX_COUNTER64:
958 err = asn_put_counter64(b, binding->v.counter64);
959 break;
960
961 case SNMP_SYNTAX_NOSUCHOBJECT:
962 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
963 break;
964
965 case SNMP_SYNTAX_NOSUCHINSTANCE:
966 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
967 break;
968
969 case SNMP_SYNTAX_ENDOFMIBVIEW:
970 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
971 break;
972 }
973
974 if (err != ASN_ERR_OK) {
975 *b = save;
976 return (err);
977 }
978
979 err = asn_commit_header(b, ptr, NULL);
980 if (err != ASN_ERR_OK) {
981 *b = save;
982 return (err);
983 }
984
985 return (ASN_ERR_OK);
986}
987
988/*
989 * Encode an PDU.
990 */
991enum snmp_code
992snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
993{
994 u_int idx;
995 enum snmp_code err;
996
997 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
998 return (err);
999 for (idx = 0; idx < pdu->nbindings; idx++)
1000 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
1001 != ASN_ERR_OK)
1002 return (SNMP_CODE_FAILED);
1003
1004 return (snmp_fix_encoding(resp_b, pdu));
1005}
1006
1007static void
1008dump_binding(const struct snmp_value *b)
1009{
1010 u_int i;
1011 char buf[ASN_OIDSTRLEN];
1012
1013 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1014 switch (b->syntax) {
1015
1016 case SNMP_SYNTAX_NULL:
1017 snmp_printf("NULL");
1018 break;
1019
1020 case SNMP_SYNTAX_INTEGER:
1021 snmp_printf("INTEGER %d", b->v.integer);
1022 break;
1023
1024 case SNMP_SYNTAX_OCTETSTRING:
1025 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1026 for (i = 0; i < b->v.octetstring.len; i++)
1027 snmp_printf(" %02x", b->v.octetstring.octets[i]);
1028 break;
1029
1030 case SNMP_SYNTAX_OID:
1031 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1032 break;
1033
1034 case SNMP_SYNTAX_IPADDRESS:
1035 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1036 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1037 break;
1038
1039 case SNMP_SYNTAX_COUNTER:
1040 snmp_printf("COUNTER %u", b->v.uint32);
1041 break;
1042
1043 case SNMP_SYNTAX_GAUGE:
1044 snmp_printf("GAUGE %u", b->v.uint32);
1045 break;
1046
1047 case SNMP_SYNTAX_TIMETICKS:
1048 snmp_printf("TIMETICKS %u", b->v.uint32);
1049 break;
1050
1051 case SNMP_SYNTAX_COUNTER64:
1052 snmp_printf("COUNTER64 %lld", b->v.counter64);
1053 break;
1054
1055 case SNMP_SYNTAX_NOSUCHOBJECT:
1056 snmp_printf("NoSuchObject");
1057 break;
1058
1059 case SNMP_SYNTAX_NOSUCHINSTANCE:
1060 snmp_printf("NoSuchInstance");
1061 break;
1062
1063 case SNMP_SYNTAX_ENDOFMIBVIEW:
1064 snmp_printf("EndOfMibView");
1065 break;
1066
1067 default:
1068 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1069 break;
1070 }
1071}
1072
1073static __inline void
1074dump_bindings(const struct snmp_pdu *pdu)
1075{
1076 u_int i;
1077
1078 for (i = 0; i < pdu->nbindings; i++) {
1079 snmp_printf(" [%u]: ", i);
1080 dump_binding(&pdu->bindings[i]);
1081 snmp_printf("\n");
1082 }
1083}
1084
1085static __inline void
1086dump_notrap(const struct snmp_pdu *pdu)
1087{
1088 snmp_printf(" request_id=%d", pdu->request_id);
1089 snmp_printf(" error_status=%d", pdu->error_status);
1090 snmp_printf(" error_index=%d\n", pdu->error_index);
1091 dump_bindings(pdu);
1092}
1093
1094void
1095snmp_pdu_dump(const struct snmp_pdu *pdu)
1096{
1097 char buf[ASN_OIDSTRLEN];
1098 const char *vers;
1099 static const char *types[] = {
1100 [SNMP_PDU_GET] = "GET",
1101 [SNMP_PDU_GETNEXT] = "GETNEXT",
1102 [SNMP_PDU_RESPONSE] = "RESPONSE",
1103 [SNMP_PDU_SET] = "SET",
1104 [SNMP_PDU_TRAP] = "TRAPv1",
1105 [SNMP_PDU_GETBULK] = "GETBULK",
1106 [SNMP_PDU_INFORM] = "INFORM",
1107 [SNMP_PDU_TRAP2] = "TRAPv2",
1108 [SNMP_PDU_REPORT] = "REPORT",
1109 };
1110
1111 if (pdu->version == SNMP_V1)
1112 vers = "SNMPv1";
1113 else if (pdu->version == SNMP_V2c)
1114 vers = "SNMPv2c";
1115 else if (pdu->version == SNMP_V3)
1116 vers = "SNMPv3";
1117 else
1118 vers = "v?";
1119
1120 switch (pdu->type) {
1121 case SNMP_PDU_TRAP:
1122 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1123 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1124 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1125 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1126 snmp_printf(" generic_trap=%d", pdu->generic_trap);
1127 snmp_printf(" specific_trap=%d", pdu->specific_trap);
1128 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1129 dump_bindings(pdu);
1130 break;
1131
1132 case SNMP_PDU_GET:
1133 case SNMP_PDU_GETNEXT:
1134 case SNMP_PDU_RESPONSE:
1135 case SNMP_PDU_SET:
1136 case SNMP_PDU_GETBULK:
1137 case SNMP_PDU_INFORM:
1138 case SNMP_PDU_TRAP2:
1139 case SNMP_PDU_REPORT:
1140 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1141 dump_notrap(pdu);
1142 break;
1143
1144 default:
1145 snmp_printf("bad pdu type %u\n", pdu->type);
1146 break;
1147 }
1148}
1149
1150void
1151snmp_value_free(struct snmp_value *value)
1152{
1153 if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1154 free(value->v.octetstring.octets);
1155 value->syntax = SNMP_SYNTAX_NULL;
1156}
1157
1158int
1159snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1160{
1161 to->var = from->var;
1162 to->syntax = from->syntax;
1163
1164 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1165 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1166 to->v.octetstring.octets = NULL;
1167 else {
1168 to->v.octetstring.octets = malloc(to->v.octetstring.len);
1169 if (to->v.octetstring.octets == NULL)
1170 return (-1);
1171 (void)memcpy(to->v.octetstring.octets,
1172 from->v.octetstring.octets, to->v.octetstring.len);
1173 }
1174 } else
1175 to->v = from->v;
1176 return (0);
1177}
1178
1179void
1179snmp_pdu_init_secparams(struct snmp_pdu *pdu, struct snmp_engine *eng,
1180 struct snmp_user *user)
1180snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1181{
1182 int32_t rval;
1183
1181{
1182 int32_t rval;
1183
1184 memcpy(&pdu->engine, eng, sizeof(pdu->engine));
1185 memcpy(&pdu->user, user, sizeof(pdu->user));
1186
1187 if (user->auth_proto != SNMP_AUTH_NOAUTH)
1184 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1188 pdu->flags |= SNMP_MSG_AUTH_FLAG;
1189
1185 pdu->flags |= SNMP_MSG_AUTH_FLAG;
1186
1190 switch (user->priv_proto) {
1187 switch (pdu->user.priv_proto) {
1191 case SNMP_PRIV_DES:
1188 case SNMP_PRIV_DES:
1192 memcpy(pdu->msg_salt, &eng->engine_boots,
1193 sizeof(eng->engine_boots));
1189 memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1190 sizeof(pdu->engine.engine_boots));
1194 rval = random();
1191 rval = random();
1195 memcpy(pdu->msg_salt + sizeof(eng->engine_boots), &rval,
1192 memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1196 sizeof(int32_t));
1197 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1198 break;
1199 case SNMP_PRIV_AES:
1200 rval = random();
1201 memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1202 rval = random();
1203 memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1204 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1205 break;
1206 default:
1207 break;
1208 }
1209}
1210
1211void
1212snmp_pdu_free(struct snmp_pdu *pdu)
1213{
1214 u_int i;
1215
1216 for (i = 0; i < pdu->nbindings; i++)
1217 snmp_value_free(&pdu->bindings[i]);
1218}
1219
1220/*
1221 * Parse an ASCII SNMP value into the binary form
1222 */
1223int
1224snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1225{
1226 char *end;
1227
1228 switch (syntax) {
1229
1230 case SNMP_SYNTAX_NULL:
1231 case SNMP_SYNTAX_NOSUCHOBJECT:
1232 case SNMP_SYNTAX_NOSUCHINSTANCE:
1233 case SNMP_SYNTAX_ENDOFMIBVIEW:
1234 if (*str != '\0')
1235 return (-1);
1236 return (0);
1237
1238 case SNMP_SYNTAX_INTEGER:
1239 v->integer = strtoll(str, &end, 0);
1240 if (*end != '\0')
1241 return (-1);
1242 return (0);
1243
1244 case SNMP_SYNTAX_OCTETSTRING:
1245 {
1246 u_long len; /* actual length of string */
1247 u_long alloc; /* allocate length of string */
1248 u_char *octs; /* actual octets */
1249 u_long oct; /* actual octet */
1250 u_char *nocts; /* to avoid memory leak */
1251 u_char c; /* actual character */
1252
1253# define STUFFC(C) \
1254 if (alloc == len) { \
1255 alloc += 100; \
1256 if ((nocts = realloc(octs, alloc)) == NULL) { \
1257 free(octs); \
1258 return (-1); \
1259 } \
1260 octs = nocts; \
1261 } \
1262 octs[len++] = (C);
1263
1264 len = alloc = 0;
1265 octs = NULL;
1266
1267 if (*str == '"') {
1268 str++;
1269 while((c = *str++) != '\0') {
1270 if (c == '"') {
1271 if (*str != '\0') {
1272 free(octs);
1273 return (-1);
1274 }
1275 break;
1276 }
1277 if (c == '\\') {
1278 switch (c = *str++) {
1279
1280 case '\\':
1281 break;
1282 case 'a':
1283 c = '\a';
1284 break;
1285 case 'b':
1286 c = '\b';
1287 break;
1288 case 'f':
1289 c = '\f';
1290 break;
1291 case 'n':
1292 c = '\n';
1293 break;
1294 case 'r':
1295 c = '\r';
1296 break;
1297 case 't':
1298 c = '\t';
1299 break;
1300 case 'v':
1301 c = '\v';
1302 break;
1303 case 'x':
1304 c = 0;
1305 if (!isxdigit(*str))
1306 break;
1307 if (isdigit(*str))
1308 c = *str++ - '0';
1309 else if (isupper(*str))
1310 c = *str++ - 'A' + 10;
1311 else
1312 c = *str++ - 'a' + 10;
1313 if (!isxdigit(*str))
1314 break;
1315 if (isdigit(*str))
1316 c += *str++ - '0';
1317 else if (isupper(*str))
1318 c += *str++ - 'A' + 10;
1319 else
1320 c += *str++ - 'a' + 10;
1321 break;
1322 case '0': case '1': case '2':
1323 case '3': case '4': case '5':
1324 case '6': case '7':
1325 c = *str++ - '0';
1326 if (*str < '0' || *str > '7')
1327 break;
1328 c = *str++ - '0';
1329 if (*str < '0' || *str > '7')
1330 break;
1331 c = *str++ - '0';
1332 break;
1333 default:
1334 break;
1335 }
1336 }
1337 STUFFC(c);
1338 }
1339 } else {
1340 while (*str != '\0') {
1341 oct = strtoul(str, &end, 16);
1342 str = end;
1343 if (oct > 0xff) {
1344 free(octs);
1345 return (-1);
1346 }
1347 STUFFC(oct);
1348 if (*str == ':')
1349 str++;
1350 else if(*str != '\0') {
1351 free(octs);
1352 return (-1);
1353 }
1354 }
1355 }
1356 v->octetstring.octets = octs;
1357 v->octetstring.len = len;
1358 return (0);
1359# undef STUFFC
1360 }
1361
1362 case SNMP_SYNTAX_OID:
1363 {
1364 u_long subid;
1365
1366 v->oid.len = 0;
1367
1368 for (;;) {
1369 if (v->oid.len == ASN_MAXOIDLEN)
1370 return (-1);
1371 subid = strtoul(str, &end, 10);
1372 str = end;
1373 if (subid > ASN_MAXID)
1374 return (-1);
1375 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1376 if (*str == '\0')
1377 break;
1378 if (*str != '.')
1379 return (-1);
1380 str++;
1381 }
1382 return (0);
1383 }
1384
1385 case SNMP_SYNTAX_IPADDRESS:
1386 {
1387 struct hostent *he;
1388 u_long ip[4];
1389 int n;
1390
1391 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1392 &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1393 ip[0] <= 0xff && ip[1] <= 0xff &&
1394 ip[2] <= 0xff && ip[3] <= 0xff) {
1395 v->ipaddress[0] = (u_char)ip[0];
1396 v->ipaddress[1] = (u_char)ip[1];
1397 v->ipaddress[2] = (u_char)ip[2];
1398 v->ipaddress[3] = (u_char)ip[3];
1399 return (0);
1400 }
1401
1402 if ((he = gethostbyname(str)) == NULL)
1403 return (-1);
1404 if (he->h_addrtype != AF_INET)
1405 return (-1);
1406
1407 v->ipaddress[0] = he->h_addr[0];
1408 v->ipaddress[1] = he->h_addr[1];
1409 v->ipaddress[2] = he->h_addr[2];
1410 v->ipaddress[3] = he->h_addr[3];
1411 return (0);
1412 }
1413
1414 case SNMP_SYNTAX_COUNTER:
1415 case SNMP_SYNTAX_GAUGE:
1416 case SNMP_SYNTAX_TIMETICKS:
1417 {
1418 uint64_t sub;
1419
1420 sub = strtoull(str, &end, 0);
1421 if (*end != '\0' || sub > 0xffffffff)
1422 return (-1);
1423 v->uint32 = (uint32_t)sub;
1424 return (0);
1425 }
1426
1427 case SNMP_SYNTAX_COUNTER64:
1428 v->counter64 = strtoull(str, &end, 0);
1429 if (*end != '\0')
1430 return (-1);
1431 return (0);
1432 }
1433 abort();
1434}
1435
1436static void
1437snmp_error_func(const char *fmt, ...)
1438{
1439 va_list ap;
1440
1441 va_start(ap, fmt);
1442 fprintf(stderr, "SNMP: ");
1443 vfprintf(stderr, fmt, ap);
1444 fprintf(stderr, "\n");
1445 va_end(ap);
1446}
1447
1448static void
1449snmp_printf_func(const char *fmt, ...)
1450{
1451 va_list ap;
1452
1453 va_start(ap, fmt);
1454 vfprintf(stderr, fmt, ap);
1455 va_end(ap);
1456}
1193 sizeof(int32_t));
1194 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1195 break;
1196 case SNMP_PRIV_AES:
1197 rval = random();
1198 memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1199 rval = random();
1200 memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1201 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1202 break;
1203 default:
1204 break;
1205 }
1206}
1207
1208void
1209snmp_pdu_free(struct snmp_pdu *pdu)
1210{
1211 u_int i;
1212
1213 for (i = 0; i < pdu->nbindings; i++)
1214 snmp_value_free(&pdu->bindings[i]);
1215}
1216
1217/*
1218 * Parse an ASCII SNMP value into the binary form
1219 */
1220int
1221snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1222{
1223 char *end;
1224
1225 switch (syntax) {
1226
1227 case SNMP_SYNTAX_NULL:
1228 case SNMP_SYNTAX_NOSUCHOBJECT:
1229 case SNMP_SYNTAX_NOSUCHINSTANCE:
1230 case SNMP_SYNTAX_ENDOFMIBVIEW:
1231 if (*str != '\0')
1232 return (-1);
1233 return (0);
1234
1235 case SNMP_SYNTAX_INTEGER:
1236 v->integer = strtoll(str, &end, 0);
1237 if (*end != '\0')
1238 return (-1);
1239 return (0);
1240
1241 case SNMP_SYNTAX_OCTETSTRING:
1242 {
1243 u_long len; /* actual length of string */
1244 u_long alloc; /* allocate length of string */
1245 u_char *octs; /* actual octets */
1246 u_long oct; /* actual octet */
1247 u_char *nocts; /* to avoid memory leak */
1248 u_char c; /* actual character */
1249
1250# define STUFFC(C) \
1251 if (alloc == len) { \
1252 alloc += 100; \
1253 if ((nocts = realloc(octs, alloc)) == NULL) { \
1254 free(octs); \
1255 return (-1); \
1256 } \
1257 octs = nocts; \
1258 } \
1259 octs[len++] = (C);
1260
1261 len = alloc = 0;
1262 octs = NULL;
1263
1264 if (*str == '"') {
1265 str++;
1266 while((c = *str++) != '\0') {
1267 if (c == '"') {
1268 if (*str != '\0') {
1269 free(octs);
1270 return (-1);
1271 }
1272 break;
1273 }
1274 if (c == '\\') {
1275 switch (c = *str++) {
1276
1277 case '\\':
1278 break;
1279 case 'a':
1280 c = '\a';
1281 break;
1282 case 'b':
1283 c = '\b';
1284 break;
1285 case 'f':
1286 c = '\f';
1287 break;
1288 case 'n':
1289 c = '\n';
1290 break;
1291 case 'r':
1292 c = '\r';
1293 break;
1294 case 't':
1295 c = '\t';
1296 break;
1297 case 'v':
1298 c = '\v';
1299 break;
1300 case 'x':
1301 c = 0;
1302 if (!isxdigit(*str))
1303 break;
1304 if (isdigit(*str))
1305 c = *str++ - '0';
1306 else if (isupper(*str))
1307 c = *str++ - 'A' + 10;
1308 else
1309 c = *str++ - 'a' + 10;
1310 if (!isxdigit(*str))
1311 break;
1312 if (isdigit(*str))
1313 c += *str++ - '0';
1314 else if (isupper(*str))
1315 c += *str++ - 'A' + 10;
1316 else
1317 c += *str++ - 'a' + 10;
1318 break;
1319 case '0': case '1': case '2':
1320 case '3': case '4': case '5':
1321 case '6': case '7':
1322 c = *str++ - '0';
1323 if (*str < '0' || *str > '7')
1324 break;
1325 c = *str++ - '0';
1326 if (*str < '0' || *str > '7')
1327 break;
1328 c = *str++ - '0';
1329 break;
1330 default:
1331 break;
1332 }
1333 }
1334 STUFFC(c);
1335 }
1336 } else {
1337 while (*str != '\0') {
1338 oct = strtoul(str, &end, 16);
1339 str = end;
1340 if (oct > 0xff) {
1341 free(octs);
1342 return (-1);
1343 }
1344 STUFFC(oct);
1345 if (*str == ':')
1346 str++;
1347 else if(*str != '\0') {
1348 free(octs);
1349 return (-1);
1350 }
1351 }
1352 }
1353 v->octetstring.octets = octs;
1354 v->octetstring.len = len;
1355 return (0);
1356# undef STUFFC
1357 }
1358
1359 case SNMP_SYNTAX_OID:
1360 {
1361 u_long subid;
1362
1363 v->oid.len = 0;
1364
1365 for (;;) {
1366 if (v->oid.len == ASN_MAXOIDLEN)
1367 return (-1);
1368 subid = strtoul(str, &end, 10);
1369 str = end;
1370 if (subid > ASN_MAXID)
1371 return (-1);
1372 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1373 if (*str == '\0')
1374 break;
1375 if (*str != '.')
1376 return (-1);
1377 str++;
1378 }
1379 return (0);
1380 }
1381
1382 case SNMP_SYNTAX_IPADDRESS:
1383 {
1384 struct hostent *he;
1385 u_long ip[4];
1386 int n;
1387
1388 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1389 &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1390 ip[0] <= 0xff && ip[1] <= 0xff &&
1391 ip[2] <= 0xff && ip[3] <= 0xff) {
1392 v->ipaddress[0] = (u_char)ip[0];
1393 v->ipaddress[1] = (u_char)ip[1];
1394 v->ipaddress[2] = (u_char)ip[2];
1395 v->ipaddress[3] = (u_char)ip[3];
1396 return (0);
1397 }
1398
1399 if ((he = gethostbyname(str)) == NULL)
1400 return (-1);
1401 if (he->h_addrtype != AF_INET)
1402 return (-1);
1403
1404 v->ipaddress[0] = he->h_addr[0];
1405 v->ipaddress[1] = he->h_addr[1];
1406 v->ipaddress[2] = he->h_addr[2];
1407 v->ipaddress[3] = he->h_addr[3];
1408 return (0);
1409 }
1410
1411 case SNMP_SYNTAX_COUNTER:
1412 case SNMP_SYNTAX_GAUGE:
1413 case SNMP_SYNTAX_TIMETICKS:
1414 {
1415 uint64_t sub;
1416
1417 sub = strtoull(str, &end, 0);
1418 if (*end != '\0' || sub > 0xffffffff)
1419 return (-1);
1420 v->uint32 = (uint32_t)sub;
1421 return (0);
1422 }
1423
1424 case SNMP_SYNTAX_COUNTER64:
1425 v->counter64 = strtoull(str, &end, 0);
1426 if (*end != '\0')
1427 return (-1);
1428 return (0);
1429 }
1430 abort();
1431}
1432
1433static void
1434snmp_error_func(const char *fmt, ...)
1435{
1436 va_list ap;
1437
1438 va_start(ap, fmt);
1439 fprintf(stderr, "SNMP: ");
1440 vfprintf(stderr, fmt, ap);
1441 fprintf(stderr, "\n");
1442 va_end(ap);
1443}
1444
1445static void
1446snmp_printf_func(const char *fmt, ...)
1447{
1448 va_list ap;
1449
1450 va_start(ap, fmt);
1451 vfprintf(stderr, fmt, ap);
1452 va_end(ap);
1453}