]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/mp_v3.cpp
Fix build on osx.
[ssmd.git] / 3rdparty / snmp++ / src / mp_v3.cpp
1 /*_############################################################################
2   _## 
3   _##  mp_v3.cpp  
4   _##
5   _##  SNMP++v3.2.25
6   _##  -----------------------------------------------
7   _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
8   _##
9   _##  This software is based on SNMP++2.6 from Hewlett Packard:
10   _##  
11   _##    Copyright (c) 1996
12   _##    Hewlett-Packard Company
13   _##  
14   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15   _##  Permission to use, copy, modify, distribute and/or sell this software 
16   _##  and/or its documentation is hereby granted without fee. User agrees 
17   _##  to display the above copyright notice and this license notice in all 
18   _##  copies of the software and any documentation of the software. User 
19   _##  agrees to assume all liability for the use of the software; 
20   _##  Hewlett-Packard and Jochen Katz make no representations about the 
21   _##  suitability of this software for any purpose. It is provided 
22   _##  "AS-IS" without warranty of any kind, either express or implied. User 
23   _##  hereby grants a royalty-free license to any and all derivatives based
24   _##  upon this software code base. 
25   _##  
26   _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
27   _##  
28   _##########################################################################*/
29 char mp_v3_cpp_version[]="@(#) SNMP++ $Id: mp_v3.cpp 1686 2009-11-24 13:47:44Z katz $";
30
31 #include <stdlib.h>
32
33 #include "snmp_pp/config_snmp_pp.h"
34
35 #ifdef _SNMPv3
36 #include "snmp_pp/v3.h"
37 #include "snmp_pp/mp_v3.h"
38 #include "snmp_pp/usm_v3.h"
39 #include "snmp_pp/notifyqueue.h"
40 #include "snmp_pp/snmpmsg.h"
41 #include "snmp_pp/uxsnmp.h"
42 #include "snmp_pp/eventlistholder.h"
43 #include "snmp_pp/asn1.h"
44 #include "snmp_pp/vb.h"
45 #include "snmp_pp/log.h"
46
47 #ifdef SNMP_PP_NAMESPACE
48 namespace Snmp_pp {
49 #endif
50
51 #define MAX_MPMSGID 2147483647
52
53 #define CACHE_LOCAL_REQ true
54 #define CACHE_REMOTE_REQ false
55
56 v3MP *v3MP::I = 0;
57
58 // Use locking on access methods in an multithreaded environment.
59 #ifdef _THREADS
60 #define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(lock)
61 #define BEGIN_REENTRANT_CODE_BLOCK_CONST  \
62           SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, &lock)))
63 #else
64 #define BEGIN_REENTRANT_CODE_BLOCK
65 #define BEGIN_REENTRANT_CODE_BLOCK_CONST
66 #endif
67
68 // ========================[ Engine id table ]=============================
69
70 // Construct engine id table
71 v3MP::EngineIdTable::EngineIdTable(int initial_size)
72 {
73   if (initial_size < 1)
74     initial_size = 10;
75
76   if (!initialize_table(initial_size))
77   {
78     LOG_BEGIN(ERROR_LOG | 0);
79     LOG("v3MP::EngineIdTable: Error creating empty table.");
80     LOG_END;
81   }
82 }
83
84 // Destruct enigne id table
85 v3MP::EngineIdTable::~EngineIdTable()
86 {
87   if (table)
88     delete [] table;
89   table = 0;
90 }
91
92 // Add an entry to the table.
93 int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
94                                    const OctetStr &host, int port)
95 {
96   if (!table)
97     return SNMPv3_MP_NOT_INITIALIZED;
98
99   LOG_BEGIN(INFO_LOG | 9);
100   LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
101   LOG(engine_id.get_printable());
102   LOG(host.get_printable());
103   LOG(port);
104   LOG_END;
105
106   BEGIN_REENTRANT_CODE_BLOCK;
107
108   for (int i = 0; i < entries; i++)
109     if (((table[i].port == port) &&
110          (table[i].host == host)) ||
111         (table[i].engine_id == engine_id))
112     {
113       LOG_BEGIN(INFO_LOG | 2);
114       LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
115       LOG(table[i].engine_id.get_printable());
116       LOG(table[i].host.get_printable());
117       LOG(table[i].port);
118       LOG(engine_id.get_printable());
119       LOG(host.get_printable());
120       LOG(port);
121       LOG_END;
122
123       table[i].engine_id = engine_id;
124       table[i].host = host;
125       table[i].port = port;
126
127       return SNMPv3_MP_OK;         // host is in table
128     }
129
130   table[entries].engine_id = engine_id;
131   table[entries].host = host;
132   table[entries].port = port;
133
134   entries++;
135   if (entries == max_entries)
136   {
137     // resize Table
138     struct Entry_T *tmp;
139     tmp = new struct Entry_T[2 * max_entries];
140     if (!tmp)
141     {
142       entries--;
143       return SNMPv3_MP_ERROR;
144     }
145     for (int i = 0; i < entries; i++)
146       tmp[i] = table[i];
147
148     delete [] table;
149     table = tmp;
150     max_entries *= 2;
151   }
152
153   return SNMPv3_MP_OK;
154 }
155
156 // Get the engine_id of the SNMP entity at the given host/port.
157 int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
158                                    const OctetStr &hostport) const
159 {
160   int port;
161   char host[MAX_HOST_NAME_LENGTH + 1];
162   char *ptr;
163
164   /* Check length */
165   if (hostport.len() > MAX_HOST_NAME_LENGTH)
166     return SNMPv3_MP_ERROR;
167
168   /* split up port from hostport */
169   strcpy(host, hostport.get_printable());
170
171   ptr = strstr((char*)host,"/");
172   if (!ptr)
173     return SNMPv3_MP_ERROR;
174
175   *ptr = '\0';
176   port = atol(ptr + 1);
177
178   /* Check for IPv6 address with [] */
179   if (host[0] == '[')
180   {
181     if (*(ptr -1) == ']')
182     {
183       *(ptr-1) = '\0';
184       return get_entry(engine_id, &(host[1]), port);
185     }
186     else
187       return SNMPv3_MP_ERROR;
188   }
189   return get_entry(engine_id, host, port);
190 }
191
192 // Get the engineID of the SNMP entity at the given host/port.
193 int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
194                                    const OctetStr &host, int port) const
195 {
196   if (!table)
197     return SNMPv3_MP_NOT_INITIALIZED;
198
199   BEGIN_REENTRANT_CODE_BLOCK_CONST;
200
201   int i, found = 0;
202
203   for (i = 0; i < entries; i++)
204     if ((table[i].port == port) &&
205         (table[i].host == host))
206     {
207       found=1;
208       break;
209     }
210   if (!found)
211   {
212     LOG_BEGIN(INFO_LOG | 4);
213     LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
214     LOG(host.get_printable());
215     LOG(port);
216     LOG_END;
217
218     return SNMPv3_MP_ERROR;
219   }
220
221   engine_id = table[i].engine_id;
222
223   return SNMPv3_MP_OK;
224 }
225
226 // Remove all entries from the engine id table.
227 int v3MP::EngineIdTable::reset()
228 {
229   if (!table)
230     return SNMPv3_MP_NOT_INITIALIZED;
231
232   LOG_BEGIN(INFO_LOG | 1);
233   LOG("v3MP::EngineIdTable: Resetting table.");
234   LOG_END;
235
236   BEGIN_REENTRANT_CODE_BLOCK;
237
238   entries = 0;
239
240   return SNMPv3_MP_OK;
241 }
242
243 // Remove the given engine id from the table.
244 int v3MP::EngineIdTable::delete_entry(const OctetStr &engine_id)
245 {
246   if (!table)
247     return SNMPv3_MP_NOT_INITIALIZED;
248
249   int i, found = 0;
250
251   BEGIN_REENTRANT_CODE_BLOCK;
252
253   for (i = 0; i < entries; i++)
254     if (table[i].engine_id == engine_id)
255     {
256       found=1;
257       break;
258     }
259   if (!found)
260   {
261     LOG_BEGIN(WARNING_LOG | 4);
262     LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (engine id)");
263     LOG(engine_id.get_printable());
264     LOG_END;
265
266     return SNMPv3_MP_ERROR;
267   }
268
269   /* i is the entry to remove */
270   if (i != entries - 1)
271     table[i] = table[entries-1];
272
273   entries--;
274
275   return SNMPv3_MP_OK;
276 }
277
278 // Remove the entry for the given address/port from the table.
279 int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
280 {
281   if (!table)
282     return SNMPv3_MP_NOT_INITIALIZED;
283
284   int i, found = 0;
285
286   BEGIN_REENTRANT_CODE_BLOCK;
287
288   for (i = 0; i < entries; i++)
289     if ((table[i].port == port) &&
290         (table[i].host == host))
291     {
292       found=1;
293       break;
294     }
295   if (!found)
296   {
297     LOG_BEGIN(WARNING_LOG | 4);
298     LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
299     LOG(host.get_printable());
300     LOG(port);
301     LOG_END;
302
303     return SNMPv3_MP_ERROR;
304   }
305
306   /* i is the entry to remove */
307   if (i != entries - 1)
308     table[i] = table[entries-1];
309
310   entries--;
311
312   return SNMPv3_MP_OK;
313 }
314
315 int v3MP::EngineIdTable::initialize_table(const int size)
316 {
317   table = new struct Entry_T[size];
318   entries = 0;
319   if (!table)
320   {
321     max_entries = 0;
322     return FALSE;
323   }
324   max_entries = size;
325   return TRUE;
326 }
327
328 // ===============================[ Cache ]==================================
329
330 v3MP::Cache::Cache()
331 {
332   // init cache
333   table = new struct Entry_T[5];
334   if (!table)
335   {
336     LOG_BEGIN(ERROR_LOG | 1);
337     LOG("v3MP::Cache: could not create empty table.");
338     LOG_END;
339
340     max_entries = 0;
341   }
342   else
343     max_entries = 5;
344
345   entries = 0;
346 }
347
348 v3MP::Cache::~Cache()
349 {
350   if (table)
351   {
352     for (int i = 0; i < entries; i++)
353       usm->delete_sec_state_reference(table[i].sec_state_ref);
354     entries = 0;
355     delete [] table;
356     table = 0;
357     max_entries = 0;
358   }
359 }
360
361 // Add an entry to the cache.
362 int v3MP::Cache::add_entry(int msg_id, unsigned long req_id,
363                            const OctetStr &sec_engine_id,
364                            int sec_model,
365                            const OctetStr &sec_name,
366                            int sec_level,
367                            const OctetStr &context_engine_id,
368                            const OctetStr &context_name,
369                            struct SecurityStateReference *sec_state_ref,
370                            int error_code, bool local_request)
371 {
372   if (!table)
373     return SNMPv3_MP_ERROR;
374
375   LOG_BEGIN(INFO_LOG | 8);
376   LOG("v3MP::Cache: adding new entry (n) (msg id) (req id) (type)");
377   LOG(entries);
378   LOG(msg_id);
379   LOG(req_id);
380   LOG(local_request ? "local" : "remote");
381   LOG_END;
382
383   BEGIN_REENTRANT_CODE_BLOCK;
384
385   for (int i = 0; i < entries; i++)
386     if ((table[i].msg_id == msg_id) &&
387         (table[i].req_id == req_id) &&
388         (table[i].local_request == local_request) &&
389         (table[i].sec_engine_id == sec_engine_id) &&
390         (table[i].sec_model == sec_model) &&
391         (table[i].sec_name == sec_name) &&
392         (table[i].sec_level == sec_level) &&
393         (table[i].context_engine_id == context_engine_id) &&
394         (table[i].context_name == context_name))
395     {
396       LOG_BEGIN(WARNING_LOG | 3);
397       LOG("v3MP::Cache: Dont add doubled entry (msg id) (req id)");
398       LOG(msg_id);
399       LOG(req_id);
400       LOG_END;
401
402       return SNMPv3_MP_DOUBLED_MESSAGE;
403     }
404
405   table[entries].msg_id            = msg_id;
406   table[entries].req_id            = req_id;
407   table[entries].local_request     = local_request;
408   table[entries].sec_engine_id     = sec_engine_id;
409   table[entries].sec_model         = sec_model;
410   table[entries].sec_name          = sec_name;
411   table[entries].sec_level         = sec_level;
412   table[entries].context_engine_id = context_engine_id;
413   table[entries].context_name      = context_name;
414   table[entries].sec_state_ref     = sec_state_ref;
415   table[entries].error_code        = error_code;
416
417   entries++;
418   if (entries == max_entries)
419   {
420     // resize Table
421     struct Entry_T *tmp;
422     tmp = new struct Entry_T[2 * max_entries];
423     if (!tmp)
424     {
425       entries--;
426       return SNMPv3_MP_ERROR;
427     }
428     for (int i=0; i<entries;i++)
429       tmp[i] = table[i];
430     delete [] table;
431     table = tmp;
432     max_entries *= 2;
433   }
434   return SNMPv3_MP_OK;
435 }
436
437 // Search the cache for a message id, return the error code and
438 int v3MP::Cache::get_entry(int msg_id, bool local_request, int *error_code,
439                            struct SecurityStateReference **sec_state_ref)
440 {
441   if (!table) return SNMPv3_MP_ERROR;
442
443   BEGIN_REENTRANT_CODE_BLOCK;
444
445   for (int i=0; i < entries; i++)
446   {
447     if ((msg_id == table[i].msg_id) &&
448         (local_request == table[i].local_request))
449     {
450       *error_code = table[i].error_code;
451       *sec_state_ref = table[i].sec_state_ref;
452       entries--;
453
454       LOG_BEGIN(INFO_LOG | 8);
455       LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
456       LOG(i);
457       LOG(msg_id);
458       LOG(local_request ? "local" : "remote");
459       LOG_END;
460
461       if (entries > i)
462       {
463         table[i] = table[entries];
464
465         LOG_BEGIN(INFO_LOG | 10);
466         LOG("v3MP::Cache: Moving entry (from) (to)");
467         LOG(entries);
468         LOG(i);
469         LOG_END;
470       }
471       return SNMPv3_MP_OK;
472     }
473   }
474
475   LOG_BEGIN(WARNING_LOG | 5);
476   LOG("v3MP::Cache: Entry not found (msg id) (type)");
477   LOG(msg_id);
478   LOG(local_request ? "local" : "remote");
479   LOG_END;
480
481   return SNMPv3_MP_ERROR;
482 }
483
484 // Delete the entry with the given request id from the cache.
485 void v3MP::Cache::delete_entry(unsigned long req_id, bool local_request)
486 {
487   if (!table) return;
488
489   BEGIN_REENTRANT_CODE_BLOCK;
490
491   for (int i=0; i<entries; i++)
492     if ((table[i].req_id == req_id) &&
493         (table[i].local_request == local_request))
494     {
495       LOG_BEGIN(INFO_LOG | 8);
496       LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (type)");
497       LOG(i);
498       LOG(req_id);
499       LOG(local_request ? "local" : "remote");
500       LOG_END;
501
502       usm->delete_sec_state_reference(table[i].sec_state_ref);
503       entries--;
504       if (entries > i)
505       {
506         table[i] = table[entries];
507
508         LOG_BEGIN(INFO_LOG | 10);
509         LOG("v3MP::Cache: Moving entry (from) (to)");
510         LOG(entries);
511         LOG(i);
512         LOG_END;
513       }
514       return;
515     }
516
517   LOG_BEGIN(INFO_LOG | 8);
518   LOG("v3MP::Cache: Entry to delete not found (req id) (type)");
519   LOG(req_id);
520   LOG(local_request ? "local" : "remote");
521   LOG_END;
522
523   return;
524 }
525
526 // Delete the entry with the given request ans message id from the cache.
527 void v3MP::Cache::delete_entry(unsigned long req_id, int msg_id,
528                                bool local_request)
529 {
530   if (!table) return;
531
532   BEGIN_REENTRANT_CODE_BLOCK;
533
534   for (int i=0; i<entries; i++)
535     if ((table[i].req_id == req_id) &&
536         (table[i].msg_id == msg_id) &&
537         (table[i].local_request == local_request))
538     {
539       LOG_BEGIN(INFO_LOG | 8);
540       LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (msg id) (type)");
541       LOG(i);
542       LOG(req_id);
543       LOG(msg_id);
544       LOG(local_request ? "local" : "remote");
545       LOG_END;
546
547       usm->delete_sec_state_reference(table[i].sec_state_ref);
548       entries--;
549       if (entries > i)
550       {
551         table[i] = table[entries];
552
553         LOG_BEGIN(INFO_LOG | 10);
554         LOG("v3MP::Cache: Moving entry (from) (to)");
555         LOG(entries);
556         LOG(i);
557         LOG_END;
558       }
559       return;
560     }
561
562   LOG_BEGIN(INFO_LOG | 8);
563   LOG("v3MP::Cache: Entry to delete not found (req id) (msg id) (type)");
564   LOG(req_id);
565   LOG(msg_id);
566   LOG(local_request ? "local" : "remote");
567   LOG_END;
568
569   return;
570 }
571
572 // Search the cache for a message id, return it and remove it from the cache
573 int v3MP::Cache::get_entry(int searchedID, bool local_request,
574                            struct Cache::Entry_T *res)
575 {
576   if ((!table) || (!res)) return SNMPv3_MP_ERROR;
577
578   BEGIN_REENTRANT_CODE_BLOCK;
579
580   for (int i=0; i < entries; i++)
581     if ((table[i].msg_id == searchedID) &&
582         (table[i].local_request == local_request))
583     {
584       res->msg_id            = table[i].msg_id;
585       res->req_id            = table[i].req_id;
586       res->local_request     = table[i].local_request;
587       res->sec_engine_id     = table[i].sec_engine_id;
588       res->sec_model         = table[i].sec_model;
589       res->sec_name          = table[i].sec_name;
590       res->sec_level         = table[i].sec_level;
591       res->context_engine_id = table[i].context_engine_id;
592       res->context_name      = table[i].context_name;
593       res->sec_state_ref     = table[i].sec_state_ref;
594       res->error_code        = table[i].error_code;
595
596       LOG_BEGIN(INFO_LOG | 8);
597       LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
598       LOG(i);
599       LOG(searchedID);
600       LOG(local_request ? "local" : "remote");
601       LOG_END;
602
603       entries--;
604
605       if (entries > i)
606       {
607         table[i] = table[entries];
608
609         LOG_BEGIN(INFO_LOG | 10);
610         LOG("v3MP::Cache: Moving entry (from) (to)");
611         LOG(entries);
612         LOG(i);
613         LOG_END;
614       }
615       return SNMPv3_MP_OK;
616     }
617
618   LOG_BEGIN(WARNING_LOG | 5);
619   LOG("v3MP::Cache: Entry not found (msg id) (type)");
620   LOG(searchedID);
621   LOG(local_request ? "local" : "remote");
622   LOG_END;
623
624   return SNMPv3_MP_ERROR;
625 }
626
627 void v3MP::Cache::delete_content(struct v3MP::Cache::Entry_T &ce)
628 {
629   if (ce.sec_state_ref)
630     usm->delete_sec_state_reference(ce.sec_state_ref);
631 }
632
633 // ==========================[ class v3MP ]===============================
634
635 // Initialize the v3MP.
636 v3MP::v3MP(const OctetStr& snmpEngineID,
637            unsigned int engineBoots, int &construct_status)
638   : own_engine_id(0), usm(0)
639 {
640   if (I)
641   {
642     debugprintf(0, "v3MP: You must not create two objects of this class!");
643     construct_status = SNMPv3_MP_ERROR;
644     return;
645   }
646
647   I = this;
648
649   snmpUnknownSecurityModels = 0;
650   snmpInvalidMsgs = 0;
651   snmpUnknownPDUHandlers = 0;
652
653   int length = snmpEngineID.len();
654   if (length > MAXLENGTH_ENGINEID)
655     length = MAXLENGTH_ENGINEID;
656
657   own_engine_id = v3strcpy(snmpEngineID.data(), length);
658   own_engine_id_len = length;
659   own_engine_id_oct = snmpEngineID;
660
661   int result;
662   usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);
663
664   if (cur_msg_id >= MAX_MPMSGID)
665     cur_msg_id = 1;
666
667   if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
668   {
669     construct_status = SNMPv3_MP_ERROR;
670     return;
671   }
672
673   cache.set_usm(usm);
674   construct_status = SNMPv3_MP_OK;
675 }
676
677 // Free all allocated ressources of the v3MP.
678 v3MP::~v3MP()
679 {
680   if (own_engine_id)
681     delete [] own_engine_id;
682   own_engine_id = 0;
683
684   if (usm)
685   {
686     delete usm;
687     usm = 0;
688   }
689
690   I = 0;
691 }
692
693 // Remove all occurences of this engine id from v3MP and USM.
694 int v3MP::remove_engine_id(const OctetStr &engine_id)
695 {
696   int retval1, retval2;
697
698   retval1 = engine_id_table.delete_entry(engine_id);
699
700   retval2 = usm->remove_engine_id(engine_id);
701
702   if ((retval1 == SNMPv3_MP_NOT_INITIALIZED) ||
703       (retval2 == SNMPv3_USM_ERROR))
704     return SNMPv3_MP_NOT_INITIALIZED;
705
706   return SNMPv3_MP_OK;
707 }
708
709 // Send a report message.
710 int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
711                       struct snmp_pdu *pdu, int errorCode, int sLevel,
712                       int sModel, OctetStr &sName,
713                       UdpAddress &destination, Snmp *snmp_session)
714 {
715   debugprintf(2, "v3MP::send_report: Sending report message.");
716
717   unsigned char *data;
718   int dataLength;
719   int pdu_type = 0;
720   unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
721   unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
722   int cEngineIDLength = MAXLENGTH_ENGINEID+1;
723   int cNameLength = MAXLENGTH_CONTEXT_NAME+1;
724
725   if (scopedPDULength != MAX_SNMP_PACKET)
726   {
727     // try to get scopedPDU and PDU
728     data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
729                                  cEngineID, &cEngineIDLength,
730                                  cName, &cNameLength);
731     if (data == NULL) {
732       debugprintf(1, "mp: Error while trying to parse  scopedPDU!");
733       cEngineID[0] = '\0';
734       cEngineIDLength = 0;
735       cName[0] = '\0';
736       cNameLength = 0;
737       // Dont send encrypted report if decryption failed:
738       if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
739         sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
740     }
741     else { // data != NULL
742       dataLength = scopedPDULength;
743
744       // parse data of scopedPDU
745       snmp_parse_data_pdu(pdu, data, dataLength);
746       pdu_type = pdu->command;
747
748       if (!data) {
749         debugprintf(0, "mp: Error while trying to parse PDU!");
750       }
751     } // end of: if (data == NULL)
752   } // end if (scopedPDULength != MAX_SNMP_PACKET)
753   else { // scopedPDULength == MAX_SNMP_PACKET
754     cEngineID[0] = '\0';
755     cEngineIDLength = 0;
756     cName[0] = '\0';
757     cNameLength = 0;
758     pdu->reqid = 0;
759   }
760
761   clear_pdu(pdu);   // Clear pdu and free all content
762
763   debugprintf(4, "pdu->reqid = %ld",pdu->reqid);
764   pdu->errstat = 0;
765   pdu->errindex = 0;
766   pdu->command = REPORT_MSG;
767
768   Vb counterVb;
769   Oid counterOid;
770   SmiLPOID smioid;
771   SmiVALUE smival;
772
773   switch (errorCode) {
774     case SNMPv3_MP_INVALID_MESSAGE:
775     case SNMPv3_USM_PARSE_ERROR: {
776       counterVb.set_oid(oidSnmpInvalidMsgs);
777       counterVb.set_value(Counter32(get_stats_invalid_msgs()));
778       break;
779     }
780     case SNMPv3_USM_NOT_IN_TIME_WINDOW:
781     case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
782       counterVb.set_oid(oidUsmStatsNotInTimeWindows);
783       counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
784       break;
785     }
786     case SNMPv3_USM_DECRYPTION_ERROR: {
787       counterVb.set_oid(oidUsmStatsDecryptionErrors);
788       counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
789       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
790       break;
791     }
792     case SNMPv3_USM_AUTHENTICATION_ERROR:
793     case SNMPv3_USM_AUTHENTICATION_FAILURE: {
794       counterVb.set_oid(oidUsmStatsWrongDigests);
795       counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
796       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
797       break;
798     }
799     case SNMPv3_USM_UNKNOWN_ENGINEID:
800     case SNMPv3_MP_INVALID_ENGINEID: {
801       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
802       counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
803       counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
804       break;
805     }
806     case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
807       counterVb.set_oid(oidSnmpUnknownSecurityModels);
808       counterVb.set_value(Counter32(get_stats_unknown_security_models()));
809       sModel = SNMP_SECURITY_MODEL_USM;
810       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
811     break;
812     }
813     case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
814       counterVb.set_oid(oidUsmStatsUnknownUserNames);
815       counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
816       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
817       debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
818       break;
819     }
820     case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
821       counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
822       counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
823       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
824       break;
825     }
826     default: {
827       counterVb.set_oid(oidSnmpInvalidMsgs);
828       counterVb.set_value(Counter32(get_stats_invalid_msgs()));
829       sModel = SNMP_SECURITY_MODEL_USM;
830       sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
831       sName.set_data(0, 0);
832
833       debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
834     }
835   } // end switch
836
837   counterVb.get_oid(counterOid);
838   smioid = counterOid.oidval();
839
840   int status = convertVbToSmival(counterVb, &smival);
841   if (status != SNMP_CLASS_SUCCESS) {
842     return SNMPv3_MP_ERROR;
843   }
844   snmp_add_var(pdu, smioid->ptr,
845                (int) smioid->len, &smival);
846   freeSmivalDescriptor(&smival);
847
848   Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
849   int sendbufferlen= MAX_SNMP_PACKET;
850   status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
851                        own_engine_id_oct, sName, sModel, sLevel,
852                        OctetStr(cEngineID, cEngineIDLength),
853                        OctetStr(cName, cNameLength));
854   if (status != SNMPv3_MP_OK) {
855     debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
856     return SNMPv3_MP_ERROR;
857   }
858   SnmpSocket send_fd = INVALID_SOCKET;
859   if (pdu_type == sNMP_PDU_INFORM)
860   {
861     debugprintf(4, "Received a snmpInform pdu.");
862     if (snmp_session->get_eventListHolder()->notifyEventList())
863       send_fd = snmp_session->get_eventListHolder()->notifyEventList()->get_notify_fd();
864   }
865
866   status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
867                                        (size_t)sendbufferlen,// pdu to send
868                                        destination,          // target address
869                                        send_fd);             // the fd to use
870   if ( status != 0)
871   {
872     debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
873     return SNMPv3_MP_ERROR;
874   }
875   debugprintf(3, "v3MP::send_report: Report sent.");
876   return SNMPv3_MP_OK;
877 }
878
879 // Parse the given buffer as a SNMPv3-Message.
880 int v3MP::snmp_parse(Snmp *snmp_session,
881                      struct snmp_pdu *pdu,
882                      unsigned char *inBuf,
883                      int inBufLength,
884                      OctetStr &securityEngineID,
885                      OctetStr &securityName,
886                      OctetStr &contextEngineID,
887                      OctetStr &contextName,
888                      long     &securityLevel,
889                      long     &msgSecurityModel,
890                      snmp_version &spp_version,
891                      UdpAddress from_address)
892 {
893   debugprintf(3, "mp is parsing incoming message:");
894   debughexprintf(25, inBuf, inBufLength);
895
896   if (inBufLength > MAX_SNMP_PACKET)
897     return  SNMPv3_MP_ERROR;
898
899   unsigned char type;
900   long version;
901   int origLength = inBufLength;
902   unsigned char *inBufPtr = inBuf;
903   long msgID, msgMaxSize;
904   unsigned char msgFlags;
905   Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
906   Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
907   int msgSecurityParametersLength = inBufLength,   msgDataLength = inBufLength;
908   Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
909   int scopedPDULength = MAX_SNMP_PACKET;
910   long  maxSizeResponseScopedPDU = 0;
911   struct SecurityStateReference *securityStateReference = NULL;
912   int securityParametersPosition;
913   int rc;
914   int errorCode = 0;
915
916   // get the type
917   inBuf = asn_parse_header( inBuf, &inBufLength, &type);
918   if (inBuf == NULL){
919     debugprintf(0, "snmp_parse: bad header");
920     return SNMPv3_MP_PARSE_ERROR;
921   }
922
923   if (type != (ASN_SEQ_CON)){
924     debugprintf(0, "snmp_parse: wrong auth header type");
925     return SNMPv3_MP_PARSE_ERROR;
926   }
927
928   if (origLength != inBufLength + (inBuf - inBufPtr)) {
929     debugprintf(0, "snmp_parse: wrong length of received packet");
930     return SNMPv3_MP_PARSE_ERROR;
931   }
932
933   // get the version
934   inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version);
935   if (inBuf == NULL){
936     debugprintf(0, "snmp_parse: bad parse of version");
937     return SNMPv3_MP_PARSE_ERROR;
938   }
939
940   debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);
941
942   if ( version != SNMP_VERSION_3 )
943     return SNMPv3_MP_PARSE_ERROR;
944
945   spp_version = (snmp_version) version;
946
947   inBuf = asn1_parse_header_data(inBuf, &inBufLength,
948                                  &msgID, &msgMaxSize,
949                                  &msgFlags, &msgSecurityModel);
950
951   if (inBuf == NULL){
952     debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
953     return SNMPv3_MP_PARSE_ERROR;
954   }
955
956   pdu->msgid = msgID;
957   if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
958     debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
959     return SNMPv3_MP_PARSE_ERROR;
960   }
961
962   // do not allow larger messages than this entity can handle
963   if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
964   pdu->maxsize_scopedpdu = msgMaxSize;
965
966   inBuf = asn_parse_string( inBuf, &inBufLength, &type,
967                             msgSecurityParameters.get_ptr(),
968                             &msgSecurityParametersLength);
969
970   if (inBuf == NULL){
971     debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
972     return SNMPv3_MP_PARSE_ERROR;
973   }
974
975   securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;
976
977   // the rest of the message is passed directly to the security module
978
979   msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
980   memcpy(msgData.get_ptr(), inBuf, msgDataLength);
981
982   debugprintf(3, "Parsed msgdata length(0x%x), "
983               "msgSecurityParameters length(0x%x)", msgDataLength,
984               msgSecurityParametersLength);
985
986   switch (msgFlags & 0x03) {
987     case 3:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV;     break;}
988     case 0:  { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
989     case 1:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;   break;}
990     default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
991                snmpInvalidMsgs++;
992                // do not send back report
993                return SNMPv3_MP_INVALID_MESSAGE;
994                break;
995              }
996   }
997
998   bool reportableFlag;
999
1000   if (msgFlags & 0x04) reportableFlag = TRUE;
1001   else                 reportableFlag = FALSE;
1002
1003   securityStateReference = usm->get_new_sec_state_reference();
1004   if (!securityStateReference)
1005     return SNMPv3_MP_ERROR;
1006
1007   switch (msgSecurityModel) {
1008     case SNMP_SECURITY_MODEL_USM:
1009       {
1010         rc = usm->process_msg(
1011                            msgMaxSize,
1012                            msgSecurityParameters.get_ptr(),
1013                            msgSecurityParametersLength,
1014                            securityParametersPosition,
1015                            securityLevel,
1016                            inBufPtr, origLength, //wholeMsg
1017                            msgData.get_ptr(), msgDataLength,
1018                            securityEngineID,
1019                            securityName,
1020                            scopedPDU.get_ptr(), &scopedPDULength,
1021                            &maxSizeResponseScopedPDU,
1022                            securityStateReference,
1023                            from_address);
1024         pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
1025         if (rc != SNMPv3_USM_OK) {
1026           if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
1027             errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
1028           }
1029           else {
1030             // error handling! rfc2262 page 31
1031             debugprintf(0, "mp: error while executing USM::process_msg");
1032             errorCode = rc;
1033           }
1034         }
1035         if (errorCode != SNMPv3_USM_PARSE_ERROR)
1036           if (securityEngineID.len() == 0)
1037             errorCode = SNMPv3_MP_INVALID_ENGINEID;
1038         break;
1039       }
1040     default: {
1041         snmpUnknownSecurityModels++;
1042         usm->delete_sec_state_reference(securityStateReference);
1043         debugprintf(0, "SecurityModel of incomming Message not supported!");
1044         // Message should be dropped without a report
1045         return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
1046       }
1047   }
1048   // process scopedPDU
1049   debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);
1050
1051   unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
1052   unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
1053   unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
1054   int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
1055   int tmp_contextNameLength     = MAXLENGTH_CONTEXT_NAME;
1056
1057   unsigned char *data;
1058   int dataLength;
1059
1060   debugprintf(1,"ErrorCode is %i",errorCode);
1061
1062   if (!errorCode) {
1063     data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
1064                                  tmp_contextEngineID,
1065                                  &tmp_contextEngineIDLength,
1066                                  tmp_contextName, &tmp_contextNameLength);
1067     if (data == NULL) {
1068       debugprintf(0, "mp: Error Parsing scopedPDU!");
1069       usm->delete_sec_state_reference(securityStateReference);
1070       return SNMPv3_MP_PARSE_ERROR;
1071     }
1072     dataLength = scopedPDULength;
1073     contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
1074     contextName.set_data(tmp_contextName, tmp_contextNameLength);
1075
1076     // parse data of scopedPDU
1077     if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
1078       debugprintf(0, "mp: Error parsing PDU!");
1079       usm->delete_sec_state_reference(securityStateReference);
1080       return SNMPv3_MP_PARSE_ERROR;
1081     }
1082     if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
1083       debugprintf(0, "mp: Error parsing Vb");
1084       usm->delete_sec_state_reference(securityStateReference);
1085       return SNMPv3_MP_PARSE_ERROR;
1086     }
1087     if ((tmp_contextEngineIDLength == 0) &&
1088         ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1089          (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1090          (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
1091          (pdu->command == TRP2_REQ_MSG)))
1092     {
1093       //  RFC 2572 ï¿½ 4.2.2.1 (2a)
1094       debugprintf(2, "mp: received request message with zero length"
1095                   " contextEngineID -> unknownPduHandlers.");
1096       inc_stats_unknown_pdu_handlers();
1097       errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
1098     }
1099   }
1100   if (errorCode) {
1101     if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) {
1102       // error occured: prepare reportpdu in agent
1103       cache.add_entry(msgID, pdu->reqid, securityEngineID,
1104                       msgSecurityModel,
1105                       securityName, securityLevel, "", "",
1106                       securityStateReference, errorCode, CACHE_REMOTE_REQ);
1107
1108       send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode,
1109                   securityLevel, msgSecurityModel, securityName,
1110                   from_address, snmp_session);
1111       clear_pdu(pdu, true);   // Clear pdu and free all content AND IDs!
1112     }
1113     else {
1114       usm->delete_sec_state_reference(securityStateReference);
1115     }
1116     return errorCode;
1117   }
1118
1119   struct Cache::Entry_T centry;
1120
1121   if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) {
1122     rc = cache.get_entry(msgID, true, &centry);
1123     if (rc != SNMPv3_MP_OK) {
1124       // RFC 2572 ï¿½ 4
1125       debugprintf(2, "Received rspMsg without outstanding request."
1126                   " -> SnmpUnknownPduHandler");
1127       usm->delete_sec_state_reference(securityStateReference);
1128       inc_stats_unknown_pdu_handlers();
1129       return SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
1130     }
1131     if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff))
1132         && (pdu->command == REPORT_MSG))
1133       pdu->reqid = centry.req_id;
1134 #ifdef BUGGY_REPORT_REQID
1135     if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG))
1136     {
1137       debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)",  pdu->reqid, centry.req_id);
1138       pdu->reqid = centry.req_id;
1139     }
1140 #endif
1141   }
1142
1143   if (pdu->command == REPORT_MSG) {
1144     // !! rfc2262 page 33
1145
1146     debugprintf(2, "*** Receiving a ReportPDU ***");
1147     if (/*((securityEngineID != centry.sec_engine_id)
1148           && (centry.sec_engine_id.len() != 0)) ||*/
1149         ((msgSecurityModel != centry.sec_model)
1150          && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) ||
1151         ((securityName != centry.sec_name)
1152          && (securityName.len() != 0)))
1153     {
1154       debugprintf(0, "Received report message doesn't match sent message!");
1155       usm->delete_sec_state_reference(securityStateReference);
1156       return SNMPv3_MP_MATCH_ERROR;
1157     }
1158     usm->delete_sec_state_reference(securityStateReference);
1159     cache.delete_content(centry);
1160     debugprintf(1, "mp finished (OK)");
1161     return SNMPv3_MP_OK;
1162   }
1163
1164   if (pdu->command == GET_RSP_MSG) {
1165     if (((securityEngineID != centry.sec_engine_id)
1166          && (centry.sec_engine_id.len() != 0)) ||
1167         (msgSecurityModel != centry.sec_model) ||
1168         (securityName != centry.sec_name) ||
1169         (securityLevel != centry.sec_level) ||
1170         ((contextEngineID != centry.context_engine_id)
1171          && (centry.context_engine_id.len() != 0))||
1172         ((contextName != centry.context_name)
1173          && (centry.context_name.len() != 0))) {
1174       debugprintf(0, "Received response message doesn't match sent message!");
1175       usm->delete_sec_state_reference(securityStateReference);
1176       cache.delete_content(centry);
1177       return SNMPv3_MP_MATCH_ERROR;
1178     }
1179     usm->delete_sec_state_reference(securityStateReference);
1180     cache.delete_content(centry);
1181     debugprintf(1, "mp finished (OK)");
1182     return SNMPv3_MP_OK;
1183   }
1184
1185   if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1186       (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1187       (pdu->command == INFORM_REQ_MSG)) {
1188     if (securityEngineID.len() == 0) {
1189       debugprintf(2, "Received Message with engineID = 0.");
1190     }
1191     else {
1192       if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(),
1193                                 own_engine_id, own_engine_id_len))) {
1194         debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id.");
1195         /* we are authoritative but engine id of message is wrong
1196            if discovery in USM is enabled:
1197            - remove automatically added illegal engine id from USM tables
1198            - send a report
1199         */
1200         if (usm->is_discovery_enabled())
1201         {
1202           // TODO: try to remove engine id from USM
1203           if (reportableFlag)
1204           {
1205             cache.add_entry(msgID, pdu->reqid, securityEngineID,
1206                             msgSecurityModel,
1207                             securityName, securityLevel, "", "",
1208                             securityStateReference,
1209                             SNMPv3_MP_INVALID_ENGINEID,
1210                             CACHE_REMOTE_REQ);
1211
1212             send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID,
1213                         SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel,
1214                         securityName, from_address, snmp_session);
1215             clear_pdu(pdu, true);  // Clear pdu and free all content AND IDs!
1216           }
1217           else
1218           {
1219             usm->delete_sec_state_reference(securityStateReference);
1220           }
1221           return SNMPv3_MP_INVALID_ENGINEID;
1222         }
1223
1224         usm->delete_sec_state_reference(securityStateReference);
1225         return SNMPv3_MP_MATCH_ERROR;
1226       }
1227     }
1228     int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID,
1229                               msgSecurityModel, securityName,
1230                               securityLevel, contextEngineID,
1231                               contextName, securityStateReference,
1232                               SNMPv3_MP_OK, CACHE_REMOTE_REQ);
1233     if (ret == SNMPv3_MP_DOUBLED_MESSAGE) {
1234       debugprintf(0, "*** received doubled message ***");
1235       // message will be ignored so return OK
1236       usm->delete_sec_state_reference(securityStateReference);
1237     }
1238
1239     debugprintf(1, "mp: parsing finished (ok).");
1240     return SNMPv3_MP_OK;
1241   }
1242
1243   if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))
1244   {
1245     usm->delete_sec_state_reference(securityStateReference);
1246     return SNMPv3_MP_OK;
1247   }
1248
1249   debugprintf(0, "mp error: This line should not be executed.");
1250   usm->delete_sec_state_reference(securityStateReference);
1251   return SNMPv3_MP_ERROR;
1252 }
1253
1254
1255 // Tests if the given buffer contains a SNMPv3-Message.
1256 bool v3MP::is_v3_msg(unsigned char *buffer, int length)
1257 {
1258   unsigned char type;
1259   long version;
1260
1261   // get the type
1262   buffer = asn_parse_header(buffer, &length, &type);
1263   if (!buffer)
1264   {
1265     LOG_BEGIN(WARNING_LOG | 1);
1266     LOG("Testing for v3 message: Bad header");
1267     LOG_END;
1268
1269     return FALSE;
1270   }
1271
1272   if (type != ASN_SEQ_CON)
1273   {
1274     LOG_BEGIN(WARNING_LOG | 1);
1275     LOG("Testing for v3 message: Wrong auth header type");
1276     LOG((int)type);
1277     LOG_END;
1278
1279     return FALSE;
1280   }
1281
1282   // get the version
1283   buffer = asn_parse_int(buffer, &length, &type, &version);
1284   if (!buffer)
1285   {
1286     LOG_BEGIN(WARNING_LOG | 1);
1287     LOG("Testing for v3 message: Bad parse of version");
1288     LOG_END;
1289
1290     return 0;
1291   }
1292
1293   return (version == SNMP_VERSION_3);
1294 }
1295
1296
1297
1298 // Do the complete process of encoding the given values into the buffer
1299 // ready to send to the target.
1300 int v3MP::snmp_build(struct snmp_pdu *pdu,
1301                      unsigned char *packet,
1302                      int *out_length,             // maximum Bytes in packet
1303                      const OctetStr &securityEngineID,
1304                      const OctetStr &securityName,
1305                      int securityModel,
1306                      int securityLevel,
1307                      const OctetStr &contextEngineID,
1308                      const OctetStr &contextName)
1309 {
1310   Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
1311   unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
1312   unsigned char globalData[MAXLENGTH_GLOBALDATA];
1313   int globalDataLength = MAXLENGTH_GLOBALDATA;
1314   int scopedPDULength, maxLen = *out_length;
1315   Buffer<unsigned char> buf(MAX_SNMP_PACKET);
1316   unsigned char *bufPtr = buf.get_ptr();
1317   long bufLength = 0, rc;
1318   int msgID;
1319   int cachedErrorCode = SNMPv3_MP_OK;
1320   struct SecurityStateReference *securityStateReference = NULL;
1321   int isRequestMessage = 0;
1322
1323   if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1324       (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1325       (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
1326       (pdu->command == TRP2_REQ_MSG))
1327     isRequestMessage = 1;
1328
1329   if (isRequestMessage) {
1330     if (securityEngineID.len() == 0) {
1331       // First Contact => use user  noAuthNoPriv and USM
1332       securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
1333       securityModel = SNMP_SECURITY_MODEL_USM;
1334     }
1335
1336     cur_msg_id_lock.lock();
1337     msgID = cur_msg_id;
1338     cur_msg_id++;
1339     if (cur_msg_id >= MAX_MPMSGID)
1340       cur_msg_id = 1;
1341     cur_msg_id_lock.unlock();
1342
1343 #ifdef INVALID_MSGID
1344     LOG_BEGIN(ERROR_LOG | 1);
1345     LOG("*** WARNING: Using constant MessageID! ***");
1346     LOG_END;
1347
1348     msgID = 0xdead;
1349 #endif
1350
1351     if (securityEngineID.len() == 0) {
1352       // length==0 => SecurityLevel == noAuthNoPriv
1353       //  => we do not send any management information
1354       //  => delete VariableBinding
1355       clear_pdu(pdu);
1356     }
1357   }
1358   else {
1359     // it is a response => search for request
1360     debugprintf(3, "Looking up cache");
1361     msgID = pdu->msgid;
1362     rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
1363                          &cachedErrorCode, &securityStateReference);
1364
1365     if (rc != SNMPv3_MP_OK) {
1366
1367       debugprintf(0, "mp: Cache lookup error");
1368       return SNMPv3_MP_MATCH_ERROR;
1369     }
1370   }
1371
1372   LOG_BEGIN(DEBUG_LOG | 5);
1373   LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
1374   LOG(securityEngineID.get_printable());
1375   LOG(securityName.get_printable());
1376   LOG(securityLevel);
1377   LOG(contextEngineID.get_printable());
1378   LOG(contextName.get_printable());
1379   LOG_END;
1380
1381   // encode vb in buf
1382   scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
1383   if (!scopedPDUPtr)
1384   {
1385     LOG_BEGIN(WARNING_LOG | 1);
1386     LOG("v3MP: Error encoding vbs into buffer");
1387     LOG_END;
1388
1389     return SNMPv3_MP_BUILD_ERROR;
1390   }
1391   scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
1392
1393   //build dataPDU in buf
1394   maxLen = *out_length;
1395   scopedPDUPtr = scopedPDU.get_ptr();
1396   bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);
1397
1398   if (!bufPtr)
1399   {
1400     LOG_BEGIN(WARNING_LOG | 1);
1401     LOG("v3MP: Error encoding data pdu into buffer");
1402     LOG_END;
1403
1404     return SNMPv3_MP_BUILD_ERROR;
1405   }
1406
1407   bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
1408
1409   //  serialize scopedPDU
1410   maxLen = *out_length;
1411   scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
1412                                        contextEngineID.data(),
1413                                        contextEngineID.len(),
1414                                        contextName.data(), contextName.len(),
1415                                        buf.get_ptr(), bufLength);
1416
1417   if (!scopedPDUPtr)
1418   {
1419     LOG_BEGIN(WARNING_LOG | 1);
1420     LOG("v3MP: Error encoding scoped pdu into buffer");
1421     LOG_END;
1422
1423     return SNMPv3_MP_BUILD_ERROR;
1424   }
1425
1426   scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
1427
1428   // build msgGlobalData
1429   unsigned char *globalDataPtr = (unsigned char *)&globalData;
1430   unsigned char msgFlags;
1431   switch (securityLevel) {
1432     case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
1433       { msgFlags = 0 ; break;}
1434     case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
1435       { msgFlags = SNMPv3_AUTHFLAG; break;}
1436     case SNMP_SECURITY_LEVEL_AUTH_PRIV:
1437       { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
1438     default:
1439     {
1440       LOG_BEGIN(WARNING_LOG | 1);
1441       LOG("v3MP: Unknown security level requested, will use authPriv");
1442       LOG(securityLevel);
1443       LOG_END;
1444
1445       msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
1446     }
1447   }
1448
1449   if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1450       (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1451       (pdu->command == INFORM_REQ_MSG))
1452     msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;
1453
1454   globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
1455                                          msgID, *out_length,  // maxMessageSize
1456                                          msgFlags, securityModel);
1457   if (!globalDataPtr)
1458   {
1459     LOG_BEGIN(ERROR_LOG | 1);
1460     LOG("v3MP: Error building header data");
1461     LOG_END;
1462
1463     return SNMPv3_MP_BUILD_ERROR;
1464   }
1465   globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);
1466
1467   switch (securityModel) {
1468     case SNMP_SECURITY_MODEL_USM: {
1469       int use_own_engine_id = 0;
1470       if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
1471           (pdu->command == REPORT_MSG)  || (pdu->command == TRP2_REQ_MSG)) {
1472         use_own_engine_id = 1;
1473       }
1474
1475       rc = usm->generate_msg(globalData, globalDataLength, *out_length,
1476                              (use_own_engine_id ?
1477                                         own_engine_id_oct : securityEngineID),
1478                              securityName, securityLevel,
1479                              scopedPDU.get_ptr(), scopedPDULength,
1480                              securityStateReference, packet, out_length);
1481
1482       if ( rc == SNMPv3_USM_OK ) {
1483         // build cache
1484         if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
1485               (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
1486           cache.add_entry(msgID, pdu->reqid, securityEngineID,
1487                           securityModel, securityName, securityLevel,
1488                           contextEngineID, contextName, securityStateReference,
1489                           SNMPv3_MP_OK, CACHE_LOCAL_REQ);
1490
1491         LOG_BEGIN(INFO_LOG | 3);
1492         LOG("v3MP: Message built OK");
1493         LOG_END;
1494
1495         return SNMPv3_MP_OK;
1496       }
1497       else
1498       {
1499         LOG_BEGIN(WARNING_LOG | 1);
1500         LOG("v3MP: Returning error for building message");
1501         LOG(rc);
1502         LOG_END;
1503
1504         return rc;
1505       }
1506     }
1507     default:
1508     {
1509       LOG_BEGIN(WARNING_LOG | 1);
1510       LOG("v3MP: Should build message with unsupported securityModel");
1511       LOG(securityModel);
1512       LOG_END;
1513
1514       return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
1515     }
1516   }
1517 }
1518
1519 #ifdef SNMP_PP_NAMESPACE
1520 }; // end of namespace Snmp_pp
1521 #endif 
1522
1523 #endif