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