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