]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/pdu.cpp
Fix build on osx.
[ssmd.git] / 3rdparty / snmp++ / src / pdu.cpp
1 /*_############################################################################
2   _## 
3   _##  pdu.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 /*===================================================================
30
31   Copyright (c) 1999
32   Hewlett-Packard Company
33
34   ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35   Permission to use, copy, modify, distribute and/or sell this software
36   and/or its documentation is hereby granted without fee. User agrees
37   to display the above copyright notice and this license notice in all
38   copies of the software and any documentation of the software. User
39   agrees to assume all liability for the use of the software; Hewlett-Packard
40   makes no representations about the suitability of this software for any
41   purpose. It is provided "AS-IS" without warranty of any kind,either express
42   or implied. User hereby grants a royalty-free license to any and all
43   derivatives based upon this software code base.
44
45
46   P D U . C P P
47
48   PDU CLASS IMPLEMENTATION
49
50   DESIGN + AUTHOR:  Peter E Mellquist
51
52   DESCRIPTION:
53   Pdu class implementation. Encapsulation of an SMI Protocol
54   Data Unit (PDU) in C++.
55
56 =====================================================================*/
57 char pdu_cpp_version[]="@(#) SNMP++ $Id: pdu.cpp 209 2006-01-07 20:02:34Z katz $";
58
59 #include "snmp_pp/pdu.h"       // include Pdu class definition
60 #include "snmp_pp/usm_v3.h"
61 #include "snmp_pp/vb.h"
62 #include "snmp_pp/v3.h"
63
64 #ifdef SNMP_PP_NAMESPACE
65 namespace Snmp_pp {
66 #endif
67
68 #define PDU_INITIAL_SIZE 25
69
70 //=====================[ constructor no args ]=========================
71 Pdu::Pdu()
72   : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
73     validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
74     v1_trap_address_set(false)
75 #ifdef _SNMPv3
76     , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
77     message_id(0), maxsize_scopedpdu(0)
78 #endif
79 {
80 }
81
82 //=====================[ constructor with vbs and count ]==============
83 Pdu::Pdu(Vb* pvbs, const int pvb_count)
84   : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
85     validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
86     v1_trap_address_set(false)
87 #ifdef _SNMPv3
88     , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
89     message_id(0), maxsize_scopedpdu(0)
90 #endif
91 {
92   if (pvb_count == 0) return;    // zero is ok
93
94   vbs = new Vb*[pvb_count];
95   if (vbs)
96     vbs_size = pvb_count;
97   else
98   {
99     vbs_size = 0;
100     validity = false;
101     return;
102   }
103
104   // loop through and assign internal vbs
105   for (int z = 0; z < pvb_count; ++z)
106   {
107     if (pvbs[z].valid())
108       vbs[z] = new Vb(pvbs[z]);
109     else
110       vbs[z] = 0;
111
112     if ((vbs[z]) && !vbs[z]->valid())
113     {
114       delete vbs[z];
115       vbs[z] = 0;
116     }
117
118     if (vbs[z] == 0)     // check for new fail
119     {
120       for (int y = 0; y < z; ++y) delete vbs[y]; // free vbs
121       validity = false;
122       return;
123     }
124   }
125
126   vb_count = pvb_count;   // assign the vb count
127 }
128
129 //=====================[ destructor ]====================================
130 Pdu::~Pdu()
131 {
132   for (int z = 0; z < vb_count; ++z)
133   {
134     delete vbs[z];
135     vbs[z] = 0;
136   }
137
138   if (vbs)
139   {
140     delete [] vbs;
141     vbs = 0;
142     vbs_size = 0;
143   }
144 }
145
146 //=====================[ assignment to another Pdu object overloaded ]===
147 Pdu& Pdu::operator=(const Pdu &pdu)
148 {
149   if (this == &pdu) return *this; // check for self assignment
150
151   // Initialize all mv's
152   error_status      = pdu.error_status;
153   error_index       = pdu.error_index;
154   request_id        = pdu.request_id;
155   pdu_type          = pdu.pdu_type;
156   notify_id         = pdu.notify_id;
157   notify_timestamp  = pdu.notify_timestamp;
158   notify_enterprise = pdu.notify_enterprise;
159 #ifdef _SNMPv3
160   security_level    = pdu.security_level;
161   message_id        = pdu.message_id;
162   context_name      = pdu.context_name;
163   context_engine_id = pdu.context_engine_id;
164   maxsize_scopedpdu = pdu.maxsize_scopedpdu;
165 #endif
166   if (pdu.v1_trap_address_set)
167   {
168     v1_trap_address = pdu.v1_trap_address;
169     v1_trap_address_set = true;
170   }
171   else
172     v1_trap_address_set = false;
173
174   validity = true;
175
176   // free up old vbs
177   for (int z = 0; z < vb_count; ++z)  delete vbs[z];
178   vb_count = 0;
179
180   // check for zero case
181   if (pdu.vb_count == 0) return *this;
182
183   // allocate array
184   if (vbs_size < pdu.vb_count)
185   {
186     delete [] vbs;
187     vbs = new Vb*[pdu.vb_count];
188     if (vbs)
189       vbs_size = pdu.vb_count;
190     else
191     {
192       vbs_size = 0;
193       validity = false;
194       return *this;
195     }
196   }
197
198   // loop through and fill em up
199   for (int y = 0; y < pdu.vb_count; ++y)
200   {
201     vbs[y] = new Vb(*(pdu.vbs[y]));
202
203     if ((vbs[y]) && !vbs[y]->valid())
204     {
205       delete vbs[y];
206       vbs[y] = 0;
207     }
208
209     if (!vbs[y])
210     {
211       for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
212       validity = false;
213       return *this;
214     }
215   }
216
217   vb_count = pdu.vb_count;
218   return *this;
219 }
220
221 // append operator, appends a variable binding
222 Pdu& Pdu::operator+=(const Vb &vb)
223 {
224   if (!vb.valid())                return *this; // dont add invalid Vbs
225
226   if (vb_count + 1 > vbs_size)
227   {
228     if (!extend_vbs()) return *this;
229   }
230
231   vbs[vb_count] = new Vb(vb);  // add the new one
232
233   if (vbs[vb_count])   // up the vb count on success
234   {
235     if (vbs[vb_count]->valid())
236     {
237       ++vb_count;
238       validity = true;   // set up validity
239     }
240     else
241     {
242       delete vbs[vb_count];
243       vbs[vb_count] = 0;
244     }
245   }
246
247   return *this;        // return self reference
248 }
249
250 //=====================[ extract Vbs from Pdu ]==========================
251 int Pdu::get_vblist(Vb* pvbs, const int pvb_count) const
252 {
253   if ((!pvbs) || (pvb_count < 0) || (pvb_count > vb_count))
254     return false;
255
256   // loop through all vbs and assign to params
257   for (int z = 0; z < pvb_count; ++z)
258   {
259     pvbs[z] = *vbs[z];
260     if (!pvbs[z].valid())
261       return false;
262   }
263
264   return true;
265 }
266
267 //=====================[ deposit Vbs ]===================================
268 int Pdu::set_vblist(Vb* pvbs, const int pvb_count)
269 {
270   // if invalid then don't destroy
271   if (((!pvbs) && (pvb_count > 0)) ||
272       (pvb_count < 0))
273     return false;
274
275   // free up current vbs
276   for (int z = 0; z < vb_count; ++z)  delete vbs[z];
277   vb_count = 0;
278
279   // check for zero case
280   if (pvb_count == 0)
281   {
282     validity = true;
283     error_status = 0;
284     error_index = 0;
285     request_id = 0;
286     return false;
287   }
288
289   // allocate array
290   if (vbs_size < pvb_count)
291   {
292     delete [] vbs;
293     vbs = new Vb*[pvb_count];
294     if (vbs)
295       vbs_size = pvb_count;
296     else
297     {
298       vbs_size = 0;
299       validity = false;
300       return false;
301     }
302   }
303
304   // loop through all vbs and reassign them
305   for (int y = 0; y < pvb_count; ++y)
306   {
307     if (pvbs[y].valid())
308     {
309       vbs[y] = new Vb(pvbs[y]);
310       if ((vbs[y]) && !vbs[y]->valid())
311       {
312         delete vbs[y];
313         vbs[y] = 0;
314       }
315     }
316     else
317       vbs[y] = 0;
318
319     // check for errors
320     if (!vbs[y])
321     {
322       for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
323       validity = false;
324       return false;
325     }
326   }
327
328   vb_count = pvb_count;
329
330   // clear error status and index since no longer valid
331   // request id may still apply so don't reassign it
332   error_status = 0;
333   error_index = 0;
334   validity = true;
335
336   return true;
337 }
338
339 //===================[ get a particular vb ]=============================
340 // here the caller has already instantiated a vb object
341 // index is zero based
342 int Pdu::get_vb(Vb &vb, const int index) const
343 {
344    if (index < 0)         return false; // can't have an index less than 0
345    if (index >= vb_count) return false; // can't ask for something not there
346
347    vb = *vbs[index];   // asssign it
348
349    return vb.valid();
350 }
351
352 //===================[ set a particular vb ]=============================
353 int Pdu::set_vb(Vb &vb, const int index)
354 {
355   if (index < 0)         return false; // can't have an index less than 0
356   if (index >= vb_count) return false; // can't ask for something not there
357   if (!vb.valid())       return false; // don't set invalid vbs
358
359   Vb *victim = vbs[index]; // save in case new fails
360   vbs[index] = new Vb(vb);
361   if (vbs[index])
362   {
363     if (vbs[index]->valid())
364     {
365       delete victim;
366     }
367     else
368     {
369       delete vbs[index];
370       vbs[index] = victim;
371       return false;
372     }
373   }
374   else
375   {
376     vbs[index] = victim;
377     return false;
378   }
379   return true;
380 }
381
382 // trim off the last vb
383 int Pdu::trim(const int count)
384 {
385   // verify that count is legal
386   if ((count < 0) || (count > vb_count)) return false;
387
388   int lp = count;
389
390   while (lp != 0)
391   {
392     if (vb_count > 0)
393     {
394       delete vbs[vb_count-1];
395       vbs[vb_count-1] = 0;
396       vb_count--;
397     }
398     lp--;
399   }
400   return true;
401 }
402
403 // delete a Vb anywhere within the Pdu
404 int Pdu::delete_vb(const int p)
405 {
406   // position has to be in range
407   if ((p<0) || (p > vb_count - 1)) return false;
408
409   delete vbs[p];   // safe to remove it
410
411   for (int z = p; z < vb_count - 1; ++z)
412     vbs[z] = vbs[z+1];
413
414   vb_count--;
415
416   return true;
417 }
418
419
420 // Get the SNMPv1 trap address
421 int Pdu::get_v1_trap_address(GenAddress &address) const
422 {
423   if (v1_trap_address_set == false)
424     return false;
425
426   address = v1_trap_address;
427   return true;
428 }
429
430 // Set the SNMPv1 trap address
431 int Pdu::set_v1_trap_address(const Address &address)
432 {
433   v1_trap_address = address;
434   v1_trap_address_set = (v1_trap_address.valid() == true);
435
436   return v1_trap_address_set;
437 }
438
439 int Pdu::get_asn1_length() const
440 {
441   int length = 0;
442
443   // length for all vbs
444   for (int i = 0; i < vb_count; ++i)
445     length += vbs[i]->get_asn1_length();
446
447   // header for vbs
448   if      (length < 0x80)      length += 2;
449   else if (length <= 0xFF)     length += 3;
450   else if (length <= 0xFFFF)   length += 4;
451   else if (length <= 0xFFFFFF) length += 5;
452   else                         length += 6;
453
454   // req id, error status, error index
455   SnmpInt32 i32(request_id ? request_id : PDU_MAX_RID);
456   length += i32.get_asn1_length();
457   i32 = error_status;
458   length += i32.get_asn1_length();
459   i32 = error_index;
460   length += i32.get_asn1_length();
461     
462   // header for data_pdu
463   if      (length < 0x80)      length += 2;
464   else if (length <= 0xFF)     length += 3;
465   else if (length <= 0xFFFF)   length += 4;
466   else if (length <= 0xFFFFFF) length += 5;
467   else                         length += 6;
468
469 #ifdef _SNMPv3
470   // now the scopedpdu part sequence (4), context engine, id context name
471   length += 4 + 2 + context_engine_id.len() + 2 + context_name.len();
472
473   // An encrypted message is transported as an octet string 
474   if (security_level == SNMP_SECURITY_LEVEL_AUTH_PRIV)
475   {
476     // assume that encryption increases the data to a multiple of 16
477     int mod = length % 16;
478     if (mod) length += 16 - mod;
479
480     length += 4;
481   }
482 #endif
483
484   return length;
485 }
486
487 // extend the vbs array
488 bool Pdu::extend_vbs()
489 {
490   if (vbs_size == 0)
491   {
492     vbs = new Vb*[PDU_INITIAL_SIZE];
493     if (vbs)
494     {
495       vbs_size = PDU_INITIAL_SIZE;
496       return true;
497     }
498     else
499        return false;
500   }
501
502   Vb **tmp = vbs;
503   vbs = new Vb*[vbs_size * 2];
504   if (!vbs)
505   {
506     vbs = tmp;
507     return false;
508   }
509
510   for (int y = 0; y < vb_count; ++y)
511     vbs[y] = tmp[y];
512   vbs_size *= 2;
513   delete [] tmp;
514   return true;
515 }
516
517 // Clear all members of the object
518 void Pdu::clear()
519 {
520   error_status        = 0;
521   error_index         = 0;
522   request_id          = 0;
523   pdu_type            = 0;
524   notify_timestamp    = 0;
525   notify_id.clear();
526   notify_enterprise.clear();
527   v1_trap_address_set = false;
528   validity            = true;
529
530   for (int z = 0; z < vb_count; ++z)  delete vbs[z];
531   vb_count = 0;
532
533 #ifdef _SNMPv3
534   security_level    = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
535   message_id        = 0;
536   maxsize_scopedpdu = 0;
537   context_name.clear();
538   context_engine_id.clear();
539 #endif // _SNMPv3
540 }
541
542 // Does the type of response match the type of request
543 bool Pdu::match_type(const int request, const int response)
544 {
545   switch (request)
546   {
547     case sNMP_PDU_GET:
548     case sNMP_PDU_GETNEXT:
549     case sNMP_PDU_SET:
550     case sNMP_PDU_GETBULK:
551     case sNMP_PDU_INFORM:
552     {
553       if ((response == sNMP_PDU_RESPONSE) ||
554           (response == sNMP_PDU_REPORT))
555         return true;
556       if ((response == sNMP_PDU_GET) ||
557           (response == sNMP_PDU_GETNEXT) ||
558           (response == sNMP_PDU_SET) ||
559           (response == sNMP_PDU_GETBULK) ||
560           (response == sNMP_PDU_INFORM) ||
561           (response == sNMP_PDU_V1TRAP) ||
562           (response == sNMP_PDU_TRAP))
563       {
564         debugprintf(0, "Unknown response pdu type (%d).", response);
565       }
566       return false;
567     }
568     case sNMP_PDU_REPORT:
569     case sNMP_PDU_RESPONSE:
570     case sNMP_PDU_V1TRAP:
571     case sNMP_PDU_TRAP:
572     {
573       return false;
574     }
575     default:
576     {
577       debugprintf(0, "Unknown request pdu type (%d).", request);
578       return false;
579     }
580   }
581 }
582
583 #ifdef SNMP_PP_NAMESPACE
584 }; // end of namespace Snmp_pp
585 #endif