1 /**
2 * @file
3 * SNMP message processing (RFC1157).
4 */
5
6 /*
7 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8 * Copyright (c) 2016 Elias Oenal.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * Author: Christiaan Simons <christiaan.simons@axon.tv>
34 * Martin Hentschel <info@cl-soft.de>
35 * Elias Oenal <lwip@eliasoenal.com>
36 */
37
38 #include "lwip/apps/snmp_opts.h"
39
40 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
41
42 #include "snmp_msg.h"
43 #include "snmp_asn1.h"
44 #include "snmp_core_priv.h"
45 #include "lwip/ip_addr.h"
46 #include "lwip/stats.h"
47
48 #if LWIP_SNMP_V3
49 #include "lwip/apps/snmpv3.h"
50 #include "snmpv3_priv.h"
51 #ifdef LWIP_HOOK_FILENAME
52 #include LWIP_HOOK_FILENAME
53 #endif
54 #endif
55
56 #include <string.h>
57
58 #define SNMP_V3_AUTH_FLAG 0x01
59 #define SNMP_V3_PRIV_FLAG 0x02
60
61 /* Security levels */
62 #define SNMP_V3_NOAUTHNOPRIV 0x00
63 #define SNMP_V3_AUTHNOPRIV SNMP_V3_AUTH_FLAG
64 #define SNMP_V3_AUTHPRIV (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)
65
66 /* public (non-static) constants */
67 /** SNMP community string */
68 const char *snmp_community = SNMP_COMMUNITY;
69 /** SNMP community string for write access */
70 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
71 /** SNMP community string for sending traps */
72 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
73
74 snmp_write_callback_fct snmp_write_callback = NULL;
75 void* snmp_write_callback_arg = NULL;
76
77 #if LWIP_SNMP_CONFIGURE_VERSIONS
78
79 static u8_t v1_enabled = 1;
80 static u8_t v2c_enabled = 1;
81 static u8_t v3_enabled = 1;
82
83 static u8_t
snmp_version_enabled(u8_t version)84 snmp_version_enabled(u8_t version)
85 {
86 LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c)
87 #if LWIP_SNMP_V3
88 || (version == SNMP_VERSION_3)
89 #endif
90 );
91
92 if (version == SNMP_VERSION_1) {
93 return v1_enabled;
94 }
95 else if (version == SNMP_VERSION_2c) {
96 return v2c_enabled;
97 }
98 #if LWIP_SNMP_V3
99 else { /* version == SNMP_VERSION_3 */
100 return v3_enabled;
101 }
102 #endif
103 }
104
105 u8_t
snmp_v1_enabled(void)106 snmp_v1_enabled(void)
107 {
108 return snmp_version_enabled(SNMP_VERSION_1);
109 }
110
111 u8_t
snmp_v2c_enabled(void)112 snmp_v2c_enabled(void)
113 {
114 return snmp_version_enabled(SNMP_VERSION_2c);
115 }
116
117 u8_t
snmp_v3_enabled(void)118 snmp_v3_enabled(void)
119 {
120 return snmp_version_enabled(SNMP_VERSION_3);
121 }
122
123 static void
snmp_version_enable(u8_t version,u8_t enable)124 snmp_version_enable(u8_t version, u8_t enable)
125 {
126 LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c)
127 #if LWIP_SNMP_V3
128 || (version == SNMP_VERSION_3)
129 #endif
130 );
131
132 if (version == SNMP_VERSION_1) {
133 v1_enabled = enable;
134 }
135 else if (version == SNMP_VERSION_2c) {
136 v2c_enabled = enable;
137 }
138 #if LWIP_SNMP_V3
139 else { /* version == SNMP_VERSION_3 */
140 v3_enabled = enable;
141 }
142 #endif
143 }
144
145 void
snmp_v1_enable(u8_t enable)146 snmp_v1_enable(u8_t enable)
147 {
148 snmp_version_enable(SNMP_VERSION_1, enable);
149 }
150
151 void
snmp_v2c_enable(u8_t enable)152 snmp_v2c_enable(u8_t enable)
153 {
154 snmp_version_enable(SNMP_VERSION_2c, enable);
155 }
156
157 void
snmp_v3_enable(u8_t enable)158 snmp_v3_enable(u8_t enable)
159 {
160 snmp_version_enable(SNMP_VERSION_3, enable);
161 }
162
163 #endif
164
165 /**
166 * @ingroup snmp_core
167 * Returns current SNMP community string.
168 * @return current SNMP community string
169 */
170 const char *
snmp_get_community(void)171 snmp_get_community(void)
172 {
173 return snmp_community;
174 }
175
176 /**
177 * @ingroup snmp_core
178 * Sets SNMP community string.
179 * The string itself (its storage) must be valid throughout the whole life of
180 * program (or until it is changed to sth else).
181 *
182 * @param community is a pointer to new community string
183 */
184 void
snmp_set_community(const char * const community)185 snmp_set_community(const char * const community)
186 {
187 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
188 snmp_community = community;
189 }
190
191 /**
192 * @ingroup snmp_core
193 * Returns current SNMP write-access community string.
194 * @return current SNMP write-access community string
195 */
196 const char *
snmp_get_community_write(void)197 snmp_get_community_write(void)
198 {
199 return snmp_community_write;
200 }
201
202 /**
203 * @ingroup snmp_traps
204 * Returns current SNMP community string used for sending traps.
205 * @return current SNMP community string used for sending traps
206 */
207 const char *
snmp_get_community_trap(void)208 snmp_get_community_trap(void)
209 {
210 return snmp_community_trap;
211 }
212
213 /**
214 * @ingroup snmp_core
215 * Sets SNMP community string for write-access.
216 * The string itself (its storage) must be valid throughout the whole life of
217 * program (or until it is changed to sth else).
218 *
219 * @param community is a pointer to new write-access community string
220 */
221 void
snmp_set_community_write(const char * const community)222 snmp_set_community_write(const char * const community)
223 {
224 LWIP_ASSERT("community string must not be NULL", community != NULL);
225 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
226 snmp_community_write = community;
227 }
228
229 /**
230 * @ingroup snmp_traps
231 * Sets SNMP community string used for sending traps.
232 * The string itself (its storage) must be valid throughout the whole life of
233 * program (or until it is changed to sth else).
234 *
235 * @param community is a pointer to new trap community string
236 */
237 void
snmp_set_community_trap(const char * const community)238 snmp_set_community_trap(const char * const community)
239 {
240 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
241 snmp_community_trap = community;
242 }
243
244 /**
245 * @ingroup snmp_core
246 * Callback fired on every successful write access
247 */
248 void
snmp_set_write_callback(snmp_write_callback_fct write_callback,void * callback_arg)249 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg)
250 {
251 snmp_write_callback = write_callback;
252 snmp_write_callback_arg = callback_arg;
253 }
254
255 /* ----------------------------------------------------------------------- */
256 /* forward declarations */
257 /* ----------------------------------------------------------------------- */
258
259 static err_t snmp_process_get_request(struct snmp_request *request);
260 static err_t snmp_process_getnext_request(struct snmp_request *request);
261 static err_t snmp_process_getbulk_request(struct snmp_request *request);
262 static err_t snmp_process_set_request(struct snmp_request *request);
263
264 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
265 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
266 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
267 static void snmp_execute_write_callbacks(struct snmp_request *request);
268
269
270 /* ----------------------------------------------------------------------- */
271 /* implementation */
272 /* ----------------------------------------------------------------------- */
273
274 void
snmp_receive(void * handle,struct pbuf * p,const ip_addr_t * source_ip,u16_t port)275 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
276 {
277 err_t err;
278 struct snmp_request request;
279
280 memset(&request, 0, sizeof(request));
281 request.handle = handle;
282 request.source_ip = source_ip;
283 request.source_port = port;
284 request.inbound_pbuf = p;
285
286 snmp_stats.inpkts++;
287
288 err = snmp_parse_inbound_frame(&request);
289 if (err == ERR_OK) {
290 err = snmp_prepare_outbound_frame(&request);
291 if (err == ERR_OK) {
292
293 if (request.error_status == SNMP_ERR_NOERROR) {
294 /* only process frame if we do not already have an error to return (e.g. all readonly) */
295 if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
296 err = snmp_process_get_request(&request);
297 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
298 err = snmp_process_getnext_request(&request);
299 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
300 err = snmp_process_getbulk_request(&request);
301 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
302 err = snmp_process_set_request(&request);
303 }
304 }
305 #if LWIP_SNMP_V3
306 else {
307 struct snmp_varbind vb;
308
309 vb.next = NULL;
310 vb.prev = NULL;
311 vb.type = SNMP_ASN1_TYPE_COUNTER32;
312 vb.value_len = sizeof(u32_t);
313
314 switch (request.error_status) {
315 case SNMP_ERR_AUTHORIZATIONERROR:
316 {
317 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
318 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
319 vb.value = &snmp_stats.wrongdigests;
320 }
321 break;
322 case SNMP_ERR_UNKNOWN_ENGINEID:
323 {
324 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
325 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
326 vb.value = &snmp_stats.unknownengineids;
327 }
328 break;
329 case SNMP_ERR_UNKNOWN_SECURITYNAME:
330 {
331 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
332 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
333 vb.value = &snmp_stats.unknownusernames;
334 }
335 break;
336 case SNMP_ERR_UNSUPPORTED_SECLEVEL:
337 {
338 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
339 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
340 vb.value = &snmp_stats.unsupportedseclevels;
341 }
342 break;
343 case SNMP_ERR_NOTINTIMEWINDOW:
344 {
345 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
346 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
347 vb.value = &snmp_stats.notintimewindows;
348 }
349 break;
350 case SNMP_ERR_DECRYIPTION_ERROR:
351 {
352 static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
353 snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
354 vb.value = &snmp_stats.decryptionerrors;
355 }
356 break;
357 default:
358 /* Unknown or unhandled error_status */
359 err = ERR_ARG;
360 }
361
362 if (err == ERR_OK) {
363 snmp_append_outbound_varbind(&(request.outbound_pbuf_stream), &vb);
364 request.error_status = SNMP_ERR_NOERROR;
365 }
366
367 request.request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_REPORT);
368 request.request_id = request.msg_id;
369 }
370 #endif
371
372 if (err == ERR_OK) {
373 err = snmp_complete_outbound_frame(&request);
374
375 if (err == ERR_OK) {
376 err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
377
378 if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)
379 && (request.error_status == SNMP_ERR_NOERROR)
380 && (snmp_write_callback != NULL)) {
381 /* raise write notification for all written objects */
382 snmp_execute_write_callbacks(&request);
383 }
384 }
385 }
386 }
387
388 if (request.outbound_pbuf != NULL) {
389 pbuf_free(request.outbound_pbuf);
390 }
391 }
392 }
393
394 static u8_t
snmp_msg_getnext_validate_node_inst(struct snmp_node_instance * node_instance,void * validate_arg)395 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg)
396 {
397 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
398 return SNMP_ERR_NOSUCHINSTANCE;
399 }
400
401 if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) {
402 /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
403 return SNMP_ERR_NOSUCHINSTANCE;
404 }
405
406 return SNMP_ERR_NOERROR;
407 }
408
409 static void
snmp_process_varbind(struct snmp_request * request,struct snmp_varbind * vb,u8_t get_next)410 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
411 {
412 err_t err;
413 struct snmp_node_instance node_instance;
414 memset(&node_instance, 0, sizeof(node_instance));
415
416 if (get_next) {
417 struct snmp_obj_id result_oid;
418 request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance);
419
420 if (request->error_status == SNMP_ERR_NOERROR) {
421 snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
422 }
423 } else {
424 request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
425
426 if (request->error_status == SNMP_ERR_NOERROR) {
427 /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
428 request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
429
430 if (request->error_status != SNMP_ERR_NOERROR) {
431 if (node_instance.release_instance != NULL) {
432 node_instance.release_instance(&node_instance);
433 }
434 }
435 }
436 }
437
438 if (request->error_status != SNMP_ERR_NOERROR) {
439 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
440 if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
441 /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
442 vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
443 vb->value_len = 0;
444
445 err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb);
446 if (err == ERR_OK) {
447 /* we stored the exception in varbind -> go on */
448 request->error_status = SNMP_ERR_NOERROR;
449 } else if (err == ERR_BUF) {
450 request->error_status = SNMP_ERR_TOOBIG;
451 } else {
452 request->error_status = SNMP_ERR_GENERROR;
453 }
454 }
455 } else {
456 /* according to RFC 1157/1905, all other errors only return genError */
457 request->error_status = SNMP_ERR_GENERROR;
458 }
459 } else {
460 s16_t len = node_instance.get_value(&node_instance, vb->value);
461 vb->type = node_instance.asn1_type;
462
463 if(len >= 0) {
464 vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */
465
466 LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
467 err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb);
468
469 if (err == ERR_BUF) {
470 request->error_status = SNMP_ERR_TOOBIG;
471 } else if (err != ERR_OK) {
472 request->error_status = SNMP_ERR_GENERROR;
473 }
474 } else {
475 request->error_status = SNMP_ERR_GENERROR;
476 }
477
478 if (node_instance.release_instance != NULL) {
479 node_instance.release_instance(&node_instance);
480 }
481 }
482 }
483
484
485 /**
486 * Service an internal or external event for SNMP GET.
487 *
488 * @param request points to the associated message process state
489 */
490 static err_t
snmp_process_get_request(struct snmp_request * request)491 snmp_process_get_request(struct snmp_request *request)
492 {
493 snmp_vb_enumerator_err_t err;
494 struct snmp_varbind vb;
495 vb.value = request->value_buffer;
496
497 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
498
499 while (request->error_status == SNMP_ERR_NOERROR) {
500 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
501 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
502 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
503 snmp_process_varbind(request, &vb, 0);
504 } else {
505 request->error_status = SNMP_ERR_GENERROR;
506 }
507 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
508 /* no more varbinds in request */
509 break;
510 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
511 /* malformed ASN.1, don't answer */
512 return ERR_ARG;
513 } else {
514 request->error_status = SNMP_ERR_GENERROR;
515 }
516 }
517
518 return ERR_OK;
519 }
520
521 /**
522 * Service an internal or external event for SNMP GET.
523 *
524 * @param request points to the associated message process state
525 */
526 static err_t
snmp_process_getnext_request(struct snmp_request * request)527 snmp_process_getnext_request(struct snmp_request *request)
528 {
529 snmp_vb_enumerator_err_t err;
530 struct snmp_varbind vb;
531 vb.value = request->value_buffer;
532
533 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
534
535 while (request->error_status == SNMP_ERR_NOERROR) {
536 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
537 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
538 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
539 snmp_process_varbind(request, &vb, 1);
540 } else {
541 request->error_status = SNMP_ERR_GENERROR;
542 }
543 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
544 /* no more varbinds in request */
545 break;
546 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
547 /* malformed ASN.1, don't answer */
548 return ERR_ARG;
549 } else {
550 request->error_status = SNMP_ERR_GENERROR;
551 }
552 }
553
554 return ERR_OK;
555 }
556
557 /**
558 * Service an internal or external event for SNMP GETBULKT.
559 *
560 * @param request points to the associated message process state
561 */
562 static err_t
snmp_process_getbulk_request(struct snmp_request * request)563 snmp_process_getbulk_request(struct snmp_request *request)
564 {
565 snmp_vb_enumerator_err_t err;
566 s32_t non_repeaters = request->non_repeaters;
567 s32_t repetitions;
568 u16_t repetition_offset = 0;
569 struct snmp_varbind_enumerator repetition_varbind_enumerator;
570 struct snmp_varbind vb;
571 vb.value = request->value_buffer;
572
573 if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) {
574 repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
575 } else {
576 repetitions = request->max_repetitions;
577 }
578
579 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
580
581 /* process non repeaters and first repetition */
582 while (request->error_status == SNMP_ERR_NOERROR) {
583 if (non_repeaters == 0) {
584 repetition_offset = request->outbound_pbuf_stream.offset;
585
586 if (repetitions == 0) {
587 /* do not resolve repeaters when repetitions is set to 0 */
588 break;
589 }
590 repetitions--;
591 }
592
593 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
594 if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
595 /* no more varbinds in request */
596 break;
597 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
598 /* malformed ASN.1, don't answer */
599 return ERR_ARG;
600 } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
601 request->error_status = SNMP_ERR_GENERROR;
602 } else {
603 snmp_process_varbind(request, &vb, 1);
604 non_repeaters--;
605 }
606 }
607
608 /* process repetitions > 1 */
609 while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
610
611 u8_t all_endofmibview = 1;
612
613 snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
614 repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
615
616 while (request->error_status == SNMP_ERR_NOERROR) {
617 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
618 err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
619 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
620 vb.value = request->value_buffer;
621 snmp_process_varbind(request, &vb, 1);
622
623 if (request->error_status != SNMP_ERR_NOERROR) {
624 /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
625 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
626 } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
627 all_endofmibview = 0;
628 }
629 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
630 /* no more varbinds in request */
631 break;
632 } else {
633 LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
634 request->error_status = SNMP_ERR_GENERROR;
635 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
636 }
637 }
638
639 if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
640 /* stop when all varbinds in a loop return EndOfMibView */
641 break;
642 }
643
644 repetitions--;
645 }
646
647 if (request->error_status == SNMP_ERR_TOOBIG) {
648 /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
649 request->error_status = SNMP_ERR_NOERROR;
650 }
651
652 return ERR_OK;
653 }
654
655 /**
656 * Service an internal or external event for SNMP SET.
657 *
658 * @param request points to the associated message process state
659 */
660 static err_t
snmp_process_set_request(struct snmp_request * request)661 snmp_process_set_request(struct snmp_request *request)
662 {
663 snmp_vb_enumerator_err_t err;
664 struct snmp_varbind vb;
665 vb.value = request->value_buffer;
666
667 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
668
669 /* perform set test on all objects */
670 while (request->error_status == SNMP_ERR_NOERROR) {
671 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
672 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
673 struct snmp_node_instance node_instance;
674 memset(&node_instance, 0, sizeof(node_instance));
675
676 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
677 if (request->error_status == SNMP_ERR_NOERROR) {
678 if (node_instance.asn1_type != vb.type) {
679 request->error_status = SNMP_ERR_WRONGTYPE;
680 } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
681 request->error_status = SNMP_ERR_NOTWRITABLE;
682 } else {
683 if (node_instance.set_test != NULL) {
684 request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
685 }
686 }
687
688 if (node_instance.release_instance != NULL) {
689 node_instance.release_instance(&node_instance);
690 }
691 }
692 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
693 /* no more varbinds in request */
694 break;
695 } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
696 request->error_status = SNMP_ERR_WRONGLENGTH;
697 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
698 /* malformed ASN.1, don't answer */
699 return ERR_ARG;
700 } else {
701 request->error_status = SNMP_ERR_GENERROR;
702 }
703 }
704
705 /* perform real set operation on all objects */
706 if (request->error_status == SNMP_ERR_NOERROR) {
707 snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
708 while (request->error_status == SNMP_ERR_NOERROR) {
709 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
710 if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
711 struct snmp_node_instance node_instance;
712 memset(&node_instance, 0, sizeof(node_instance));
713 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
714 if (request->error_status == SNMP_ERR_NOERROR) {
715 if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) {
716 if (request->inbound_varbind_enumerator.varbind_count == 1) {
717 request->error_status = SNMP_ERR_COMMITFAILED;
718 } else {
719 /* we cannot undo the set operations done so far */
720 request->error_status = SNMP_ERR_UNDOFAILED;
721 }
722 }
723
724 if (node_instance.release_instance != NULL) {
725 node_instance.release_instance(&node_instance);
726 }
727 }
728 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
729 /* no more varbinds in request */
730 break;
731 } else {
732 /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
733 request->error_status = SNMP_ERR_GENERROR;
734 }
735 }
736 }
737
738 return ERR_OK;
739 }
740
741 #define PARSE_EXEC(code, retValue) \
742 if ((code) != ERR_OK) { \
743 LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
744 snmp_stats.inasnparseerrs++; \
745 return retValue; \
746 }
747
748 #define PARSE_ASSERT(cond, retValue) \
749 if (!(cond)) { \
750 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
751 snmp_stats.inasnparseerrs++; \
752 return retValue; \
753 }
754
755 #define BUILD_EXEC(code, retValue) \
756 if ((code) != ERR_OK) { \
757 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
758 return retValue; \
759 }
760
761 #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG)
762 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG)
763
764 /**
765 * Checks and decodes incoming SNMP message header, logs header errors.
766 *
767 * @param request points to the current message request state return
768 * @return
769 * - ERR_OK SNMP header is sane and accepted
770 * - ERR_VAL SNMP header is either malformed or rejected
771 */
772 static err_t
snmp_parse_inbound_frame(struct snmp_request * request)773 snmp_parse_inbound_frame(struct snmp_request *request)
774 {
775 struct snmp_pbuf_stream pbuf_stream;
776 struct snmp_asn1_tlv tlv;
777 s32_t parent_tlv_value_len;
778 s32_t s32_value;
779 err_t err;
780 #if LWIP_SNMP_V3
781 snmpv3_auth_algo_t auth;
782 snmpv3_priv_algo_t priv;
783 #endif
784
785 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
786
787 /* decode main container consisting of version, community and PDU */
788 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
789 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
790 parent_tlv_value_len = tlv.value_len;
791
792 /* decode version */
793 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
794 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
795 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
796 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
797
798 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
799
800 if (((s32_value != SNMP_VERSION_1) &&
801 (s32_value != SNMP_VERSION_2c)
802 #if LWIP_SNMP_V3
803 && (s32_value != SNMP_VERSION_3)
804 #endif
805 )
806 #if LWIP_SNMP_CONFIGURE_VERSIONS
807 || (!snmp_version_enabled(s32_value))
808 #endif
809 )
810 {
811 /* unsupported SNMP version */
812 snmp_stats.inbadversions++;
813 return ERR_ARG;
814 }
815 request->version = (u8_t)s32_value;
816
817 #if LWIP_SNMP_V3
818 if (request->version == SNMP_VERSION_3) {
819 u16_t u16_value;
820 u16_t inbound_msgAuthenticationParameters_offset;
821
822 /* SNMPv3 doesn't use communities */
823 /* @todo: Differentiate read/write access */
824 strcpy((char*)request->community, snmp_community);
825 request->community_strlen = (u16_t)strlen(snmp_community);
826
827 /* RFC3414 globalData */
828 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
829 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
830 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
831 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
832
833 /* decode msgID */
834 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
835 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
836 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
837 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
838
839 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
840 request->msg_id = s32_value;
841
842 /* decode msgMaxSize */
843 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
844 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
845 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
846 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
847
848 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
849 request->msg_max_size = s32_value;
850
851 /* decode msgFlags */
852 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
853 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
854 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
855 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
856
857 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
858 request->msg_flags = (u8_t)s32_value;
859
860 /* decode msgSecurityModel */
861 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
862 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
863 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
864 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
865
866 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
867 request->msg_security_model = s32_value;
868
869 /* RFC3414 msgSecurityParameters
870 * The User-based Security Model defines the contents of the OCTET
871 * STRING as a SEQUENCE.
872 *
873 * We skip the protective dummy OCTET STRING header
874 * to access the SEQUENCE header.
875 */
876 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
877 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
878 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
879 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
880
881 /* msgSecurityParameters SEQUENCE header */
882 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
883 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
884 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
885 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
886
887 /* decode msgAuthoritativeEngineID */
888 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
889 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
890 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
891 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
892
893 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
894 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
895 request->msg_authoritative_engine_id_len = (u8_t)u16_value;
896
897 /* msgAuthoritativeEngineBoots */
898 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
899 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
900 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
901 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
902 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots));
903
904 /* msgAuthoritativeEngineTime */
905 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
906 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
907 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
908 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
909 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time));
910
911 /* msgUserName */
912 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
913 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
914 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
915 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
916
917 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
918 &u16_value, SNMP_V3_MAX_USER_LENGTH));
919 request->msg_user_name_len = (u8_t)u16_value;
920
921 /* msgAuthenticationParameters */
922 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
923 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
924 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
925 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
926 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
927 /* Remember position */
928 inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
929 LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
930 /* Read auth parameters */
931 /* IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); */
932 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
933 &u16_value, tlv.value_len));
934 request->msg_authentication_parameters_len = (u8_t)u16_value;
935
936 /* msgPrivacyParameters */
937 memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
938 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
939 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
940 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
941 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
942
943 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
944 &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
945 request->msg_privacy_parameters_len = (u8_t)u16_value;
946
947 /* validate securityParameters here (do this after decoding because we don't want to increase other counters for wrong frames)
948 * 1) securityParameters was correctly serialized if we reach here.
949 * 2) securityParameters are already cached.
950 * 3) if msgAuthoritativeEngineID is unknown, zero-length or too long:
951 b) https://tools.ietf.org/html/rfc3414#section-7
952 */
953 {
954 const char *eid;
955 u8_t eid_len;
956
957 snmpv3_get_engine_id(&eid, &eid_len);
958
959 if ((request->msg_authoritative_engine_id_len == 0) ||
960 (request->msg_authoritative_engine_id_len != eid_len) ||
961 (memcmp(eid, request->msg_authoritative_engine_id, eid_len) != 0)) {
962 snmp_stats.unknownengineids++;
963 request->msg_flags = 0; /* noauthnopriv */
964 request->error_status = SNMP_ERR_UNKNOWN_ENGINEID;
965 return ERR_OK;
966 }
967 }
968
969 /* 4) verify username */
970 if(snmpv3_get_user((char*)request->msg_user_name, &auth, NULL, &priv, NULL)) {
971 snmp_stats.unknownusernames++;
972 request->msg_flags = 0; /* noauthnopriv */
973 request->error_status = SNMP_ERR_UNKNOWN_SECURITYNAME;
974 return ERR_OK;
975 }
976
977 /* 5) verify security level */
978 switch(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)) {
979 case SNMP_V3_NOAUTHNOPRIV:
980 if ((auth != SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
981 /* Invalid security level for user */
982 snmp_stats.unsupportedseclevels++;
983 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
984 request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
985 return ERR_OK;
986 }
987 break;
988 #if LWIP_SNMP_V3_CRYPTO
989 case SNMP_V3_AUTHNOPRIV:
990 if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
991 /* Invalid security level for user */
992 snmp_stats.unsupportedseclevels++;
993 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
994 request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
995 return ERR_OK;
996 }
997 break;
998 case SNMP_V3_AUTHPRIV:
999 if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv == SNMP_V3_PRIV_ALGO_INVAL)) {
1000 /* Invalid security level for user */
1001 snmp_stats.unsupportedseclevels++;
1002 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1003 request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
1004 return ERR_OK;
1005 }
1006 break;
1007 #endif
1008 default:
1009 snmp_stats.unsupportedseclevels++;
1010 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1011 request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
1012 return ERR_OK;
1013 }
1014
1015 /* 6) if securitylevel specifies authentication, authenticate message. */
1016 #if LWIP_SNMP_V3_CRYPTO
1017 if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
1018 const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
1019 u8_t key[20];
1020 u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
1021 struct snmp_pbuf_stream auth_stream;
1022
1023 if (request->msg_authentication_parameters_len > SNMP_V3_MAX_AUTH_PARAM_LENGTH) {
1024 snmp_stats.wrongdigests++;
1025 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1026 request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
1027 return ERR_OK;
1028 }
1029
1030 /* Rewind stream */
1031 IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
1032 IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&auth_stream, inbound_msgAuthenticationParameters_offset));
1033 /* Set auth parameters to zero for verification */
1034 IF_PARSE_EXEC(snmp_asn1_enc_raw(&auth_stream, zero_arr, request->msg_authentication_parameters_len));
1035
1036 /* Verify authentication */
1037 IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
1038
1039 IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &auth, key, NULL, NULL));
1040 IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, auth, hmac));
1041
1042 if(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) {
1043 snmp_stats.wrongdigests++;
1044 request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1045 request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
1046 return ERR_OK;
1047 }
1048
1049 /* 7) if securitylevel specifies authentication, verify engineboots, enginetime and lastenginetime */
1050 {
1051 s32_t boots = snmpv3_get_engine_boots_internal();
1052 if ((request->msg_authoritative_engine_boots != boots) || (boots == 2147483647UL)) {
1053 snmp_stats.notintimewindows++;
1054 request->msg_flags = SNMP_V3_AUTHNOPRIV;
1055 request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1056 return ERR_OK;
1057 }
1058 }
1059 {
1060 s32_t time = snmpv3_get_engine_time_internal();
1061 if (request->msg_authoritative_engine_time > time) {
1062 snmp_stats.notintimewindows++;
1063 request->msg_flags = SNMP_V3_AUTHNOPRIV;
1064 request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1065 return ERR_OK;
1066 }
1067 else if (time > 150) {
1068 if (request->msg_authoritative_engine_time < time - 150) {
1069 snmp_stats.notintimewindows++;
1070 request->msg_flags = SNMP_V3_AUTHNOPRIV;
1071 request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1072 return ERR_OK;
1073 }
1074 }
1075 }
1076 }
1077 #endif
1078
1079 /* 8) if securitylevel specifies privacy, decrypt message. */
1080 #if LWIP_SNMP_V3_CRYPTO
1081 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1082 /* Decrypt message */
1083
1084 u8_t key[20];
1085
1086 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1087 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1088 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
1089 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1090
1091 IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &priv, key));
1092 if(snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
1093 request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
1094 request->msg_authoritative_engine_time, priv, SNMP_V3_PRIV_MODE_DECRYPT) != ERR_OK) {
1095 snmp_stats.decryptionerrors++;
1096 request->msg_flags = SNMP_V3_AUTHNOPRIV;
1097 request->error_status = SNMP_ERR_DECRYIPTION_ERROR;
1098 return ERR_OK;
1099 }
1100 }
1101 #endif
1102 /* 9) calculate max size of scoped pdu?
1103 * 10) securityname for user is retrieved from usertable?
1104 * 11) security data is cached?
1105 * 12)
1106 */
1107
1108 /* Scoped PDU
1109 * Encryption context
1110 */
1111 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1112 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
1113 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
1114 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1115
1116 /* contextEngineID */
1117 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1118 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1119 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1120 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1121
1122 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
1123 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
1124 request->context_engine_id_len = (u8_t)u16_value;
1125 /* TODO: do we need to verify this contextengineid too? */
1126
1127 /* contextName */
1128 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1129 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1130 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1131 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1132
1133 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name,
1134 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
1135 request->context_name_len = (u8_t)u16_value;
1136 /* TODO: do we need to verify this contextname too? */
1137 } else
1138 #endif
1139 {
1140 /* decode community */
1141 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1142 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1143 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1144 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1145
1146 err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
1147 if (err == ERR_MEM) {
1148 /* community string does not fit in our buffer -> its too long -> its invalid */
1149 request->community_strlen = 0;
1150 snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
1151 } else {
1152 IF_PARSE_ASSERT(err == ERR_OK);
1153 }
1154 /* add zero terminator */
1155 request->community[request->community_strlen] = 0;
1156 }
1157
1158 /* decode PDU type (next container level) */
1159 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1160 IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length);
1161 request->inbound_padding_len = pbuf_stream.length - tlv.value_len;
1162 parent_tlv_value_len = tlv.value_len;
1163
1164 /* validate PDU type */
1165 switch(tlv.type) {
1166 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
1167 /* GetRequest PDU */
1168 snmp_stats.ingetrequests++;
1169 break;
1170 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
1171 /* GetNextRequest PDU */
1172 snmp_stats.ingetnexts++;
1173 break;
1174 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
1175 /* GetBulkRequest PDU */
1176 if (request->version < SNMP_VERSION_2c) {
1177 /* RFC2089: invalid, drop packet */
1178 return ERR_ARG;
1179 }
1180 break;
1181 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
1182 /* SetRequest PDU */
1183 snmp_stats.insetrequests++;
1184 break;
1185 default:
1186 /* unsupported input PDU for this agent (no parse error) */
1187 LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
1188 return ERR_ARG;
1189 break;
1190 }
1191 request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
1192 request->request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP);
1193
1194 /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
1195 if (request->community_strlen == 0) {
1196 /* community string was too long or really empty*/
1197 snmp_stats.inbadcommunitynames++;
1198 snmp_authfail_trap();
1199 return ERR_ARG;
1200 } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1201 if (snmp_community_write[0] == 0) {
1202 /* our write community is empty, that means all our objects are readonly */
1203 request->error_status = SNMP_ERR_NOTWRITABLE;
1204 request->error_index = 1;
1205 } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
1206 /* community name does not match */
1207 snmp_stats.inbadcommunitynames++;
1208 snmp_authfail_trap();
1209 return ERR_ARG;
1210 }
1211 } else {
1212 if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
1213 /* community name does not match */
1214 snmp_stats.inbadcommunitynames++;
1215 snmp_authfail_trap();
1216 return ERR_ARG;
1217 }
1218 }
1219
1220 /* decode request ID */
1221 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1222 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1223 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1224 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1225
1226 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
1227
1228 /* decode error status / non-repeaters */
1229 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1230 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1231 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1232 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1233
1234 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
1235 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
1236 if (request->non_repeaters < 0) {
1237 /* RFC 1905, 4.2.3 */
1238 request->non_repeaters = 0;
1239 }
1240 } else {
1241 /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
1242 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
1243 IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
1244 }
1245
1246 /* decode error index / max-repetitions */
1247 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1248 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1249 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1250 IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1251
1252 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
1253 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
1254 if (request->max_repetitions < 0) {
1255 /* RFC 1905, 4.2.3 */
1256 request->max_repetitions = 0;
1257 }
1258 } else {
1259 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
1260 IF_PARSE_ASSERT(s32_value == 0);
1261 }
1262
1263 /* decode varbind-list type (next container level) */
1264 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1265 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length));
1266
1267 request->inbound_varbind_offset = pbuf_stream.offset;
1268 request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len;
1269 snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1270
1271 return ERR_OK;
1272 }
1273
1274 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
1275
1276 static err_t
snmp_prepare_outbound_frame(struct snmp_request * request)1277 snmp_prepare_outbound_frame(struct snmp_request *request)
1278 {
1279 struct snmp_asn1_tlv tlv;
1280 struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream);
1281
1282 /* try allocating pbuf(s) for maximum response size */
1283 request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
1284 if (request->outbound_pbuf == NULL) {
1285 return ERR_MEM;
1286 }
1287
1288 snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
1289
1290 /* 'Message' sequence */
1291 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1292 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1293
1294 /* version */
1295 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1296 snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
1297 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1298 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
1299
1300 #if LWIP_SNMP_V3
1301 if (request->version < SNMP_VERSION_3) {
1302 #endif
1303 /* community */
1304 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
1305 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1306 OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
1307 #if LWIP_SNMP_V3
1308 } else {
1309 const char* id;
1310
1311 /* globalData */
1312 request->outbound_msg_global_data_offset = pbuf_stream->offset;
1313 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1314 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1315
1316 /* msgID */
1317 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1318 snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len);
1319 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1320 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id));
1321
1322 /* msgMaxSize */
1323 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1324 snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len);
1325 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1326 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size));
1327
1328 /* msgFlags */
1329 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1);
1330 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1331 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1));
1332
1333 /* msgSecurityModel */
1334 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1335 snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len);
1336 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1337 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model));
1338
1339 /* end of msgGlobalData */
1340 request->outbound_msg_global_data_end = pbuf_stream->offset;
1341
1342 /* msgSecurityParameters */
1343 request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset;
1344 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0);
1345 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1346
1347 request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset;
1348 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1349 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1350
1351 /* msgAuthoritativeEngineID */
1352 snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
1353 MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
1354 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
1355 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1356 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
1357
1358 request->msg_authoritative_engine_time = snmpv3_get_engine_time();
1359 request->msg_authoritative_engine_boots = snmpv3_get_engine_boots();
1360
1361 /* msgAuthoritativeEngineBoots */
1362 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1363 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len);
1364 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1365 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots));
1366
1367 /* msgAuthoritativeEngineTime */
1368 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1369 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len);
1370 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1371 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time));
1372
1373 /* msgUserName */
1374 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len);
1375 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1376 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
1377
1378 #if LWIP_SNMP_V3_CRYPTO
1379 /* msgAuthenticationParameters */
1380 if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
1381 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1382 request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset;
1383 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1384 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1385 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1386 } else
1387 #endif
1388 {
1389 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1390 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1391 }
1392
1393 #if LWIP_SNMP_V3_CRYPTO
1394 /* msgPrivacyParameters */
1395 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1396 snmpv3_build_priv_param(request->msg_privacy_parameters);
1397
1398 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
1399 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1400 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
1401 } else
1402 #endif
1403 {
1404 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1405 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1406 }
1407
1408 /* End of msgSecurityParameters, so we can calculate the length of this sequence later */
1409 request->outbound_msg_security_parameters_end = pbuf_stream->offset;
1410
1411 #if LWIP_SNMP_V3_CRYPTO
1412 /* For encryption we have to encapsulate the payload in an octet string */
1413 if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1414 request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
1415 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0);
1416 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1417 }
1418 #endif
1419 /* Scoped PDU
1420 * Encryption context
1421 */
1422 request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset;
1423 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1424 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1425
1426 /* contextEngineID */
1427 snmpv3_get_engine_id(&id, &request->context_engine_id_len);
1428 MEMCPY(request->context_engine_id, id, request->context_engine_id_len);
1429 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
1430 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1431 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
1432
1433 /* contextName */
1434 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len);
1435 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1436 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len));
1437 }
1438 #endif
1439
1440 /* 'PDU' sequence */
1441 request->outbound_pdu_offset = pbuf_stream->offset;
1442 SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3, 0);
1443 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1444
1445 /* request ID */
1446 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1447 snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
1448 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1449 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
1450
1451 /* error status */
1452 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1453 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1454 request->outbound_error_status_offset = pbuf_stream->offset;
1455 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1456
1457 /* error index */
1458 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1459 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1460 request->outbound_error_index_offset = pbuf_stream->offset;
1461 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1462
1463 /* 'VarBindList' sequence */
1464 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1465 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1466
1467 request->outbound_varbind_offset = pbuf_stream->offset;
1468
1469 return ERR_OK;
1470 }
1471
1472 /** Calculate the length of a varbind list */
1473 err_t
snmp_varbind_length(struct snmp_varbind * varbind,struct snmp_varbind_len * len)1474 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
1475 {
1476 /* calculate required lengths */
1477 snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len);
1478 snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len);
1479
1480 if (varbind->value_len == 0) {
1481 len->value_value_len = 0;
1482 } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1483 len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
1484 } else {
1485 switch (varbind->type) {
1486 case SNMP_ASN1_TYPE_INTEGER:
1487 if (varbind->value_len != sizeof (s32_t)) {
1488 return ERR_VAL;
1489 }
1490 snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len);
1491 break;
1492 case SNMP_ASN1_TYPE_COUNTER:
1493 case SNMP_ASN1_TYPE_GAUGE:
1494 case SNMP_ASN1_TYPE_TIMETICKS:
1495 if (varbind->value_len != sizeof (u32_t)) {
1496 return ERR_VAL;
1497 }
1498 snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len);
1499 break;
1500 case SNMP_ASN1_TYPE_OCTET_STRING:
1501 case SNMP_ASN1_TYPE_IPADDR:
1502 case SNMP_ASN1_TYPE_OPAQUE:
1503 len->value_value_len = varbind->value_len;
1504 break;
1505 case SNMP_ASN1_TYPE_NULL:
1506 if (varbind->value_len != 0) {
1507 return ERR_VAL;
1508 }
1509 len->value_value_len = 0;
1510 break;
1511 case SNMP_ASN1_TYPE_OBJECT_ID:
1512 if ((varbind->value_len & 0x03) != 0) {
1513 return ERR_VAL;
1514 }
1515 snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len);
1516 break;
1517 case SNMP_ASN1_TYPE_COUNTER64:
1518 if (varbind->value_len != (2 * sizeof (u32_t))) {
1519 return ERR_VAL;
1520 }
1521 snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len);
1522 break;
1523 default:
1524 /* unsupported type */
1525 return ERR_VAL;
1526 }
1527 }
1528 snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len);
1529
1530 len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len;
1531 snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len);
1532
1533 return ERR_OK;
1534 }
1535
1536 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
1537
1538 err_t
snmp_append_outbound_varbind(struct snmp_pbuf_stream * pbuf_stream,struct snmp_varbind * varbind)1539 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind)
1540 {
1541 struct snmp_asn1_tlv tlv;
1542 struct snmp_varbind_len len;
1543 err_t err;
1544
1545 err = snmp_varbind_length(varbind, &len);
1546
1547 if (err != ERR_OK) {
1548 return err;
1549 }
1550
1551 /* check length already before adding first data because in case of GetBulk,
1552 * data added so far is returned and therefore no partial data shall be added
1553 */
1554 if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) {
1555 return ERR_BUF;
1556 }
1557
1558 /* 'VarBind' sequence */
1559 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len);
1560 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1561
1562 /* VarBind OID */
1563 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len);
1564 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1565 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len));
1566
1567 /* VarBind value */
1568 SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len);
1569 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1570
1571 if (len.value_value_len > 0) {
1572 if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1573 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1574 } else {
1575 switch (varbind->type) {
1576 case SNMP_ASN1_TYPE_INTEGER:
1577 OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value)));
1578 break;
1579 case SNMP_ASN1_TYPE_COUNTER:
1580 case SNMP_ASN1_TYPE_GAUGE:
1581 case SNMP_ASN1_TYPE_TIMETICKS:
1582 OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value)));
1583 break;
1584 case SNMP_ASN1_TYPE_OCTET_STRING:
1585 case SNMP_ASN1_TYPE_IPADDR:
1586 case SNMP_ASN1_TYPE_OPAQUE:
1587 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1588 len.value_value_len = varbind->value_len;
1589 break;
1590 case SNMP_ASN1_TYPE_OBJECT_ID:
1591 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t)));
1592 break;
1593 case SNMP_ASN1_TYPE_COUNTER64:
1594 OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value));
1595 break;
1596 default:
1597 LWIP_ASSERT("Unknown variable type", 0);
1598 break;
1599 }
1600 }
1601 }
1602
1603 return ERR_OK;
1604 }
1605
1606 static err_t
snmp_complete_outbound_frame(struct snmp_request * request)1607 snmp_complete_outbound_frame(struct snmp_request *request)
1608 {
1609 struct snmp_asn1_tlv tlv;
1610 u16_t frame_size;
1611 u8_t outbound_padding = 0;
1612
1613 if (request->version == SNMP_VERSION_1) {
1614 if (request->error_status != SNMP_ERR_NOERROR) {
1615 /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
1616 switch (request->error_status) {
1617 /* mapping of implementation specific "virtual" error codes
1618 * (during processing of frame we already stored them in error_status field,
1619 * so no need to check all varbinds here for those exceptions as suggested by RFC) */
1620 case SNMP_ERR_NOSUCHINSTANCE:
1621 case SNMP_ERR_NOSUCHOBJECT:
1622 case SNMP_ERR_ENDOFMIBVIEW:
1623 request->error_status = SNMP_ERR_NOSUCHNAME;
1624 break;
1625 /* mapping according to RFC */
1626 case SNMP_ERR_WRONGVALUE:
1627 case SNMP_ERR_WRONGENCODING:
1628 case SNMP_ERR_WRONGTYPE:
1629 case SNMP_ERR_WRONGLENGTH:
1630 case SNMP_ERR_INCONSISTENTVALUE:
1631 request->error_status = SNMP_ERR_BADVALUE;
1632 break;
1633 case SNMP_ERR_NOACCESS:
1634 case SNMP_ERR_NOTWRITABLE:
1635 case SNMP_ERR_NOCREATION:
1636 case SNMP_ERR_INCONSISTENTNAME:
1637 case SNMP_ERR_AUTHORIZATIONERROR:
1638 request->error_status = SNMP_ERR_NOSUCHNAME;
1639 break;
1640 case SNMP_ERR_RESOURCEUNAVAILABLE:
1641 case SNMP_ERR_COMMITFAILED:
1642 case SNMP_ERR_UNDOFAILED:
1643 default:
1644 request->error_status = SNMP_ERR_GENERROR;
1645 break;
1646 }
1647 }
1648 } else {
1649 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1650 /* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */
1651 switch (request->error_status) {
1652 case SNMP_ERR_NOSUCHINSTANCE:
1653 case SNMP_ERR_NOSUCHOBJECT:
1654 case SNMP_ERR_ENDOFMIBVIEW:
1655 request->error_status = SNMP_ERR_NOTWRITABLE;
1656 break;
1657 default:
1658 break;
1659 }
1660 }
1661
1662 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
1663 /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
1664 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
1665 return ERR_ARG;
1666 }
1667 }
1668
1669 if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
1670 /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
1671 struct snmp_pbuf_stream inbound_stream;
1672 OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
1673 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) );
1674 snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0);
1675 }
1676
1677 frame_size = request->outbound_pbuf_stream.offset;
1678
1679 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1680 /* Calculate padding for encryption */
1681 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1682 u8_t i;
1683 outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07;
1684 for (i = 0; i < outbound_padding; i++) {
1685 snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
1686 }
1687 }
1688 #endif
1689
1690 /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
1691 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1692 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
1693 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1694
1695 #if LWIP_SNMP_V3
1696 if (request->version == SNMP_VERSION_3) {
1697 /* complete missing length in 'globalData' sequence */
1698 /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1699 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end
1700 - request->outbound_msg_global_data_offset - 1 - 1);
1701 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset));
1702 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1703
1704 /* complete missing length in 'msgSecurityParameters' sequence */
1705 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end
1706 - request->outbound_msg_security_parameters_str_offset - 1 - 1);
1707 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset));
1708 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1709
1710 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end
1711 - request->outbound_msg_security_parameters_seq_offset - 1 - 1);
1712 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset));
1713 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1714
1715 /* complete missing length in scoped PDU sequence */
1716 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3);
1717 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset));
1718 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1719 }
1720 #endif
1721
1722 /* complete missing length in 'PDU' sequence */
1723 SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3,
1724 frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1725 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
1726 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1727
1728 /* process and encode final error status */
1729 if (request->error_status != 0) {
1730 u16_t len;
1731 snmp_asn1_enc_s32t_cnt(request->error_status, &len);
1732 if (len != 1) {
1733 /* error, we only reserved one byte for it */
1734 return ERR_ARG;
1735 }
1736 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
1737 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
1738
1739 /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
1740 switch (request->error_status) {
1741 case SNMP_ERR_TOOBIG:
1742 snmp_stats.outtoobigs++;
1743 break;
1744 case SNMP_ERR_NOSUCHNAME:
1745 snmp_stats.outnosuchnames++;
1746 break;
1747 case SNMP_ERR_BADVALUE:
1748 snmp_stats.outbadvalues++;
1749 break;
1750 case SNMP_ERR_GENERROR:
1751 default:
1752 snmp_stats.outgenerrs++;
1753 break;
1754 }
1755
1756 if (request->error_status == SNMP_ERR_TOOBIG) {
1757 request->error_index = 0; /* defined by RFC 1157 */
1758 } else if (request->error_index == 0) {
1759 /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
1760 request->error_index = request->inbound_varbind_enumerator.varbind_count;
1761 }
1762 } else {
1763 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1764 snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
1765 } else {
1766 snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
1767 }
1768 }
1769
1770 /* encode final error index*/
1771 if (request->error_index != 0) {
1772 u16_t len;
1773 snmp_asn1_enc_s32t_cnt(request->error_index, &len);
1774 if (len != 1) {
1775 /* error, we only reserved one byte for it */
1776 return ERR_VAL;
1777 }
1778 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
1779 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
1780 }
1781
1782 /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
1783 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
1784 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1785 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1786
1787 /* Authenticate response */
1788 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1789 /* Encrypt response */
1790 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1791 u8_t key[20];
1792 snmpv3_priv_algo_t algo;
1793
1794 /* complete missing length in PDU sequence */
1795 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1796 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset));
1797 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding
1798 - request->outbound_scoped_pdu_string_offset - 1 - 3);
1799 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1800
1801 OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key));
1802
1803 OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
1804 request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
1805 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT));
1806 }
1807
1808 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) {
1809 u8_t key[20];
1810 snmpv3_auth_algo_t algo;
1811 u8_t hmac[20];
1812
1813 OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL));
1814 OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
1815 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1816 OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
1817
1818 MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1819 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
1820 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1821 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
1822 request->outbound_msg_authentication_parameters_offset));
1823
1824 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1825 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv));
1826 OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream,
1827 request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1828 }
1829 #endif
1830
1831 pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding);
1832
1833 snmp_stats.outgetresponses++;
1834 snmp_stats.outpkts++;
1835
1836 return ERR_OK;
1837 }
1838
1839 static void
snmp_execute_write_callbacks(struct snmp_request * request)1840 snmp_execute_write_callbacks(struct snmp_request *request)
1841 {
1842 struct snmp_varbind_enumerator inbound_varbind_enumerator;
1843 struct snmp_varbind vb;
1844
1845 snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1846 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
1847
1848 while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) {
1849 snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
1850 }
1851 }
1852
1853
1854 /* ----------------------------------------------------------------------- */
1855 /* VarBind enumerator methods */
1856 /* ----------------------------------------------------------------------- */
1857
1858 void
snmp_vb_enumerator_init(struct snmp_varbind_enumerator * enumerator,struct pbuf * p,u16_t offset,u16_t length)1859 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length)
1860 {
1861 snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
1862 enumerator->varbind_count = 0;
1863 }
1864
1865 #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1866 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1867
1868 snmp_vb_enumerator_err_t
snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator * enumerator,struct snmp_varbind * varbind)1869 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
1870 {
1871 struct snmp_asn1_tlv tlv;
1872 u16_t varbind_len;
1873 err_t err;
1874
1875 if (enumerator->pbuf_stream.length == 0)
1876 {
1877 return SNMP_VB_ENUMERATOR_ERR_EOVB;
1878 }
1879 enumerator->varbind_count++;
1880
1881 /* decode varbind itself (parent container of a varbind) */
1882 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1883 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
1884 varbind_len = tlv.value_len;
1885
1886 /* decode varbind name (object id) */
1887 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1888 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
1889
1890 VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
1891 varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1892
1893 /* decode varbind value (object id) */
1894 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1895 VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
1896 varbind->type = tlv.type;
1897
1898 /* shall the value be decoded ? */
1899 if (varbind->value != NULL) {
1900 switch (varbind->type) {
1901 case SNMP_ASN1_TYPE_INTEGER:
1902 VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
1903 varbind->value_len = sizeof(s32_t*);
1904 break;
1905 case SNMP_ASN1_TYPE_COUNTER:
1906 case SNMP_ASN1_TYPE_GAUGE:
1907 case SNMP_ASN1_TYPE_TIMETICKS:
1908 VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1909 varbind->value_len = sizeof(u32_t*);
1910 break;
1911 case SNMP_ASN1_TYPE_OCTET_STRING:
1912 case SNMP_ASN1_TYPE_OPAQUE:
1913 err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
1914 if (err == ERR_MEM) {
1915 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1916 }
1917 VB_PARSE_ASSERT(err == ERR_OK);
1918 break;
1919 case SNMP_ASN1_TYPE_NULL:
1920 varbind->value_len = 0;
1921 break;
1922 case SNMP_ASN1_TYPE_OBJECT_ID:
1923 /* misuse tlv.length_len as OID_length transporter */
1924 err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
1925 if (err == ERR_MEM) {
1926 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1927 }
1928 VB_PARSE_ASSERT(err == ERR_OK);
1929 varbind->value_len = tlv.length_len * sizeof(u32_t);
1930 break;
1931 case SNMP_ASN1_TYPE_IPADDR:
1932 if (tlv.value_len == 4) {
1933 /* must be exactly 4 octets! */
1934 VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
1935 } else {
1936 VB_PARSE_ASSERT(0);
1937 }
1938 break;
1939 case SNMP_ASN1_TYPE_COUNTER64:
1940 VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1941 varbind->value_len = 2 * sizeof(u32_t*);
1942 break;
1943 default:
1944 VB_PARSE_ASSERT(0);
1945 break;
1946 }
1947 } else {
1948 snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
1949 varbind->value_len = tlv.value_len;
1950 }
1951
1952 return SNMP_VB_ENUMERATOR_ERR_OK;
1953 }
1954
1955 #endif /* LWIP_SNMP */
1956