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