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