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