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