]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/usm_v3.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / usm_v3.cpp
1 /*_############################################################################
2   _## 
3   _##  usm_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 usm_v3_cpp_version[]="@(#) SNMP++ $Id: usm_v3.cpp 1788 2010-07-23 20:02:38Z katz $";
30
31 #if defined(_AIX) || defined(__APPLE__)
32 #include <unistd.h>
33 #endif
34 #ifdef __MINGW32__
35 #include <io.h>
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41
42 #include "snmp_pp/config_snmp_pp.h"
43
44 #ifdef _SNMPv3
45
46 #include "snmp_pp/v3.h"
47 #include "snmp_pp/usm_v3.h"
48 #include "snmp_pp/auth_priv.h"
49 #include "snmp_pp/reentrant.h"
50 #include "snmp_pp/mp_v3.h"
51 #include "snmp_pp/asn1.h"
52 #include "snmp_pp/vb.h"
53 #include "snmp_pp/pdu.h"
54 #include "snmp_pp/log.h"
55
56 #ifdef SNMP_PP_NAMESPACE
57 namespace Snmp_pp {
58 #endif
59
60 // Use locking on access methods in an multithreading enviroment.
61 #ifdef _THREADS
62 #define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(*this)
63 #define BEGIN_REENTRANT_CODE_BLOCK_CONST  \
64           SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, this)))
65 #define BEGIN_AUTO_LOCK(obj) SnmpSynchronize auto_lock(*obj)
66 #else
67 #define BEGIN_REENTRANT_CODE_BLOCK
68 #define BEGIN_REENTRANT_CODE_BLOCK_CONST
69 #define BEGIN_AUTO_LOCK(obj)
70 #endif
71
72 #ifndef min
73 #define min(a,b) ( (a) < (b) ? (a) : (b) )
74 #endif
75
76 #define MAX_LINE_LEN 2048  // Max line length in usm user files
77
78 // structure for key update
79 struct UsmKeyUpdate
80 {
81   OctetStr engineID;
82   OctetStr securityName;
83   OctetStr newPassword;
84   OctetStr newKey;
85   int type;
86 };
87
88 /* ------------------------- UsmTimeTable --------------------------*/
89
90 /**
91  * This class provides a table for the time values (engine boots and
92  * engine time) for snmp entities that are identified through their
93  * engine id.
94  *
95  * @author Jochen Katz
96  */
97 class USMTimeTable : public SnmpSynchronized
98 {
99 public:
100
101   /**
102    * Initialize the usmTimeTable.
103    *
104    * The usmTimeTable stores for each known engineID the engineBoots
105    * and the difference to the local system time
106    *
107    * @param owner        - Pointer to the USM object that created this table
108    * @param engine_boots - The new value for the snmpEngineBoots counter
109    * @param result       - OUT: Result of the creation of the table
110    */
111   USMTimeTable(const USM *owner, const unsigned int engine_boots, int &result);
112
113   ~USMTimeTable();
114
115   /**
116    * Add a new entry to the usmTimeTable. The caller is responsible for
117    * not adding an engineID twice.
118    *
119    * @param engine_id    - The engineID of the SNMP entity
120    * @param engine_boots - The engine boot counter
121    * @param engine_time  - The engine time
122    *
123    * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
124    */
125   int add_entry(const OctetStr &engine_id,
126                 const long int engine_boots, const long int engine_time);
127
128   /**
129    * Delete this engine id from the table.
130    *
131    * @param engine_id    - The engineID of the SNMP entity
132    *
133    * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
134    */
135   int delete_entry(const OctetStr &engine_id);
136
137   /**
138    * Return engineBoots and engineTime for a given engineID
139    *
140    * @param engine_id    - The engineID of the SNMP entity
141    * @param engine_boots - OUT: boot counter (0 if not found)
142    * @param engine_time  - OUT: engine time (0 if not found)
143    *
144    * @return - SNMPv3_USM_ERROR (not initialized),
145    *           SNMPv3_USM_OK (entry found, values are filled)
146    *           SNMPv3_USM_UNKNOWN_ENGINEID ( not found)
147    */
148   int get_time(const OctetStr &engine_id,
149                long int &engine_boots, long int &engine_time);
150
151   /**
152    * Return the engineBoots and engineTime of this snmp entity.
153    *
154    * @param engine_boots - OUT: boot counter (0 if not found)
155    * @param engine_time  - OUT: engine time (0 if not found)
156    *
157    * @return - SNMPv3_USM_ERROR (not initialized),
158    *           SNMPv3_USM_OK (entry found, values are filled)
159    */
160   int get_local_time(long int &engine_boots, long int &engine_time);
161
162   /**
163    * Return the engineBoots value of this snmp entity.
164    *
165    * @return - engine_boots value if initialized, 0 else
166    */
167   unsigned long get_local_boots()
168     { return (table ? table[0].engine_boots : 0); };
169
170   /**
171    * Return the engineTime value of this snmp entity.
172    *
173    * @return - engine_time value if initialized, 0 else
174    */
175   unsigned long get_local_time();
176
177   /**
178    * Check if the given values for engineBoots and engineTime are
179    * in the time window. If the time values are ok, the entry in
180    * the usmTimeTable is updated with the given time values.
181    *
182    * @param engine_id    - The engineID of the SNMP entity
183    * @param engine_boots - The boot counter
184    * @param engine_time  - The engine time
185    *
186    * @return - SNMPv3_USM_ERROR (not initialized),
187    *           SNMPv3_USM_NOT_IN_TIME_WINDOW,
188    *           SNMPv3_USM_OK (time ok),
189    *           SNMPv3_USM_UNKNOWN_ENGINEID
190    */
191   int check_time(const OctetStr &engine_id,
192                  const long int engine_boots, const long int engine_time);
193
194   /**
195    * Check if the given engineID is known: If the USM is in
196    * the discovery mode, all engineIDs are accepted and entries
197    * in the timeTable are created.
198    *
199    * @param engine_id - engine id to check
200    *
201    * @return - SNMPv3_USM_ERROR (not found and no discovery)
202    *           SNMPv3_USM_OK (found or discovery set)
203    */
204   int check_engine_id(const OctetStr &engine_id);
205
206 private:
207   struct Entry_T
208   {
209     unsigned char engine_id[MAXLENGTH_ENGINEID];
210     int engine_id_len;
211     long int engine_boots;
212     long int time_diff;
213     long int latest_received_time;
214   };
215
216   struct Entry_T *table; ///< Array of entries
217   const USM *usm;  ///< Pointer to the USM, this table belongs to
218   int max_entries; ///< the maximum number of entries
219   int entries;     ///< the current amount of entries
220 };
221
222
223 /* ------------------------- UsmUserNameTable ----------------------*/
224
225 /**
226  * This class holds USM users with PASSWORDS.
227  *
228  * Whenever the USM has to process a message of a user that is not
229  * found in the USMUserTable, this table is queried for the
230  * properties of the user. If the user is found, a localized entry
231  * for the USMUserTable is created and used for processing the message.
232  */
233 class USMUserNameTable : public SnmpSynchronized
234 {
235 public:
236   USMUserNameTable(int &result);
237   ~USMUserNameTable();
238
239   /**
240    * Add a new user to the usmUserNameTable. If the userName is already
241    * known, the old entry is replaced.
242    *
243    * It is not recommended to add users with userName != securityName.
244    *
245    * @param user_name     - Unique userName
246    * @param security_name - Unique securityName
247    * @param auth_proto    - Possible values are:
248    *                        SNMP_AUTHPROTOCOL_NONE,
249    *                        SNMP_AUTHPROTOCOL_HMACMD5,
250    *                        SNMP_AUTHPROTOCOL_HMACSHA
251    * @param priv_proto    - Possible values are:
252    *                        SNMP_PRIVPROTOCOL_NONE,
253    *                        SNMP_PRIVPROTOCOL_DES,
254    *                        SNMP_PRIVPROTOCOL_IDEA
255    * @param auth_pass     - Secret password for authentication
256    * @param priv_pass     - Secret password for privacy
257    *
258    * @return - SNMPv3_USM_OK or
259    *           SNMP_v3_USM_ERROR (memory error, not initialized)
260    */
261   int add_entry(const OctetStr& user_name,
262                 const OctetStr& security_name,
263                 const long int  auth_proto,
264                 const long int  priv_proto,
265                 const OctetStr& auth_pass,
266                 const OctetStr& priv_pass);
267
268   /**
269    * Delete all occurences of the user with the given securityName
270    * from the table.
271    *
272    * @param security_name - the securityName of the user
273    *
274    * @return - SNMPv3_USM_OK, SNMPv3_USM_ERROR (not initialized)
275    */
276   int delete_security_name(const OctetStr& security_name);
277
278   /**
279    * Get the entry with the given securityName from the usmUserNameTable
280    *
281    * @note Use lock() and unlock() for thread synchronizytion.
282    *
283    * @param security_name     -
284    *
285    * @return - pointer to the struct or NULL (no need to delete anything)
286    */
287   const struct UsmUserNameTableEntry* get_entry(const OctetStr &security_name);
288
289   /**
290    * Get a clone of the entry with the given securityName from the usmUserNameTable
291    *
292    * @note call delete_cloned_entry() with the retruned pointer.
293    *
294    * @param security_name     -
295    *
296    * @return - pointer to the struct or NULL
297    */
298   struct UsmUserNameTableEntry* get_cloned_entry(const OctetStr &security_name);
299
300   /**
301    * Deletes a entry created through get_cloned_entry().
302    *
303    * @param entry     -
304    */
305   void delete_cloned_entry(struct UsmUserNameTableEntry* &entry);
306
307   /**
308    * Get the securityName from a userName
309    *
310    * @param user_name         -
311    * @param user_name_len     -
312    * @param security_name     - Buffer for the securityName
313    *
314    * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
315    *           SNMPv3_USM_OK
316    */
317   int get_security_name(const unsigned char *user_name,
318                         const long int user_name_len,
319                         OctetStr &security_name);
320
321   /**
322    * Get the userName from a securityName
323    *
324    * @param user_name         - Buffer for the userName
325    * @param user_name_len     - Has to be set to the max length of the
326    *                            buffer. Is set to the length of the found
327    *                            securityName or to 0 if not found.
328    * @param security_name     -
329    * @param security_name_len -
330    *
331    * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
332    *           SNMPv3_USM_OK
333    */
334   int get_user_name(unsigned char *user_name, long int *user_name_len,
335                     const unsigned char *security_name,
336                     const long int security_name_len);
337
338   /**
339    * Save all entries into a file.
340    */
341   int save_to_file(const char *name, AuthPriv *ap);
342
343   /**
344    * Load the table from a file.
345    */
346   int load_from_file(const char *name, AuthPriv *ap);
347
348   const UsmUserNameTableEntry *peek_first() const
349     { if (entries > 0) return table; return 0; };
350
351   const UsmUserNameTableEntry *peek_next(const UsmUserNameTableEntry *e) const;
352
353 private:
354   struct UsmUserNameTableEntry *table;
355
356   int max_entries; ///< the maximum number of entries
357   int entries;     ///< the current amount of entries
358 };
359
360
361 /* ---------------------------- UsmUserTable ------------------- */
362
363 /**
364  * This class holds USM users with localized KEYS.
365  */
366 class USMUserTable : public SnmpSynchronized
367 {
368 public:
369   USMUserTable(int &result);
370
371   ~USMUserTable();
372
373   /**
374    * Get the number of valid entries in the table.
375    *
376    * @return - number of entries
377    */
378   int size() const { return entries; };
379
380   /**
381    * Get the userName from a securityName
382    *
383    * @param user_name     - Buffer for the userName
384    * @param user_name_len - Has to be set to the max length of the
385    *                        buffer. Is set to the length of the found
386    *                        securityName or to 0 if not found.
387    * @param sec_name      -
388    * @param sec_name_len  -
389    *
390    * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
391    *           SNMPv3_USM_OK
392    */
393   int get_user_name(unsigned char *user_name, long int *user_name_len,
394                     const unsigned char *sec_name, const long sec_name_len);
395
396   /**
397    * Get the sec_name from a userName
398    *
399    * @param user_name       -
400    * @param user_name_len   -
401    * @param sec_name        - Object for the security name
402    *
403    * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
404    *           SNMPv3_USM_OK
405    */
406   int get_security_name(const unsigned char *user_name,
407                         const long user_name_len,
408                         OctetStr &sec_name);
409
410   /**
411    * Delete all entries of this user from the usmUserTable
412    *
413    * @param user_name - The userName that should be deleted
414    *
415    * @return - SNMPv3_USM_ERROR (not initialized),
416    *           SNMPv3_USM_OK (user deleted or not in table)
417    */
418   int delete_entries(const OctetStr& user_name);
419
420   /**
421    * Delete all entries with this engine id from the table.
422    *
423    * @param engine id - The engine id
424    *
425    * @return - SNMPv3_USM_ERROR (not initialized),
426    *           SNMPv3_USM_OK (user deleted or not in table)
427    */
428   int delete_engine_id(const OctetStr& engine_id);
429
430   /**
431    * Delete the entry with the given userName and engineID
432    * from the usmUserTable
433    *
434    * @param engine_id  - The engine id
435    * @param user_name - The userName that should be deleted
436    *
437    * @return - SNMPv3_USM_ERROR (not initialized),
438    *           SNMPv3_USM_OK (user deleted or not in table)
439    */
440   int delete_entry(const OctetStr& engine_id, const OctetStr& user_name);
441
442   /**
443    * Protected (for agent++):
444    *
445    * Get the user at the specified position of the usmUserTable.
446    *
447    * @note Use lock() and unlock() for thread synchronization.
448    *
449    * @param number - get the entry at position number (1...)
450    *
451    * @return - a pointer to the structure or NULL if number is out
452    *           of range (no need to delete anything)
453    */
454   const struct UsmUserTableEntry *get_entry(const int number);
455
456   /**
457    * Get a user of the usmUserTable.
458    *
459    * @note Use lock() and unlock() for thread synchronization.
460    *
461    * @param engine_id - Get a user for this engine id
462    * @param sec_name  - Get the user with this security name
463    *
464    * @return - a pointer to the structure or NULL if the user is not
465    *           found (no need to delete anything)
466    */
467   const struct UsmUserTableEntry *get_entry(const OctetStr &engine_id,
468                                             const OctetStr &sec_name);
469
470   /**
471    * Get a user of the usmUserTable.
472    *
473    * @note call delete_cloned_entry() with the retruned pointer.
474    *
475    * @param engine_id - Get a user for this engine id
476    * @param sec_name  - Get the user with this security name
477    *
478    * @return - a pointer to the structure or NULL if the user is not
479    *           found
480    */
481   struct UsmUserTableEntry *get_cloned_entry(const OctetStr &engine_id,
482                                              const OctetStr &sec_name);
483
484   /**
485    * Deletes a entry created through get_cloned_entry().
486    *
487    * @param entry     -
488    */
489   void delete_cloned_entry(struct UsmUserTableEntry* &entry);
490
491   /**
492    * Get a user of the usmUserTable.
493    *
494    * There could be more than one entry with the given
495    * sec_name. Always the first entry that is found is returned.
496    *
497    * @note Use lock() and unlock() for thread synchronization.
498    *
499    * @param sec_name - security name to search for
500    *
501    * @return - a pointer to the structure or NULL if the user is not
502    *           found (no need to delete anything)
503    */
504   const struct UsmUserTableEntry *get_entry(const OctetStr &sec_name);
505
506   /**
507    * Public:
508    *
509    * Add or replace a user in the usmUserTable. The usmUserTable stores
510    * users with their localized keys.
511    *
512    * @param engine_id     - The engine_id, the key was localized with
513    * @param user_name     - The name of the user (in the USM)
514    * @param sec_name      - The security name of the user, this name
515    *                                is the same for all securityModels
516    * @param auth_proto    - Possible values are:
517    *                                SNMP_AUTHPROTOCOL_NONE,
518    *                                SNMP_AUTHPROTOCOL_HMACMD5,
519    *                                SNMP_AUTHPROTOCOL_HMACSHA
520    * @param auth_key      - The key used for authentications
521    * @param priv_proto    - Possible values are:
522    *                                SNMP_PRIVPROTOCOL_NONE,
523    *                                SNMP_PRIVPROTOCOL_DES,
524    *                                SNMP_PRIVPROTOCOL_IDEA
525    * @param priv_key      - The key used for privacy
526    *
527    * @return - SNMPv3_USM_OK
528    *           SNMP_v3_USM_ERROR (not initialized, no memory)
529    */
530   int add_entry(const OctetStr &engine_id,
531                 const OctetStr &user_name,  const OctetStr &sec_name,
532                 const long int  auth_proto, const OctetStr &auth_key,
533                 const long int  priv_proto, const OctetStr &priv_key);
534
535   /**
536    * Replace a localized key of the user and engine_id in the
537    * usmUserTable.
538    *
539    * @param user_name     - The name of the user in the USM
540    * @param engine_id     - Change the localized key for the SNMP
541    *                        entity with this engine_id
542    * @param new_key       - The new key
543    * @param key_type      - AUTHKEY, OWNAUTHKEY, PRIVKEY or OWNPRIVKEY
544    *
545    * @return - SNMPv3_USM_ERROR (no such entry or not initialized),
546    *           SNMPv3_USM_OK
547    */
548   int update_key(const OctetStr &user_name,
549                  const OctetStr &engine_id,
550                  const OctetStr &new_key,
551                  const int key_type);
552
553   /**
554    * Save all entries into a file.
555    */
556   int save_to_file(const char *name, AuthPriv *ap);
557
558   /**
559    * Load the table from a file.
560    */
561   int load_from_file(const char *name, AuthPriv *ap);
562
563   const UsmUserTableEntry *peek_first() const
564     { if (entries > 0) return table; return 0; };
565
566   const UsmUserTableEntry *peek_next(const UsmUserTableEntry *e) const;
567
568 private:
569   void delete_entry(const int nr);
570
571   struct UsmUserTableEntry *table;
572
573   int max_entries; ///< the maximum number of entries
574   int entries;     ///< the current amount of entries
575 };
576
577
578
579 struct UsmSecurityParameters {
580   unsigned char  msgAuthoritativeEngineID[MAXLENGTH_ENGINEID];
581   long int       msgAuthoritativeEngineIDLength;
582   long int       msgAuthoritativeEngineBoots;
583   long int       msgAuthoritativeEngineTime;
584   unsigned char  msgUserName[MAXLEN_USMUSERNAME];
585   long int       msgUserNameLength;
586   unsigned char *msgAuthenticationParameters;
587   long int       msgAuthenticationParametersLength;
588   unsigned char *msgPrivacyParameters;
589   unsigned int   msgPrivacyParametersLength;
590 };
591
592
593
594
595 struct SecurityStateReference
596 {
597   unsigned char  msgUserName[MAXLEN_USMUSERNAME]; int msgUserNameLength;
598   unsigned char *securityName;                    int securityNameLength;
599   unsigned char *securityEngineID;                int securityEngineIDLength;
600   int authProtocol;
601   unsigned char* authKey;                         int authKeyLength;
602   int privProtocol;
603   unsigned char* privKey;                         int privKeyLength;
604   int securityLevel;
605 };
606
607
608
609
610 void USM::inc_stats_unsupported_sec_levels()
611 {
612   if (usmStatsUnsupportedSecLevels == MAXUINT32)
613     usmStatsUnsupportedSecLevels = 0;
614   else
615     usmStatsUnsupportedSecLevels++;
616 }
617
618 void USM::inc_stats_not_in_time_windows()
619 {
620   if (usmStatsNotInTimeWindows == MAXUINT32)
621     usmStatsNotInTimeWindows = 0;
622   else
623     usmStatsNotInTimeWindows++;
624 }
625
626 void USM::inc_stats_unknown_user_names()
627 {
628   if (usmStatsUnknownUserNames == MAXUINT32)
629     usmStatsUnknownUserNames = 0;
630   else
631     usmStatsUnknownUserNames++;
632 }
633
634 void USM::inc_stats_unknown_engine_ids()
635 {
636   if (usmStatsUnknownEngineIDs == MAXUINT32)
637     usmStatsUnknownEngineIDs = 0;
638   else
639     usmStatsUnknownEngineIDs++;
640 }
641
642 void USM::inc_stats_wrong_digests()
643 {
644   if (usmStatsWrongDigests == MAXUINT32)
645     usmStatsWrongDigests = 0;
646   else
647     usmStatsWrongDigests++;
648 }
649
650 void USM::inc_stats_decryption_errors()
651 {
652   if (usmStatsDecryptionErrors == MAXUINT32)
653     usmStatsDecryptionErrors = 0;
654   else
655     usmStatsDecryptionErrors++;
656 }
657
658
659 void USM::delete_sec_state_reference(struct SecurityStateReference *ssr)
660 {
661   if (ssr)
662   {
663     ssr->msgUserName[0] = 0;
664     if (ssr->securityName) delete [] ssr->securityName;
665     if (ssr->securityEngineID) delete [] ssr->securityEngineID;
666     if (ssr->authKey)
667     {
668       memset(ssr->authKey, 0, ssr->authKeyLength);
669       delete [] ssr->authKey;
670     }
671     if (ssr->privKey)
672     {
673       memset(ssr->privKey, 0, ssr->privKeyLength);
674       delete [] ssr->privKey;
675     }
676   }
677   delete ssr;
678 }
679
680 struct SecurityStateReference *USM::get_new_sec_state_reference()
681 {
682   struct SecurityStateReference *res = new SecurityStateReference;
683
684   if (!res)
685     return NULL;
686
687   memset(res, 0, sizeof(struct SecurityStateReference));
688   return res;
689 }
690
691
692 USM::USM(unsigned int engine_boots, const OctetStr &engine_id,
693          const v3MP *v3_mp,
694          unsigned int *msgID, int &result)
695   : local_snmp_engine_id (engine_id),
696     v3mp (v3_mp),
697
698     discovery_mode (TRUE),
699
700     usmStatsUnsupportedSecLevels (0),
701     usmStatsNotInTimeWindows     (0),
702     usmStatsUnknownUserNames     (0),
703     usmStatsUnknownEngineIDs     (0),
704     usmStatsWrongDigests         (0),
705     usmStatsDecryptionErrors     (0),
706
707     usm_add_user_cb (0)
708 {
709   auth_priv = new AuthPriv(result);
710   if (result != SNMPv3_USM_OK)
711     return;
712   auth_priv->add_default_modules();
713
714   usm_user_name_table = new USMUserNameTable(result);
715   if (result != SNMPv3_USM_OK)
716     return;
717
718   usm_user_table = new USMUserTable(result);
719   if (result != SNMPv3_USM_OK)
720     return;
721
722 #ifdef _TEST
723
724   printf("\nTesting 3DES starts\n\n");
725   OctetStr engineId = OctetStr::from_hex_string("00 00 00 00 00 00 "
726                                                 "00 00 00 00 00 02");
727
728   OctetStr oldKey, newKey, delta;
729   oldKey.set_len(64);
730   newKey.set_len(64);
731   unsigned int key_len=64;
732
733   debughexcprintf(0,"engineID", engineId.data(), engineId.len());
734
735   auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
736                                  SNMP_PRIVPROTOCOL_3DESEDE,
737                                  (unsigned char*)"maplesyrup", 10,
738                                  engineId.data(), engineId.len(),
739                                  oldKey.data(),
740                                  &key_len);
741   oldKey.set_len(key_len);
742   key_len=64;
743   auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
744                                  SNMP_PRIVPROTOCOL_3DESEDE,
745                                  (unsigned char*)"newsyrup", 8,
746                                  engineId.data(), engineId.len(),
747                                  newKey.data(),
748                                  &key_len);
749   newKey.set_len(key_len);
750
751   OctetStr expectedKey = OctetStr::from_hex_string("78 e2 dc ce 79 d5 94 03 b5 8c 1b ba a5 bf f4 63 91 f1 cd 25 97 74 35 55 f9 fc f9 4a c3 e7 e9 22");
752
753   if (newKey != expectedKey)
754   {
755       printf("newKey != expectedKey\n");
756       printf("newKey:   %s\n", newKey.get_printable_hex());
757       printf("expected: %s\n", expectedKey.get_printable_hex());
758   }
759
760   auth_priv->get_keychange_value(SNMP_AUTHPROTOCOL_HMACSHA,
761                                  oldKey, newKey, delta);
762
763   OctetStr expectedDelta = OctetStr::from_hex_string(
764       "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
765       "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
766       "ce 13 28 fb 9a 9c 19 ce c1 51 a3 5a 77 f9 20 39 "
767       "ca ff 00 c9 b3 9b 19 a0 5e 01 75 55 94 37 6a 57");
768
769   if (delta != expectedDelta)
770   {
771       printf("delta != expectedDelta\n");
772       printf("delta:    %s\n", delta.get_printable_hex());
773       printf("expected: %s\n", expectedDelta.get_printable_hex());
774   }
775
776   printf("\nTesting 3DES finished\n\n");
777
778   printf(" Testing DES:\n");
779   PrivDES pd;
780   pp_uint64 testsalt=0xbabec0de;
781   pd.set_salt(&testsalt);
782
783   const char *desplaintext[10];
784   desplaintext[0] = "abcdefghijklmnopqrstuvwxyz123456";
785   desplaintext[1] = "abcdefghijklmnopqrstuvwxyz1234567";
786   desplaintext[2] = "abcdefghijklmnopqrstuvwxyz12345678";
787   desplaintext[3] = "abcdefghijklmnopqrstuvwxyz123456789";
788   desplaintext[4] = "abcdefghijklmnopqrstuvwxyz123456789A";
789   desplaintext[5] = "abcdefghijklmnopqrstuvwxyz123456789AB";
790   desplaintext[6] = "abcdefghijklmnopqrstuvwxyz123456789ABC";
791   desplaintext[7] = "abcdefghijklmnopqrstuvwxyz123456789ABCD";
792   desplaintext[8] = "abcdefghijklmnopqrstuvwxyz123456789ABCDE";
793   desplaintext[9] = "abcdefghijklmnopqrstuvwxyz123456789ABCDEF";
794
795   unsigned char desencrypted[80];
796   unsigned char desdecrypted[80];
797   unsigned char desprivparams[8];
798   unsigned char deskey[17] = "illegal_des_key!";
799
800   for (int i=0; i<9; i++)
801   {
802       unsigned int encrypt_len = 80;
803       unsigned int decrypt_len = 80;
804       unsigned int desprivparamslen = 8;
805
806       memset(desencrypted, 'x', 80);
807       memset(desdecrypted, 'y', 80);
808
809       debughexcprintf(1, "Plaintext", (unsigned char*)desplaintext[i],
810                       strlen(desplaintext[i]));
811
812       int res = pd.encrypt(deskey, 16,
813                            (unsigned char*)desplaintext[i],
814                            strlen(desplaintext[i]),
815                            desencrypted, &encrypt_len,
816                            desprivparams, &desprivparamslen,
817                            0x2340abcd, 0);
818
819       printf("%d: Result of encryption is %d\n", i, res);
820       debughexcprintf(1, "Encrypted", desencrypted, encrypt_len);
821
822       res = pd.decrypt(deskey, 16,
823                        desencrypted, encrypt_len,
824                        desdecrypted, &decrypt_len,
825                        desprivparams, desprivparamslen,
826                        0x2340abcd, 0);
827       printf("%d: Result of decryption is %d\n", i, res);
828       debughexcprintf(1, "Decrypted", desdecrypted, decrypt_len);
829
830       if (memcmp(desplaintext[i], desdecrypted, strlen(desplaintext[i])))
831           printf("\n********* FAILED **********\n");
832       else
833           printf("\nOK\n");
834
835   }
836
837
838
839 #if 0
840   printf(" Testing SHA:\n");
841
842   // test password2key-algor:
843   unsigned char keysha[50];
844   auth_priv->password_to_key_auth(...(unsigned char*)"maplesyrup",10,
845                      (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keysha);
846   printf("Output of PasswordToKey-algorithm for SHA:\n");
847   for (int i=0; i< 20; i++) {
848     printf("%02X ", keysha[i]);
849     if ((i+1)%4==0) printf(" ");
850     if ((i+1)%16==0) printf("\n");
851   }
852   printf("\nOutput should be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
853   printf("66 95 fe bc  92 88 e3 62  82 23 5f c7  15 1f 12 84\n97 b3 8f 3f\n");
854   printf("\nTesting MD5:\n");
855   unsigned char keymd5[50];
856   apPasswordToKeyMD5((unsigned char*)"maplesyrup",10,
857                      (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keymd5);
858   printf("Output of PasswordToKey-algorithm for MD5:\n");
859   for (int i=0; i< 16; i++) {
860     printf("%02X ", keymd5[i]);
861     if ((i+1)%4==0) printf(" ");
862     if ((i+1)%16==0) printf("\n");
863   }
864   printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
865   printf("52 6f 5e ed  9f cc e2 6f  89 64 c2 93  07 87 d8 2b\n");
866
867   printf("\nTesting IDEA:\n");
868   unsigned char source[35] = "Hallo, das ist ein test!", encrypted[35], decrypted[35], params[8];
869   int len_encrypted = 35, len_decrypted = 35;
870   apIDEAEncryptData((unsigned char*)"1234567890abcdef",
871                     source, 25, encrypted, &len_encrypted, params);
872
873   apIDEADecryptData((unsigned char*)"1234567890abcdef",
874                     encrypted, len_encrypted,
875                      decrypted, &len_decrypted, params);
876
877
878   printf("params:\n");
879   for (int i=0; i< 8; i++) {
880     printf("%02X ", params[i]);
881     if ((i+1)%4==0) printf(" ");
882     if ((i+1)%16==0) printf("\n");
883   }
884   printf("\nsource:\n");
885   for (int i=0; i< 25; i++) {
886     printf("%02X ", source[i]);
887     if ((i+1)%4==0) printf(" ");
888     if ((i+1)%16==0) printf("\n");
889   }
890   printf("\n");
891   printf("encrypted:\n");
892   for (int i=0; i< 25; i++) {
893     printf("%02X ", encrypted[i]);
894     if ((i+1)%4==0) printf(" ");
895     if ((i+1)%16==0) printf("\n");
896   }
897   printf("\n");
898   printf("decrypted:\n");
899   for (int i=0; i< 25; i++) {
900     printf("%02X ", decrypted[i]);
901     if ((i+1)%4==0) printf(" ");
902     if ((i+1)%16==0) printf("\n");
903   }
904   printf("\n");
905   for (int i=0; i<25; i++)
906     if (source[i]!=decrypted[i]) {
907       printf("\n*** source != decrypted ****\n\n");
908       break;
909     }
910
911   // test keyUpdate md5
912   printf("\n Test KeyUpdate Algorithm:\n");
913   printf("Test MD5:\n");
914   OctetStr oldKey = OctetStr(keymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5);
915
916   unsigned char newkeymd5[50];
917   apPasswordToKeyMD5((unsigned char*)"newsyrup",8,
918                      (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeymd5);
919   printf("Output of PasswordToKey-algorithm for MD5:\n");
920   for (int i=0; i< 16; i++) {
921     printf("%02X ", newkeymd5[i]);
922     if ((i+1)%4==0) printf(" ");
923     if ((i+1)%16==0) printf("\n");
924   }
925   printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
926   printf("87 02 1d 7b  d9 d1 01 ba  05 ea 6e 3b  f9 d9 bd 4a\n");
927   OctetStr result;
928   apNewKey(oldKey, OctetStr(newkeymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5),
929             result, SNMPv3_usmHMACMD5AuthProtocol);
930
931   // test keyUpdate sha (auth)
932   printf("\nTest SHA for authPassword:\n");
933   oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_SHA);
934
935   unsigned char newkeysha[50];
936   apPasswordToKeySHA((unsigned char*)"newsyrup",8,
937                      (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeysha);
938   printf("Output of PasswordToKey-algorithm for sha:\n");
939   for (int i=0; i< SNMPv3_AP_OUTPUT_LENGTH_SHA; i++) {
940     printf("%02X ", newkeysha[i]);
941     if ((i+1)%4==0) printf(" ");
942     if ((i+1)%16==0) printf("\n");
943   }
944   printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
945   printf("78 e2 dc ce  79 d5 94 03  b5 8c 1b ba  a5 bf f4 63 \n91 f1 cd 25\n");
946
947   apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_SHA),
948             result, SNMPv3_usmHMACSHAAuthProtocol);
949   // test keyUpdate sha (privPassword DES)
950   printf("\nTest SHA for privPassword:\n");
951
952   oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_MD5);
953   apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_MD5),
954             result, SNMPv3_usmHMACSHAAuthProtocol);
955   printf("Result should be:\n");
956   printf("00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00\n");
957   printf("7e f8 d8 a4  c9 cd b2 6b  47 59 1c d8  52 ff 88 b5\n");
958 #endif
959   /* test AES key extension algorithm */
960   unsigned char key_sha[SNMPv3_USM_MAX_KEY_LEN];
961   unsigned int key_sha_len = SNMPv3_USM_MAX_KEY_LEN;
962
963   int res = auth_priv->password_to_key_priv(
964     SNMP_AUTHPROTOCOL_HMACSHA,
965     SNMP_PRIVPROTOCOL_AES256,
966     (unsigned char*)"maplesyrup", 10,
967     (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2", 12,
968     key_sha, &key_sha_len);
969
970   debugprintf(0, "aes key extension result %i, key_sha_len = %i.",
971               res, key_sha_len);
972   debughexcprintf(0, "key_sha", key_sha, key_sha_len);
973
974   unsigned char pt[56] = "This is a secret message, nobody is allowed to read it!";
975   unsigned char *plaintext = pt;
976   unsigned char ct[56];
977   unsigned char *cipher = ct;
978   unsigned int cipherlen = 56;
979   unsigned char privpar[8];
980   unsigned int privparlen = 8;
981
982   Priv *priv = auth_priv->get_priv(SNMP_PRIVPROTOCOL_AES256);
983   pp_uint64 salt = 0;
984   priv->set_salt(&salt);
985   auth_priv->encrypt_msg(SNMP_PRIVPROTOCOL_AES256,
986                          key_sha, key_sha_len,
987                          plaintext, 55, cipher, &cipherlen,
988                          privpar, &privparlen,
989                          0xdeadc0deUL, 0xbeefdedeUL);
990
991   auth_priv->decrypt_msg(SNMP_PRIVPROTOCOL_AES256,
992                          key_sha, key_sha_len,
993                          cipher, 55, plaintext, &cipherlen,
994                          privpar, privparlen,
995                          0xdeadc0deUL, 0xbeefdedeUL);
996
997 #endif // _TEST
998
999   usm_time_table = new USMTimeTable(this, engine_boots, result);
1000   if (result != SNMPv3_USM_OK)
1001     return;
1002
1003   *msgID = (engine_boots & 0x7FFF) << 16;
1004 }
1005
1006 USM::~USM()
1007 {
1008   if (usm_time_table)
1009     delete usm_time_table;
1010   usm_time_table = NULL;
1011
1012   if (usm_user_table)
1013     delete usm_user_table;
1014   usm_user_table = NULL;
1015
1016   if (usm_user_name_table)
1017   {
1018     delete usm_user_name_table;
1019     usm_user_name_table = NULL;
1020   }
1021
1022   if (auth_priv)
1023   {
1024     delete auth_priv;
1025     auth_priv = NULL;
1026   }
1027 }
1028
1029 // Delete this engine id form all USM tables (users and engine time).
1030 int USM::remove_engine_id(const OctetStr &engine_id)
1031 {
1032   int retval1, retval2;
1033
1034   retval1 = usm_time_table->delete_entry(engine_id);
1035
1036   retval2 = usm_user_table->delete_entries(engine_id);
1037
1038   if ((retval1 == SNMPv3_USM_ERROR) ||
1039       (retval2 == SNMPv3_USM_ERROR))
1040     return SNMPv3_USM_ERROR;
1041
1042   return SNMPv3_USM_OK;
1043 }
1044
1045 // Delete the time information for the given engine id
1046 int USM::remove_time_information(const OctetStr &engine_id)
1047 {
1048   if (usm_time_table->delete_entry(engine_id) == SNMPv3_USM_ERROR)
1049     return SNMPv3_USM_ERROR;
1050
1051   return SNMPv3_USM_OK;
1052 }
1053
1054 int USM::update_key(const unsigned char* user_name,
1055                     const long int user_name_len,
1056                     const unsigned char* engine_id,
1057                     const long int engine_id_len,
1058                     const unsigned char* new_key,
1059                     const long int new_key_len,
1060                     const int type_of_key)
1061 {
1062   OctetStr key(new_key, new_key_len);
1063   int res;
1064   res = usm_user_table->update_key(OctetStr(user_name, user_name_len),
1065                                    OctetStr(engine_id, engine_id_len),
1066                                    key, type_of_key);
1067   key.clear();
1068   return res;
1069 }
1070
1071 int USM::add_localized_user(const OctetStr &engine_id,
1072                             const OctetStr &user_name,
1073                             const OctetStr &security_name,
1074                             const long auth_protocol,
1075                             const OctetStr &auth_key,
1076                             const long priv_protocol,
1077                             const OctetStr &priv_key)
1078 {
1079    return usm_user_table->add_entry(engine_id, user_name, security_name,
1080                                     auth_protocol, auth_key,
1081                                     priv_protocol, priv_key);
1082 }
1083
1084
1085 int USM::add_usm_user(const OctetStr& user_name,
1086                       const OctetStr& security_name,
1087                       const long int  auth_protocol,
1088                       const long int  priv_protocol,
1089                       const OctetStr& auth_password,
1090                       const OctetStr& priv_password)
1091 {
1092   /*  delete localized entries if some exists */
1093   delete_localized_user(user_name);
1094
1095   int result = usm_user_name_table->add_entry(user_name,security_name,
1096                                               auth_protocol, priv_protocol,
1097                                               auth_password, priv_password);
1098   if (result != SNMPv3_USM_OK)
1099     return result;
1100
1101   struct UsmUser *dummy;
1102   dummy = get_user(local_snmp_engine_id, security_name);
1103   if (dummy) free_user(dummy);
1104
1105   return SNMPv3_USM_OK;
1106 }
1107
1108 int USM::add_usm_user(const OctetStr& user_name,
1109                       const OctetStr& security_name,
1110                       const long int  auth_protocol,
1111                       const long int  priv_protocol,
1112                       const OctetStr& auth_password,
1113                       const OctetStr& priv_password,
1114                       const OctetStr& engine_id)
1115 {
1116   OctetStr auth_key;
1117   OctetStr priv_key;
1118
1119   auth_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
1120   priv_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
1121
1122   unsigned int auth_key_len = auth_key.len();
1123   unsigned int priv_key_len = priv_key.len();
1124
1125   int res = build_localized_keys(engine_id, auth_protocol, priv_protocol,
1126                                  auth_password.data(), auth_password.len(),
1127                                  priv_password.data(), priv_password.len(),
1128                                  auth_key.data(), &auth_key_len,
1129                                  priv_key.data(), &priv_key_len);
1130
1131   if (res != SNMPv3_USM_OK)
1132     return res;
1133
1134   auth_key.set_len(auth_key_len);
1135   priv_key.set_len(priv_key_len);
1136
1137   res = usm_user_table->add_entry(engine_id, user_name, security_name,
1138                                   auth_protocol, auth_key,
1139                                   priv_protocol, priv_key);
1140
1141   auth_key.clear();
1142   priv_key.clear();
1143
1144   return res;
1145 }
1146
1147 int USM::add_usm_user(const OctetStr& security_name,
1148                       const long int  auth_protocol,
1149                       const long int  priv_protocol,
1150                       const OctetStr& auth_password,
1151                       const OctetStr& priv_password)
1152 {
1153   // usmUserName:     UserName for UserbasedSecurityModel
1154   // usmSecurityName: UserName for all SecurityModels
1155   return add_usm_user(security_name, security_name,
1156                       auth_protocol, priv_protocol,
1157                       auth_password, priv_password);
1158 }
1159
1160 int USM::delete_localized_user(const OctetStr& usmUserName)
1161 {
1162   return usm_user_table->delete_entries(usmUserName);
1163 }
1164
1165 int USM::delete_localized_user(const OctetStr& engine_id,
1166                                const OctetStr& user_name)
1167 {
1168   return usm_user_table->delete_entry(engine_id, user_name);
1169 }
1170
1171
1172 int USM::build_localized_keys(const OctetStr      &engine_id,
1173                               const int            auth_prot,
1174                               const int            priv_prot,
1175                               const unsigned char *auth_password,
1176                               const unsigned int   auth_password_len,
1177                               const unsigned char *priv_password,
1178                               const unsigned int   priv_password_len,
1179                               unsigned char *auth_key,
1180                               unsigned int  *auth_key_len,
1181                               unsigned char *priv_key,
1182                               unsigned int  *priv_key_len)
1183 {
1184   int res = auth_priv->password_to_key_auth(
1185                                   auth_prot, auth_password,
1186                                   auth_password_len,
1187                                   engine_id.data(), engine_id.len(),
1188                                   auth_key, auth_key_len);
1189
1190   if (res != SNMPv3_USM_OK)
1191   {
1192     if (res == SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL)
1193     {
1194         LOG_BEGIN(ERROR_LOG | 4);
1195         LOG("Could not generate localized key: Unsupported auth protocol");
1196         LOG(auth_prot);
1197         LOG_END;
1198     }
1199     else
1200     {
1201         LOG_BEGIN(ERROR_LOG | 4);
1202         LOG("Could not generate localized auth key, error code");
1203         LOG(res);
1204         LOG_END;
1205     }
1206     return res;
1207   }
1208
1209   res = auth_priv->password_to_key_priv(auth_prot, priv_prot, priv_password,
1210                                         priv_password_len,
1211                                         engine_id.data(), engine_id.len(),
1212                                         priv_key, priv_key_len);
1213
1214   if (res != SNMPv3_USM_OK)
1215   {
1216     if (res == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
1217     {
1218         LOG_BEGIN(ERROR_LOG | 4);
1219         LOG("Could not generate localized key: Unsupported priv protocol");
1220         LOG(priv_prot);
1221         LOG_END;
1222     }
1223     else
1224     {
1225         LOG_BEGIN(ERROR_LOG | 4);
1226         LOG("Could not generate localized priv key, error code");
1227         LOG(res);
1228         LOG_END;
1229     }
1230     return res;
1231   }
1232
1233   return res; // OK
1234 }
1235
1236 struct UsmUser *USM::get_user(const OctetStr &engine_id,
1237                               const OctetStr &security_name)
1238 {
1239   debugprintf(7,"USM::get_user: user (%s) engine_id (%s)",
1240               security_name.get_printable(),engine_id.get_printable());
1241
1242   struct UsmUserNameTableEntry *name_table_entry = NULL;
1243   struct UsmUserTableEntry *user_table_entry = NULL;
1244
1245   user_table_entry = usm_user_table->get_cloned_entry(engine_id,
1246                                                       security_name);
1247   if (!user_table_entry)
1248   {
1249     name_table_entry = usm_user_name_table->get_cloned_entry(security_name);
1250     if (!name_table_entry)
1251     {
1252       const struct UsmUserTableEntry *entry;
1253
1254       BEGIN_AUTO_LOCK(usm_user_table);
1255
1256       entry = usm_user_table->get_entry(security_name);
1257
1258       if ((entry) && (engine_id.len() == 0))
1259       {
1260         // there is a entry for this security_name in the usmUserTable
1261         // so return an entry for this user to do engine_id discovery
1262         struct UsmUser *res = new UsmUser;
1263         if (!res)
1264           return 0;
1265
1266         res->engineID = 0;
1267         res->engineIDLength = 0;
1268         res->usmUserName = v3strcpy(entry->usmUserName,
1269                                     entry->usmUserNameLength);
1270         res->usmUserNameLength = entry->usmUserNameLength;
1271         res->securityName = v3strcpy(entry->usmUserSecurityName,
1272                                      entry->usmUserSecurityNameLength);
1273         res->securityNameLength = entry->usmUserSecurityNameLength;
1274         res->authProtocol = SNMP_AUTHPROTOCOL_NONE;
1275         res->authKey = 0;        res->authKeyLength = 0;
1276         res->privProtocol = SNMP_PRIVPROTOCOL_NONE;
1277         res->privKey = 0;        res->privKeyLength = 0;
1278
1279         if ((res->usmUserNameLength  && !res->usmUserName) ||
1280             (res->securityNameLength && !res->securityName))
1281         {
1282             free_user(res);
1283         }
1284         return res;
1285       }
1286       else
1287       {
1288         debugprintf(1, "USM::get_user: User unknown");
1289         return NULL;
1290       }
1291     }
1292     // here we have valid name_table_entry but not user_table_entry
1293     if (engine_id.len() == 0)
1294     {
1295       // do not add a user
1296       struct UsmUser *res = new UsmUser;
1297       if (!res)
1298       {
1299         usm_user_name_table->delete_cloned_entry(name_table_entry);
1300         return 0;
1301       }
1302       res->engineID           = 0;
1303       res->engineIDLength     = 0;
1304       res->usmUserName        = v3strcpy(name_table_entry->usmUserName.data(),
1305                                          name_table_entry->usmUserName.len());
1306       res->usmUserNameLength  = name_table_entry->usmUserName.len();
1307       res->securityName       = v3strcpy(
1308                                   name_table_entry->usmUserSecurityName.data(),
1309                                   name_table_entry->usmUserSecurityName.len());
1310       res->securityNameLength = name_table_entry->usmUserSecurityName.len();
1311       res->authProtocol       = SNMP_AUTHPROTOCOL_NONE;
1312       res->authKey            = 0;
1313       res->authKeyLength      = 0;
1314       res->privProtocol       = SNMP_PRIVPROTOCOL_NONE;
1315       res->privKey            = 0;
1316       res->privKeyLength      = 0;
1317
1318       if ((res->usmUserNameLength  && !res->usmUserName) ||
1319           (res->securityNameLength && !res->securityName))
1320       {
1321           free_user(res);
1322       }
1323       usm_user_name_table->delete_cloned_entry(name_table_entry);
1324       return res;
1325     }
1326     else
1327     {
1328       // We can add a new user:
1329       unsigned char privKey[SNMPv3_USM_MAX_KEY_LEN];
1330       unsigned char authKey[SNMPv3_USM_MAX_KEY_LEN];
1331       unsigned int authKeyLength = SNMPv3_USM_MAX_KEY_LEN;
1332       unsigned int privKeyLength = SNMPv3_USM_MAX_KEY_LEN;
1333
1334       int res = build_localized_keys(engine_id,
1335                          name_table_entry->usmUserAuthProtocol,
1336                          name_table_entry->usmUserPrivProtocol,
1337                          name_table_entry->authPassword,
1338                          name_table_entry->authPasswordLength,
1339                          name_table_entry->privPassword,
1340                          name_table_entry->privPasswordLength,
1341                          authKey, &authKeyLength,
1342                          privKey, &privKeyLength);
1343
1344       if (res != SNMPv3_USM_OK)
1345       {
1346         LOG_BEGIN(ERROR_LOG | 4);
1347         LOG("Cannot add User: error code");
1348         LOG(res);
1349         LOG_END;
1350
1351         usm_user_name_table->delete_cloned_entry(name_table_entry);
1352         return 0;
1353       }
1354
1355       OctetStr akey(authKey, authKeyLength);
1356       OctetStr pkey(privKey, privKeyLength);
1357       add_localized_user(
1358         engine_id,
1359         name_table_entry->usmUserName,
1360         name_table_entry->usmUserSecurityName,
1361         name_table_entry->usmUserAuthProtocol, akey,
1362         name_table_entry->usmUserPrivProtocol, pkey);
1363
1364       if (usm_add_user_cb)
1365       {
1366         // inform agent++ about new user
1367         debugprintf(5, "Informing agent++ about newly created user");
1368         usm_add_user_cb(engine_id,
1369                         name_table_entry->usmUserName,
1370                         name_table_entry->usmUserSecurityName,
1371                         name_table_entry->usmUserAuthProtocol, akey,
1372                         name_table_entry->usmUserPrivProtocol, pkey);
1373       }
1374       akey.clear();
1375       pkey.clear();
1376
1377       user_table_entry = usm_user_table->get_cloned_entry(engine_id,
1378                                                           security_name);
1379       if (!user_table_entry)
1380       {
1381         LOG_BEGIN(ERROR_LOG | 1);
1382         LOG("Get of just added localized entry failed (sec name) (engine id)");
1383         LOG(security_name.get_printable());
1384         LOG(engine_id.get_printable());
1385         LOG_END;
1386         usm_user_name_table->delete_cloned_entry(name_table_entry);
1387         return 0;
1388       }
1389     }
1390     usm_user_name_table->delete_cloned_entry(name_table_entry);
1391   }
1392   struct UsmUser *res = new UsmUser;
1393   if (!res)
1394   {
1395     usm_user_table->delete_cloned_entry(user_table_entry);
1396     return 0;
1397   }
1398   res->engineID           = user_table_entry->usmUserEngineID;
1399   res->engineIDLength     = user_table_entry->usmUserEngineIDLength;
1400   res->usmUserName        = user_table_entry->usmUserName;
1401   res->usmUserNameLength  = user_table_entry->usmUserNameLength;
1402   res->securityName       = user_table_entry->usmUserSecurityName;
1403   res->securityNameLength = user_table_entry->usmUserSecurityNameLength;
1404   res->authProtocol       = user_table_entry->usmUserAuthProtocol;
1405   res->authKey            = user_table_entry->usmUserAuthKey;
1406   res->authKeyLength      = user_table_entry->usmUserAuthKeyLength;
1407   res->privProtocol       = user_table_entry->usmUserPrivProtocol;
1408   res->privKey            = user_table_entry->usmUserPrivKey;
1409   res->privKeyLength      = user_table_entry->usmUserPrivKeyLength;
1410
1411   user_table_entry->usmUserEngineID = 0;
1412   user_table_entry->usmUserName = 0;
1413   user_table_entry->usmUserSecurityName = 0;
1414   user_table_entry->usmUserAuthKey = 0;
1415   user_table_entry->usmUserPrivKey = 0;
1416
1417   usm_user_table->delete_cloned_entry(user_table_entry);
1418
1419   return res;
1420 }
1421
1422 // Free the structure returned from get_user().
1423 void USM::free_user(struct UsmUser *&user)
1424 {
1425   if (!user) return;
1426
1427   if (user->engineID)     delete [] user->engineID;
1428   if (user->usmUserName)  delete [] user->usmUserName;
1429   if (user->securityName) delete [] user->securityName;
1430
1431   if (user->authKey)
1432   {
1433     memset(user->authKey, 0, user->authKeyLength);
1434     delete [] user->authKey;
1435   }
1436
1437   if (user->privKey)
1438   {
1439     memset(user->privKey, 0, user->privKeyLength);
1440     delete [] user->privKey;
1441   }
1442
1443   delete user;
1444
1445   user = 0;
1446 }
1447
1448 void USM::delete_usm_user(const OctetStr& security_name)
1449 {
1450   usm_user_name_table->delete_security_name(security_name);
1451
1452   unsigned char username[MAXLEN_USMUSERNAME + 1];
1453   long int length = MAXLEN_USMUSERNAME;
1454
1455   if ((get_user_name(username, &length,
1456                      security_name.data(), security_name.len()))
1457       == SNMPv3_USM_OK)
1458     delete_localized_user(OctetStr(username, length));
1459 }
1460
1461 int USM::get_security_name(const unsigned char *user_name,
1462                            const long int user_name_len,
1463                            OctetStr &security_name)
1464 {
1465   debugprintf(20,"USM::get_security_name: get  user (%s)",
1466               OctetStr(user_name,user_name_len).get_printable());
1467
1468   int result;
1469
1470   result = usm_user_name_table->get_security_name(user_name, user_name_len,
1471                                                   security_name);
1472   if (result == SNMPv3_USM_OK)
1473     return SNMPv3_USM_OK;
1474
1475   result = usm_user_table->get_security_name(user_name, user_name_len,
1476                                              security_name);
1477   if (result == SNMPv3_USM_OK)
1478     return SNMPv3_USM_OK;
1479
1480   debugprintf(1, "USM::get_security_name: User unknown");
1481   return SNMPv3_USM_ERROR;
1482 }
1483
1484 int USM::get_user_name(unsigned char *user_name, long int *user_name_len,
1485                        const unsigned char *security_name,
1486                        const long int security_name_len)
1487 {
1488   int result;
1489   long int  buf_len = *user_name_len;
1490
1491   result = usm_user_name_table->get_user_name(user_name, user_name_len,
1492                                               security_name,
1493                                               security_name_len);
1494
1495   if (result == SNMPv3_USM_OK)
1496     return SNMPv3_USM_OK;
1497
1498   *user_name_len = buf_len;
1499
1500   result = usm_user_table->get_user_name(user_name, user_name_len,
1501                                          security_name, security_name_len);
1502
1503   if (result == SNMPv3_USM_OK)
1504     return SNMPv3_USM_OK;
1505
1506   debugprintf(1, "usmGetUsmUserName: User unknown");
1507   return SNMPv3_USM_ERROR;
1508 }
1509
1510
1511 void USM::delete_sec_parameters( struct UsmSecurityParameters *usp)
1512 {
1513   usp->msgAuthoritativeEngineID[0] = 0;
1514   usp->msgAuthoritativeEngineIDLength = 0;
1515   usp->msgAuthoritativeEngineBoots = 0;
1516   usp->msgAuthoritativeEngineTime = 0;
1517   usp->msgUserName[0] = 0;
1518   usp->msgUserNameLength = 0;
1519
1520   if (usp->msgAuthenticationParameters) {
1521     delete [] usp->msgAuthenticationParameters;
1522     usp->msgAuthenticationParameters = NULL;
1523   }
1524   usp->msgAuthenticationParametersLength = 0;
1525   if (usp->msgPrivacyParameters) {
1526     delete [] usp->msgPrivacyParameters;
1527     usp->msgPrivacyParameters = NULL;
1528   }
1529   usp->msgPrivacyParametersLength = 0;
1530 }
1531
1532
1533 const struct UsmUserTableEntry *USM::get_user(int number)
1534 {
1535   return usm_user_table->get_entry(number);
1536 }
1537
1538 const struct UsmUserNameTableEntry *USM::get_user(const OctetStr &security_name)
1539 {
1540   return usm_user_name_table->get_entry(security_name);
1541 }
1542
1543 int USM::get_user_count() const
1544 {
1545   return usm_user_table->size();
1546 }
1547
1548 DLLOPT void USM::add_user_added_callback(const usm_add_user_callback cb)
1549 {
1550  usm_add_user_cb = cb;
1551 }
1552
1553 int USM::get_time(const OctetStr &engine_id,
1554                   long int *engine_boots, long int *engine_time)
1555 {
1556   return usm_time_table->get_time(engine_id, *engine_boots, *engine_time);
1557 }
1558
1559 int USM::get_local_time(long int *engine_boots, long int *engine_time) const
1560 {
1561   return usm_time_table->get_local_time(*engine_boots, *engine_time);
1562 }
1563
1564 AuthPriv *USM::get_auth_priv()
1565 {
1566   return auth_priv;
1567 }
1568
1569 struct UsmKeyUpdate* USM::key_update_prepare(const OctetStr& securityName,
1570                                              SnmpTarget& target,
1571                                              const OctetStr& newPassword,
1572                                              Pdu& pdu, int type,
1573                                              int &status,
1574                                              const OctetStr& oldpass,
1575                                              const OctetStr& oldengid,
1576                                              const OctetStr& newengid)
1577 {
1578   // check address
1579
1580   GenAddress genaddress;
1581   target.get_address(genaddress);
1582   UdpAddress udp_address(genaddress);
1583   if (!udp_address.valid()) {
1584     debugprintf(0, "usmPrepareKeyUpdate: Address invalid.");
1585     status = SNMPv3_USM_ADDRESS_ERROR;
1586     return NULL;
1587   }
1588
1589   OctetStr engineID = "";
1590   // get engineID
1591   if (v3mp->get_from_engine_id_table(engineID,
1592                                      (char*)udp_address.get_printable())
1593       != SNMPv3_MP_OK ) {
1594     debugprintf(0, "usmPrepareKeyUpdate: Could not find engineID of given address.");
1595     status = SNMPv3_USM_ADDRESS_ERROR;
1596     return NULL;
1597   }
1598
1599   // get user
1600   struct UsmUser* user;
1601   user = get_user(engineID, securityName);
1602
1603   if (user == NULL) {
1604     debugprintf(0, "usmPrepareKeyUpdate: Could not find user in usmTables.");
1605     status =  SNMPv3_USM_UNKNOWN_SECURITY_NAME;
1606     return NULL;
1607   }
1608
1609   /* set old and new key */
1610   unsigned char key[SNMPv3_USM_MAX_KEY_LEN];
1611   unsigned int  key_len = SNMPv3_USM_MAX_KEY_LEN;
1612   OctetStr      newKey;
1613   OctetStr      oldKey;
1614
1615   switch (type) {
1616     case AUTHKEY:
1617     case OWNAUTHKEY: {
1618       status = auth_priv->password_to_key_auth(
1619                                          user->authProtocol,
1620                                          newPassword.data(), newPassword.len(),
1621                                          engineID.data(), engineID.len(),
1622                                          key, &key_len);
1623       oldKey = OctetStr(user->authKey, user->authKeyLength);
1624       break;
1625     }
1626     case PRIVKEY:
1627     case OWNPRIVKEY: {
1628       status = auth_priv->password_to_key_priv(
1629                                          user->authProtocol,
1630                                          user->privProtocol,
1631                                          newPassword.data(), newPassword.len(),
1632                                          engineID.data(), engineID.len(),
1633                                          key, &key_len);
1634       oldKey = OctetStr(user->privKey, user->privKeyLength);
1635       break;
1636     }
1637     default: {
1638       debugprintf(0, "usmPrepareKeyUpdate: wrong type specified.");
1639       status = SNMPv3_USM_ERROR;
1640       free_user(user);
1641       return NULL;
1642     }
1643   }
1644
1645   if (status != SNMPv3_USM_OK)
1646   {
1647     debugprintf(0, "usmPrepareKeyUpdate: password_to_key failed (code %i).",
1648                 status);
1649     free_user(user);
1650     return NULL;
1651   }
1652
1653   newKey = OctetStr(key, key_len);
1654
1655   /* get value to set and random value */
1656   OctetStr newValue;
1657   OctetStr random_value;
1658
1659   auth_priv->get_keychange_value(user->authProtocol,
1660                                  oldKey, newKey, newValue);
1661
1662   char tmp_rand;
1663   for (int i = 0; i<30; i++) {
1664     tmp_rand = rand();
1665     random_value += tmp_rand;
1666   }
1667
1668   // Oid in usmUserTable
1669   Oid userOid = Oid(oidUsmUserEntry);
1670   Oid publicOid  = Oid(oidUsmUserEntry);
1671
1672   publicOid += "11";
1673
1674   switch (type) {
1675     case AUTHKEY: {
1676       userOid += "6";
1677       break;
1678     }
1679     case OWNAUTHKEY: {
1680       userOid += "7";
1681       break;
1682     }
1683     case PRIVKEY: {
1684        userOid += "9";
1685        break;
1686     }
1687     case OWNPRIVKEY: {
1688       userOid += "10";
1689       break;
1690     }
1691     default: {
1692       debugprintf(0, "KeyChange error: wrong type:");
1693       status = SNMPv3_USM_ERROR;
1694       free_user(user);
1695       return NULL;
1696     }
1697   }
1698
1699   userOid += engineID.len();
1700   publicOid += engineID.len();
1701
1702   for (unsigned int j=0; j<engineID.len(); j++) {
1703     userOid += (engineID)[j];
1704     publicOid += (engineID)[j];
1705   }
1706
1707   OctetStr os = securityName;
1708   userOid += os.len();
1709   publicOid += os.len();
1710
1711   for (unsigned int k=0; k<os.len(); k++) {
1712     userOid += os[k];
1713     publicOid += os[k];
1714   }
1715
1716   Vb vb;
1717   vb.set_oid(userOid);
1718   vb.set_value(newValue);
1719   pdu += vb;
1720
1721   vb.set_oid(publicOid);
1722   vb.set_value(random_value);
1723   pdu += vb;
1724
1725   struct UsmKeyUpdate *uku = new struct UsmKeyUpdate;
1726   uku->engineID = engineID;
1727   uku->securityName = securityName;
1728   uku->newPassword = newPassword;
1729   uku->newKey = newKey;
1730   uku->type = type;
1731
1732   free_user(user);
1733   status = SNMPv3_USM_OK;
1734   return uku;
1735 }
1736
1737 void USM::key_update_abort(struct UsmKeyUpdate *uku)
1738 {
1739   delete uku;
1740 }
1741
1742 int USM::key_update_commit(struct UsmKeyUpdate *uku, int update_type)
1743 {
1744   if (!uku) return SNMPv3_USM_ERROR;
1745
1746   int result;
1747   OctetStr userName;
1748
1749   switch (update_type)
1750   {
1751     case USM_KeyUpdate: {
1752       result = update_key(uku->securityName.data(), uku->securityName.len(),
1753                           uku->engineID.data(), uku->engineID.len(),
1754                           uku->newKey.data(), uku->newKey.len(),
1755                           uku->type);
1756       delete uku;
1757       return result;
1758     }
1759     case USM_PasswordKeyUpdate: {
1760       result = update_key(uku->securityName.data(), uku->securityName.len(),
1761                           uku->engineID.data(), uku->engineID.len(),
1762                           uku->newKey.data(), uku->newKey.len(),
1763                           uku->type);
1764       struct UsmUserNameTableEntry *entry;
1765       entry = usm_user_name_table->get_cloned_entry(uku->securityName);
1766       if (!entry || (result != SNMPv3_USM_OK)) {
1767         delete uku;
1768         if (entry)
1769           usm_user_name_table->delete_cloned_entry(entry);
1770         return SNMPv3_USM_ERROR;
1771       }
1772
1773       result = SNMPv3_USM_ERROR;
1774
1775       switch (uku->type) {
1776         case OWNAUTHKEY:
1777         case AUTHKEY: {
1778           OctetStr privPass(entry->privPassword, entry->privPasswordLength);
1779           result = add_usm_user(uku->securityName, entry->usmUserName,
1780                                 entry->usmUserAuthProtocol,
1781                                 entry->usmUserPrivProtocol,
1782                                 uku->newPassword, privPass);
1783           break;
1784         }
1785         case OWNPRIVKEY:
1786         case PRIVKEY: {
1787           OctetStr authPass(entry->privPassword, entry->privPasswordLength);
1788           result = add_usm_user(uku->securityName, entry->usmUserName,
1789                                 entry->usmUserAuthProtocol,
1790                                 entry->usmUserPrivProtocol,
1791                                 authPass, uku->newPassword);
1792           break;
1793         }
1794       }
1795       delete uku;
1796       usm_user_name_table->delete_cloned_entry(entry);
1797       return result;
1798     }
1799     case USM_PasswordAllKeyUpdate: {
1800       struct UsmUserNameTableEntry *entry;
1801       entry = usm_user_name_table->get_cloned_entry(uku->securityName);
1802       if (!entry) {
1803         delete uku;
1804         return SNMPv3_USM_ERROR;
1805       }
1806
1807       result = SNMPv3_USM_ERROR;
1808
1809       switch (uku->type) {
1810         case OWNAUTHKEY:
1811         case AUTHKEY: {
1812           OctetStr privPass = OctetStr(entry->privPassword,
1813                                        entry->privPasswordLength);
1814           delete_usm_user(uku->securityName);
1815           result = add_usm_user(uku->securityName, entry->usmUserName,
1816                                 entry->usmUserAuthProtocol,
1817                                 entry->usmUserPrivProtocol,
1818                                 uku->newPassword, privPass);
1819           break;
1820         }
1821         case OWNPRIVKEY:
1822         case PRIVKEY: {
1823           OctetStr authPass = OctetStr(entry->authPassword,
1824                                        entry->authPasswordLength);
1825           delete_usm_user(uku->securityName);
1826           result = add_usm_user(uku->securityName, entry->usmUserName,
1827                                 entry->usmUserAuthProtocol,
1828                                 entry->usmUserPrivProtocol,
1829                                 authPass, uku->newPassword);
1830           break;
1831         }
1832       }
1833       delete uku;
1834       usm_user_name_table->delete_cloned_entry(entry);
1835       return result;
1836     }
1837   }
1838   delete uku;
1839   return SNMPv3_USM_ERROR;
1840 }
1841
1842 int USM::generate_msg(
1843              unsigned char *globalData,       // message header, admin data
1844              int globalDataLength,
1845              int maxMessageSize,              // of the sending SNMP entity
1846              const OctetStr &securityEngineID,// authoritative SNMP entity
1847              const OctetStr &securityName,    // on behalf of this principal
1848              int  securityLevel,              // Level of Security requested
1849              unsigned char  *scopedPDU,       // message (plaintext) payload
1850              int scopedPDULength,
1851              struct SecurityStateReference *securityStateReference,
1852              unsigned char *wholeMsg,         // OUT complete generated message
1853              int *wholeMsgLength)             // OUT length of generated message
1854 {
1855   Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
1856   Buffer<unsigned char> buffer2(MAX_SNMP_PACKET);
1857   unsigned char *bufPtr = buffer.get_ptr();
1858   unsigned char *buf2Ptr = buffer2.get_ptr();
1859
1860   if (!bufPtr || !buf2Ptr)
1861     return SNMPv3_USM_ERROR;
1862
1863   unsigned char *wholeMsgPtr;
1864   int startAuthPar = 0;
1865   struct UsmUser *user = NULL;
1866   struct UsmSecurityParameters usmSecurityParams;
1867
1868   int bufLength = 0;
1869   unsigned int buf2Length = 0;
1870   int totalLength = 0;             // Bytes encoded
1871   int restLength = maxMessageSize; // max Bytes left in packet-buffer
1872   int rc;
1873   int responseMsg = 0;
1874
1875   if (securityStateReference) {
1876     // this is a response message
1877     responseMsg = 1;
1878     user = new UsmUser;
1879     if (!user)
1880       return SNMPv3_USM_ERROR;
1881     if (securityStateReference->securityEngineID) {
1882       user->engineIDLength = securityStateReference->securityEngineIDLength;
1883       user->engineID       = securityStateReference->securityEngineID;
1884     } else {
1885       user->engineIDLength = securityEngineID.len();
1886       user->engineID       = v3strcpy(securityEngineID.data(),
1887                                       securityEngineID.len());
1888     }
1889
1890     user->usmUserName = new unsigned char[MAXLEN_USMUSERNAME + 1];
1891     if (securityStateReference->securityName)
1892     {
1893       user->securityName       = securityStateReference->securityName;
1894       user->securityNameLength = securityStateReference->securityNameLength;
1895       memcpy(user->usmUserName, securityStateReference->msgUserName,
1896              securityStateReference->msgUserNameLength);
1897       user->usmUserNameLength  = securityStateReference->msgUserNameLength;
1898     }
1899     else
1900     {
1901       user->securityNameLength = securityName.len();
1902       user->securityName = v3strcpy(securityName.data(), securityName.len());
1903       if (securityStateReference->msgUserNameLength)
1904       {
1905         securityStateReference->msgUserName[0] = 0;
1906         securityStateReference->msgUserNameLength = 0;
1907       }
1908       user->usmUserNameLength = MAXLEN_USMUSERNAME;
1909       get_user_name(user->usmUserName, &user->usmUserNameLength,
1910                     securityName.data(), securityName.len());
1911       if ((user->usmUserNameLength == 0) &&
1912           (securityName.len() <= MAXLEN_USMUSERNAME)) {
1913         memcpy(user->usmUserName, securityName.data(), securityName.len());
1914         user->usmUserName[securityName.len()] = 0;
1915         user->usmUserNameLength = securityName.len();
1916       }
1917     }
1918     user->authProtocol       = securityStateReference->authProtocol;
1919     user->authKey            = securityStateReference->authKey;
1920     user->authKeyLength      = securityStateReference->authKeyLength;
1921     user->privProtocol       = securityStateReference->privProtocol;
1922     user->privKeyLength      = securityStateReference->privKeyLength;
1923     user->privKey            = securityStateReference->privKey;
1924
1925     delete securityStateReference;
1926     securityStateReference = NULL;
1927   }
1928   else
1929   {
1930     if (securityEngineID.len() == 0)
1931     {
1932       // discovery
1933       user = new UsmUser;
1934       if (!user)
1935         return SNMPv3_USM_ERROR;
1936       memset(user, 0, sizeof(UsmUser));
1937     }
1938     else
1939     {
1940       // search for user in usmUserTable
1941       user = get_user(securityEngineID, securityName);
1942
1943       if (!user) {
1944         debugprintf(0, "USM: User unknown!");
1945         return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
1946       }
1947     }
1948   }
1949
1950   if (securityEngineID.len() > MAXLENGTH_ENGINEID)
1951   {
1952     debugprintf(0, "engine_id too long %i > %i",
1953                 securityEngineID.len(), MAXLENGTH_ENGINEID);
1954     free_user(user);
1955     return SNMPv3_USM_ERROR;
1956   }
1957
1958   if (user->usmUserNameLength > MAXLEN_USMUSERNAME)
1959   {
1960     debugprintf(0, "user name too long %i > %i",
1961                 user->usmUserNameLength, MAXLEN_USMUSERNAME);
1962     free_user(user);
1963     return SNMPv3_USM_ERROR;
1964   }
1965
1966   usmSecurityParams.msgAuthoritativeEngineIDLength = securityEngineID.len();
1967   usmSecurityParams.msgUserNameLength = user->usmUserNameLength;
1968   memcpy(usmSecurityParams.msgUserName,
1969          user->usmUserName, user->usmUserNameLength);
1970   memcpy(usmSecurityParams.msgAuthoritativeEngineID,
1971          securityEngineID.data(), securityEngineID.len());
1972
1973   usmSecurityParams.msgPrivacyParametersLength = 0;
1974   usmSecurityParams.msgPrivacyParameters = NULL;
1975
1976   usmSecurityParams.msgAuthenticationParametersLength = 0;
1977   usmSecurityParams.msgAuthenticationParameters = NULL;
1978
1979   if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
1980   {
1981     // get engineBoots, engineTime
1982     rc = usm_time_table->get_time(
1983                            securityEngineID,
1984                            usmSecurityParams.msgAuthoritativeEngineBoots,
1985                            usmSecurityParams.msgAuthoritativeEngineTime);
1986     if (rc == SNMPv3_USM_UNKNOWN_ENGINEID) {
1987       usm_time_table->add_entry(securityEngineID,
1988                                 usmSecurityParams.msgAuthoritativeEngineBoots,
1989                                 usmSecurityParams.msgAuthoritativeEngineTime);
1990     }
1991     if (rc == SNMPv3_USM_ERROR) {
1992       debugprintf(0, "usm: usmGetTime error.");
1993       free_user(user);
1994       return SNMPv3_USM_ERROR;
1995     }
1996   }
1997
1998   if (securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
1999   {
2000     usmSecurityParams.msgPrivacyParametersLength
2001              = auth_priv->get_priv_params_len(user->privProtocol);
2002     usmSecurityParams.msgPrivacyParameters
2003              = new unsigned char[usmSecurityParams.msgPrivacyParametersLength];
2004
2005     // encrypt Message
2006     int enc_result = auth_priv->encrypt_msg(
2007                                user->privProtocol,
2008                                user->privKey, user->privKeyLength,
2009                                scopedPDU, scopedPDULength,
2010                                buf2Ptr, &buf2Length,
2011                                usmSecurityParams.msgPrivacyParameters,
2012                                &usmSecurityParams.msgPrivacyParametersLength,
2013                                usmSecurityParams.msgAuthoritativeEngineBoots,
2014                                usmSecurityParams.msgAuthoritativeEngineTime);
2015     if (enc_result != SNMPv3_USM_OK)
2016     {
2017       int return_value;
2018
2019       if (user->privProtocol == SNMP_PRIVPROTOCOL_NONE)
2020       {
2021         debugprintf(0, "usm: Privacy requested, but no UserPrivProtocol");
2022         return_value = SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
2023       }
2024       else
2025       {
2026         return_value = SNMPv3_USM_ENCRYPTION_ERROR;
2027       }
2028
2029       debugprintf(0, "usm: Encryption error (result %i).", enc_result);
2030
2031       delete_sec_parameters(&usmSecurityParams);
2032       free_user(user);
2033       return return_value;
2034     }
2035
2036     bufPtr = asn_build_string(bufPtr, &restLength, ASN_UNI_PRIM | ASN_OCTET_STR,
2037                               buf2Ptr, buf2Length);
2038     if (!bufPtr) {
2039       debugprintf(0, "usm: Encoding Error");
2040       free_user(user);
2041       return SNMPv3_USM_ERROR;
2042     }
2043     bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
2044     totalLength =  bufLength;
2045     bufPtr = buffer.get_ptr();
2046     memcpy(buf2Ptr, bufPtr, bufLength);
2047     buf2Length = bufLength;
2048
2049   } else { // (securityLevel != SNMP_SECURITY_LEVEL_AUTH_PRIV)
2050     buf2Ptr = scopedPDU;
2051     buf2Length = scopedPDULength;
2052     totalLength = scopedPDULength;
2053   }
2054   if (!bufPtr) {
2055     debugprintf(0, "usm: Encoding Error");
2056     free_user(user);
2057     return SNMPv3_USM_ERROR;
2058   }
2059
2060   totalLength += SAFE_INT_CAST(bufPtr - buffer.get_ptr());
2061   memcpy(bufPtr, buf2Ptr, buf2Length);
2062   bufLength = totalLength;
2063
2064   debugprintf(21, "buf after privacy:");
2065   debughexprintf(21, buffer.get_ptr(), bufLength);
2066
2067   wholeMsgPtr = wholeMsg;
2068
2069   if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
2070   {
2071     /* Build message with authentication */
2072     usmSecurityParams.msgAuthenticationParametersLength
2073                          = auth_priv->get_auth_params_len(user->authProtocol);
2074     usmSecurityParams.msgAuthenticationParameters
2075       = new unsigned char[usmSecurityParams.msgAuthenticationParametersLength];
2076     memset((char*)(usmSecurityParams.msgAuthenticationParameters), 0,
2077            usmSecurityParams.msgAuthenticationParametersLength);
2078
2079     wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
2080                                   globalData, globalDataLength,
2081                                   &startAuthPar, // for MD5, SHA,...
2082                                   usmSecurityParams,
2083                                   buffer.get_ptr(),
2084                                   bufLength);   // the msgData
2085     if (wholeMsgPtr == NULL)
2086     {
2087       debugprintf(0, "usm: could not generate wholeMsg");
2088       delete_sec_parameters(&usmSecurityParams);
2089       free_user(user);
2090       return SNMPv3_USM_ERROR;
2091     }
2092     *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
2093
2094     rc = auth_priv->auth_out_msg(user->authProtocol,
2095                                  user->authKey,
2096                                  wholeMsg, *wholeMsgLength,
2097                                  wholeMsg + startAuthPar);
2098
2099     if (rc!=SNMPv3_USM_OK)
2100     {
2101       debugprintf(0, "usm: Authentication error for outgoing message."
2102                   " error code (%i).", rc);
2103       delete_sec_parameters(&usmSecurityParams);
2104       free_user(user);
2105       return rc;
2106     }
2107   }
2108   else
2109   {
2110     //build Message without authentication
2111
2112     // Set engineBoots and enigneTime to zero!
2113     usmSecurityParams.msgAuthoritativeEngineBoots = 0;
2114     usmSecurityParams.msgAuthoritativeEngineTime  = 0;
2115
2116     usmSecurityParams.msgAuthenticationParametersLength = 0;
2117     usmSecurityParams.msgAuthenticationParameters = 0;
2118
2119     wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
2120                                   globalData, globalDataLength,
2121                                   &startAuthPar, // dummy ( no auth)
2122                                   usmSecurityParams,
2123                                   buffer.get_ptr(),
2124                                   bufLength);   // the msgData
2125     if (wholeMsgPtr == NULL) {
2126       debugprintf(0, "usm: could not generate wholeMsg");
2127       delete_sec_parameters(&usmSecurityParams);
2128       free_user(user);
2129       return SNMPv3_USM_ERROR;
2130     }
2131     *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
2132   }
2133
2134   debugprintf(21, "Complete Whole Msg:");
2135   debughexprintf(21, wholeMsg, *wholeMsgLength);
2136
2137   delete_sec_parameters(&usmSecurityParams);
2138   free_user(user);
2139   return SNMPv3_USM_OK;
2140 }
2141
2142 int USM::process_msg(
2143             int maxMessageSize,               // of the sending SNMP entity
2144             unsigned char *securityParameters,// for the received message
2145             int securityParametersLength,
2146             int securityParametersPosition,
2147             long int securityLevel,           // Level of Security
2148             unsigned char *wholeMsg,          // as received on the wire
2149             int wholeMsgLength,               // length as received on the wire
2150             unsigned char *msgData,
2151             int msgDataLength,
2152             OctetStr &security_engine_id,     // authoritative SNMP entity
2153             OctetStr &security_name,          //identification of the principal
2154             unsigned char *scopedPDU,         // message (plaintext) payload
2155             int *scopedPDULength,
2156             long *maxSizeResponseScopedPDU, // maximum size of the Response PDU
2157             struct SecurityStateReference *securityStateReference,
2158                                             // reference to security state
2159                                             // information, needed for response
2160             const UdpAddress &fromAddress)
2161 {
2162   unsigned char* sp = securityParameters;
2163   int spLength = securityParametersLength;
2164   unsigned char type;
2165   long int engineBoots, engineTime;
2166   unsigned char authParam[SNMPv3_AP_MAXLENGTH_AUTHPARAM];
2167   unsigned char privParam[SNMPv3_AP_MAXLENGTH_PRIVPARAM];
2168   int authParamLength = SNMPv3_AP_MAXLENGTH_AUTHPARAM;
2169   int privParamLength = SNMPv3_AP_MAXLENGTH_PRIVPARAM;
2170   Buffer<unsigned char> encryptedScopedPDU(MAX_SNMP_PACKET);
2171   int encryptedScopedPDULength = msgDataLength;
2172   struct UsmUser *user = NULL;
2173   int rc;
2174   int notInTime = 0;
2175
2176   // check securityParameters
2177   sp = asn_parse_header( sp, &spLength, &type);
2178   if (sp == NULL){
2179     debugprintf(0, "bad header of securityParameters");
2180     return SNMPv3_USM_PARSE_ERROR;
2181   }
2182   debugprintf(3, "Parsed securityParametersLength = 0x%x", spLength);
2183
2184   if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)){
2185     debugprintf(0, "wrong type in header of securityParameters");
2186     return SNMPv3_USM_PARSE_ERROR;
2187   }
2188
2189   // extract security parameters
2190   {
2191     int len = MAXLENGTH_ENGINEID + 1;
2192     unsigned char data[MAXLENGTH_ENGINEID + 1];
2193     sp = asn_parse_string( sp, &spLength, &type, data, &len);
2194
2195     debugprintf(3, "Parsed securityEngineID, length = 0x%x", len);
2196     if (sp==NULL) {
2197       debugprintf(0, "bad parse of securityEngineID");
2198       return SNMPv3_USM_PARSE_ERROR;
2199     }
2200     security_engine_id.set_data(data, len);
2201   }
2202
2203   sp = asn_parse_int(sp, &spLength, &type, &engineBoots);
2204   if ((sp == NULL) || (engineBoots < 0)) {
2205     debugprintf(0, "bad parse of engineBoots");
2206     return SNMPv3_USM_PARSE_ERROR;
2207   }
2208
2209   sp = asn_parse_int(sp, &spLength, &type, &engineTime);
2210   if ((sp == NULL) || (engineTime < 0)) {
2211     debugprintf(0, "bad parse of engineTime");
2212     return SNMPv3_USM_PARSE_ERROR;
2213   }
2214
2215   debugprintf(3, "Parsed engineBoots(0x%lx), engineTime(0x%lx)",
2216               engineTime, engineBoots);
2217
2218   unsigned char usmUserName[MAXLEN_USMUSERNAME + 1];
2219   int usmUserNameLength = MAXLEN_USMUSERNAME;
2220
2221   sp = asn_parse_string( sp, &spLength, &type,
2222                          (unsigned char*)&usmUserName, &usmUserNameLength);
2223
2224   if (sp==NULL) {
2225     debugprintf(0, "bad parse of usmUserName");
2226     return SNMPv3_USM_PARSE_ERROR;
2227   }
2228
2229   sp = asn_parse_string( sp, &spLength, &type,
2230                          (unsigned char*)&authParam, &authParamLength);
2231
2232   if (sp==NULL) {
2233     debugprintf(0, "bad parse of msgAuthenticationParameters");
2234     return SNMPv3_USM_PARSE_ERROR;
2235   }
2236   int authParametersPosition = securityParametersPosition +
2237                                SAFE_INT_CAST(sp - securityParameters) - authParamLength;
2238
2239   sp = asn_parse_string( sp, &spLength, &type,
2240                          (unsigned char*)&privParam, &privParamLength);
2241
2242   if (sp==NULL) {
2243     debugprintf(0, "bad parse of msgPrivacyParameters");
2244     return SNMPv3_USM_PARSE_ERROR;
2245   }
2246   if (spLength !=0) {
2247     debugprintf(0, "Error Parsing msgPrivacyParameters");
2248     return SNMPv3_USM_PARSE_ERROR;
2249   }
2250   debugprintf(5, "Parsed usmUserName length(0x%x)"
2251               " msgAuthenticationParameters length(0x%x)"
2252               " msgPrivacyParameters length(0x%x)",
2253               usmUserNameLength, authParamLength, privParamLength);
2254
2255   // prepare securityStateReference
2256   if (usmUserNameLength > MAXLEN_USMUSERNAME)
2257   {
2258     debugprintf(0, "user name too long: %i > %i.",
2259                 usmUserNameLength, MAXLEN_USMUSERNAME);
2260     return SNMPv3_USM_PARSE_ERROR;
2261   }
2262
2263   securityStateReference->msgUserNameLength = usmUserNameLength;
2264   memcpy(securityStateReference->msgUserName, usmUserName,
2265          securityStateReference->msgUserNameLength);
2266
2267   securityStateReference->securityEngineIDLength = security_engine_id.len();
2268   securityStateReference->securityEngineID =
2269     new unsigned char [securityStateReference->securityEngineIDLength];
2270   memcpy(securityStateReference->securityEngineID, security_engine_id.data(),
2271          securityStateReference->securityEngineIDLength);
2272
2273   securityStateReference->securityLevel = securityLevel;
2274
2275   securityStateReference->securityNameLength = 0;
2276   securityStateReference->securityName = NULL;
2277   securityStateReference->authProtocol = 1;
2278   securityStateReference->privProtocol = 1;
2279   securityStateReference->authKey = NULL;
2280   securityStateReference->privKey = NULL;
2281
2282   // in case we return with error,
2283   // perhaps v3MP can decode it (requestID!!!)
2284   memcpy(scopedPDU, msgData, msgDataLength);
2285   *scopedPDULength = msgDataLength;
2286
2287   if ((security_engine_id.len() == 0) ||
2288       (usm_time_table->check_engine_id(security_engine_id) != SNMPv3_USM_OK ))
2289   {
2290     inc_stats_unknown_engine_ids();
2291
2292     // *+* REPORT *+*
2293     securityStateReference->securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
2294     security_name.set_data(usmUserName, usmUserNameLength);
2295
2296     debugprintf(2, "USM: EngineID unknown");
2297     return SNMPv3_USM_UNKNOWN_ENGINEID;
2298   }
2299
2300   // get securityName:
2301   if ((usmUserNameLength) ||
2302       (securityLevel != SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV))
2303   {
2304     rc = get_security_name(usmUserName, usmUserNameLength, security_name);
2305     if (rc != SNMPv3_USM_OK) {
2306       inc_stats_unknown_user_names();
2307       security_name.set_data(usmUserName, usmUserNameLength);
2308
2309       debugprintf(2,"usmProcessMsg: unknown user (%s)",
2310                   security_name.get_printable());
2311       return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
2312     }
2313   }
2314   else
2315   {
2316     debugprintf(2, "Accepting zero length user/security name.");
2317     security_name = "";
2318   }
2319
2320   securityStateReference->securityNameLength = security_name.len();
2321   securityStateReference->securityName =
2322     new unsigned char [securityStateReference->securityNameLength];
2323   memcpy(securityStateReference->securityName, security_name.data(),
2324          securityStateReference->securityNameLength);
2325
2326   // get user from LCD (usmUserTable)
2327   if (usmUserNameLength)
2328   {
2329     user = get_user(security_engine_id, security_name);
2330
2331     if (!user) {
2332       inc_stats_unknown_user_names();
2333       debugprintf(0, "usmProcessMsg: unknown user");
2334       return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
2335     }
2336   }
2337   else
2338   {
2339     user = new UsmUser;
2340     if (!user)
2341     {
2342       debugprintf(0, "Memory error");
2343       return SNMPv3_USM_ERROR;
2344     }
2345     memset(user, 0, sizeof(UsmUser));
2346   }
2347
2348   if (((securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV) &&
2349        (user->authProtocol == SNMP_AUTHPROTOCOL_NONE)) ||
2350       ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV) &&
2351        (user->privProtocol == SNMP_PRIVPROTOCOL_NONE))) {
2352     inc_stats_unsupported_sec_levels();
2353     debugprintf(0, "usmProcessMsg: unsupported Securitylevel");
2354     free_user(user);
2355     return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
2356   }
2357
2358   if (securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV)
2359   {
2360     rc = auth_priv->auth_inc_msg(user->authProtocol,
2361                                  user->authKey,
2362                                  wholeMsg, wholeMsgLength,
2363                                  wholeMsg + authParametersPosition,
2364                                  authParamLength);
2365     if (rc != SNMPv3_USM_OK)
2366     {
2367       switch (rc)
2368       {
2369         case SNMPv3_USM_AUTHENTICATION_FAILURE:
2370           debugprintf(0, "usmProcessMsg: Authentication failure.");
2371           inc_stats_wrong_digests();
2372           /* set securityLevel for Report */
2373           break;
2374         case SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL:
2375           debugprintf(0, "usmProcessMsg: unknown AuthProtocol");
2376           inc_stats_unsupported_sec_levels();
2377         default:
2378           debugprintf(0, "usmProcessMsg: error authenticating msg."
2379                       " Error code (%i).", rc);
2380           // todo: is it ok to increment this counter?
2381           inc_stats_unsupported_sec_levels();
2382           break;
2383       }
2384       securityStateReference->securityLevel= SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
2385       free_user(user);
2386       return rc;
2387     }
2388
2389     rc = usm_time_table->check_time(security_engine_id,
2390                                     engineBoots, engineTime);
2391     if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW)
2392     {
2393       inc_stats_not_in_time_windows();
2394       debugprintf(2, "***Message not in TimeWindow!");
2395       notInTime = 1;
2396     }
2397     if (rc == SNMPv3_USM_UNKNOWN_ENGINEID)
2398     {
2399       debugprintf(0, "***EngineID not in timeTable!");
2400       free_user(user);
2401       return rc;
2402     }
2403   }
2404
2405   *scopedPDULength = MAX_SNMP_PACKET;
2406
2407   // decrypt ScopedPDU if message is in time window
2408   if ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
2409       && (!notInTime)) {
2410     msgData = asn_parse_string( msgData, &msgDataLength, &type,
2411                                 encryptedScopedPDU.get_ptr(),
2412                                 &encryptedScopedPDULength);
2413     if (msgData == NULL){
2414       debugprintf(0, "usmProcessMsg: bad header of encryptedPDU");
2415       free_user(user);
2416       return SNMPv3_USM_PARSE_ERROR;
2417     }
2418
2419     // decrypt Message
2420     unsigned int tmp_length = *scopedPDULength;
2421     int dec_result = auth_priv->decrypt_msg(
2422                                   user->privProtocol,
2423                                   user->privKey, user->privKeyLength,
2424                                   encryptedScopedPDU.get_ptr(),
2425                                   encryptedScopedPDULength,
2426                                   scopedPDU, &tmp_length,
2427                                   (unsigned char*)&privParam, privParamLength,
2428                                   engineBoots, engineTime);
2429     *scopedPDULength = tmp_length;
2430     if (dec_result != SNMPv3_USM_OK)
2431     {
2432       int return_value;
2433       if (dec_result == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
2434       {
2435         debugprintf(0, "usmProcessMsg: unknown PrivacyProtocol");
2436         inc_stats_unsupported_sec_levels();
2437         return_value = SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
2438       }
2439       else // catch all
2440       {
2441         debugprintf(0, "usmProcessMsg: Decryption error (result %i).",
2442                     dec_result);
2443         inc_stats_decryption_errors();
2444         return_value = SNMPv3_USM_DECRYPTION_ERROR;
2445       }
2446       free_user(user);
2447       return return_value;
2448     }
2449
2450     debugprintf(21, "scopedPDU(1):");
2451     debughexprintf(21, scopedPDU, *scopedPDULength);
2452
2453     // test for decryption error
2454     // first byte 0x30
2455     if (scopedPDU[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE)) {
2456       debugprintf(0, "Decryption error detected");
2457       inc_stats_decryption_errors();
2458       free_user(user);
2459       return SNMPv3_USM_DECRYPTION_ERROR;
2460     }
2461   }
2462   else {
2463     // message was not encrypted
2464     memcpy(scopedPDU, msgData, msgDataLength);
2465     *scopedPDULength = msgDataLength;
2466   }
2467
2468   *maxSizeResponseScopedPDU = maxMessageSize - (wholeMsgLength - *scopedPDULength);
2469
2470   security_name.set_data(user->securityName, user->securityNameLength);
2471
2472   securityStateReference->authProtocol = user->authProtocol;
2473   securityStateReference->privProtocol = user->privProtocol;
2474
2475   securityStateReference->authKeyLength = user->authKeyLength;
2476   securityStateReference->authKey = user->authKey;
2477
2478   securityStateReference->privKeyLength = user->privKeyLength;
2479   securityStateReference->privKey = user->privKey;
2480
2481   user->authKey = 0;
2482   user->privKey = 0;
2483
2484   free_user(user);
2485
2486   if (notInTime)
2487     return SNMPv3_USM_NOT_IN_TIME_WINDOW;
2488
2489   return SNMPv3_USM_OK;
2490 }
2491
2492 unsigned char *USM::build_sec_params(unsigned char *outBuf, int *maxLength,
2493                                      struct UsmSecurityParameters sp,
2494                                      int *position)
2495 {
2496   Buffer<unsigned char> buf(MAX_SNMP_PACKET);
2497   unsigned char *bufPtr = buf.get_ptr();
2498   unsigned char *outBufPtr = outBuf;
2499   int length = *maxLength;
2500   int totalLength;
2501
2502   debugprintf(5, "Coding octstr sp.msgAuthoritativeEngineID, length = 0x%lx",
2503               sp.msgAuthoritativeEngineIDLength);
2504   bufPtr = asn_build_string(bufPtr, &length,
2505                             ASN_UNI_PRIM | ASN_OCTET_STR,
2506                             sp.msgAuthoritativeEngineID,
2507                             sp.msgAuthoritativeEngineIDLength);
2508   if (bufPtr == NULL) {
2509     debugprintf(0, "usmBuildSecurityParameters error coding engineid");
2510     return NULL;
2511   }
2512
2513   debugprintf(5, "Coding int sp.msgAuthoritativeEngineBoots = 0x%lx",
2514               sp.msgAuthoritativeEngineBoots);
2515   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
2516                          &sp.msgAuthoritativeEngineBoots);
2517
2518   if (bufPtr == NULL) {
2519     debugprintf(0, "usmBuildSecurityParameters error coding engineboots");
2520     return NULL;
2521   }
2522
2523   debugprintf(5, "Coding int sp.msgAuthoritativeEngineTime = 0x%lx",
2524               sp.msgAuthoritativeEngineTime);
2525   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
2526                          &sp.msgAuthoritativeEngineTime);
2527
2528   if (bufPtr == NULL) {
2529     debugprintf(0, "usmBuildSecurityParameters error coding enginetime");
2530     return NULL;
2531   }
2532
2533   debugprintf(5, "Coding octstr sp.msgUserName, length = 0x%lx",
2534               sp.msgUserNameLength);
2535   bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
2536                             sp.msgUserName, sp.msgUserNameLength);
2537   if (bufPtr == NULL) {
2538     debugprintf(0, "usmBuildSecurityParameters error coding msgusername");
2539     return NULL;
2540   }
2541
2542   *position = SAFE_INT_CAST(bufPtr - buf.get_ptr()) + 2;
2543
2544   debugprintf(5, "Coding octstr sp.msgAu..Para.. , length = 0x%lx",
2545               sp.msgAuthenticationParametersLength);
2546   bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
2547                             sp.msgAuthenticationParameters,
2548                             sp.msgAuthenticationParametersLength);
2549
2550   if (bufPtr == NULL) {
2551     debugprintf(0, "usmBuildSecurityParameters error coding authparams");
2552     return NULL;
2553   }
2554
2555   debugprintf(5, "Coding octstr sp.msgPr..Para.. , length = 0x%lx",
2556               sp.msgPrivacyParametersLength);
2557   bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
2558                             sp.msgPrivacyParameters,
2559                             sp.msgPrivacyParametersLength);
2560
2561   if (bufPtr == NULL) {
2562     debugprintf(0, "usmBuildSecurityParameters error coding privparams");
2563     return NULL;
2564   }
2565
2566   totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
2567
2568   debugprintf(5, "Coding sequence (securityPar), length = 0x%x", totalLength);
2569   outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
2570                                  totalLength);
2571
2572   if (outBufPtr == NULL) {
2573     debugprintf(0, "usm: usmBuildSecurityParameters error coding secparams");
2574     return NULL;
2575   }
2576
2577   if (*maxLength < totalLength) {
2578     debugprintf(0, "usm: usmBuildSecurityParameters error (length mismatch)");
2579     return NULL;
2580   }
2581   *position += SAFE_INT_CAST(outBufPtr - outBuf);
2582   memcpy(outBufPtr, buf.get_ptr(), totalLength);
2583   outBufPtr += totalLength;
2584   *maxLength -= totalLength;
2585
2586   debugprintf(21, "bufSecurityData:");
2587   debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
2588
2589   return outBufPtr;
2590 }
2591
2592 unsigned char *USM::build_whole_msg(
2593                          unsigned char *outBuf, int *maxLength,
2594                          unsigned char *globalData, long int globalDataLength,
2595                          int *positionAuthPar,
2596                          struct UsmSecurityParameters  securityParameters,
2597                          unsigned char *msgData, long int msgDataLength)
2598 {
2599   Buffer<unsigned char> buf(MAX_SNMP_PACKET);
2600   unsigned char *bufPtr = buf.get_ptr();
2601   Buffer<unsigned char> secPar(MAX_SNMP_PACKET);
2602   unsigned char *secParPtr = secPar.get_ptr();
2603   unsigned char *outBufPtr = outBuf;
2604   long int secParLength;
2605   int length = *maxLength;
2606   int totalLength;
2607
2608   int dummy = *maxLength;
2609
2610   secParPtr = build_sec_params(secParPtr, &dummy, securityParameters,
2611                                positionAuthPar);
2612
2613   if (!secParPtr)
2614     return NULL;
2615   secParLength = SAFE_INT_CAST(secParPtr - secPar.get_ptr());
2616
2617   long int dummyVersion = 3;
2618   debugprintf(3, "Coding int snmpVersion = 0x%lx",dummyVersion);
2619   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
2620                          &dummyVersion);
2621   if (bufPtr == NULL) {
2622     debugprintf(0, "usmBuildWholeMsg error");
2623     return NULL;
2624   }
2625
2626   // globalData is encoded as sequence
2627   length -= globalDataLength;
2628   if (length < 0) {
2629     debugprintf(0, "usmBuildWholeMsg error");
2630     return NULL;
2631   }
2632   memcpy(bufPtr, globalData, globalDataLength);
2633   bufPtr += globalDataLength;
2634
2635   *positionAuthPar += SAFE_INT_CAST(bufPtr - buf.get_ptr()) +2;
2636   if (secParLength> 0x7f)
2637     *positionAuthPar += 2;
2638
2639   debugprintf(3, "Coding octstr securityParameter, length = 0x%lx",
2640               secParLength);
2641   bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
2642                             secPar.get_ptr(), secParLength);
2643
2644   if (bufPtr == NULL) {
2645     debugprintf(0, "usmBuildWholeMsg error2");
2646     return NULL;
2647   }
2648
2649   // msgData (ScopedPduData) is encoded
2650   length -=msgDataLength;
2651   if (length < 0) {
2652     debugprintf(10, "usmBuildWholeMsg error: msgDataLength = %i",
2653                 msgDataLength);
2654     debugprintf(10, "maxLength = %i, encoded = %i", *maxLength,
2655                 SAFE_INT_CAST(bufPtr - buf.get_ptr()));
2656     return NULL;
2657   }
2658   memcpy(bufPtr, msgData, msgDataLength);
2659   bufPtr += msgDataLength;
2660
2661   totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
2662
2663   debugprintf(3, "Coding sequence (wholeMsg), length = 0x%x", totalLength);
2664
2665   outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
2666                                  totalLength);
2667
2668   if (outBufPtr == NULL) {
2669     debugprintf(0, "usm: usmBuildWholeMsg error");
2670     return NULL;
2671   }
2672
2673   if (*maxLength < totalLength) {
2674     debugprintf(0, "usm: usmBuildWholeMsg error");
2675     return NULL;
2676   }
2677   *positionAuthPar += SAFE_INT_CAST(outBufPtr - outBuf);
2678   memcpy(outBufPtr, buf.get_ptr(), totalLength);
2679   outBufPtr += totalLength;
2680   *maxLength -= totalLength;
2681
2682   debugprintf(21,"bufWholeMsg:");
2683   debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
2684
2685   return outBufPtr;
2686 }
2687
2688 inline void USM::delete_user_ptr(struct UsmUser *user)
2689 {
2690   if (!user) return;
2691   if (user->engineID) {
2692     delete [] user->engineID;
2693     user->engineID = NULL;
2694   }
2695   if (user->usmUserName) {
2696     delete [] user->usmUserName;
2697     user->usmUserName = NULL;
2698   }
2699   if (user->securityName) {
2700     delete [] user->securityName;
2701     user->securityName = NULL;
2702   }
2703   if (user->authKey) {
2704     memset(user->authKey, 0, user->authKeyLength);
2705     delete [] user->authKey;
2706     user->authKey = NULL;
2707   }
2708   if (user->privKey) {
2709     memset(user->privKey, 0, user->privKeyLength);
2710     delete [] user->privKey;
2711     user->authKey = NULL;
2712   }
2713 }
2714
2715 // Save all localized users into a file.
2716 int USM::save_localized_users(const char *file)
2717 {
2718   return usm_user_table->save_to_file(file, auth_priv);
2719 }
2720
2721 // Load localized users from a file.
2722 int USM::load_localized_users(const char *file)
2723 {
2724   return usm_user_table->load_from_file(file, auth_priv);
2725 }
2726
2727 // Safe all users with their passwords into a file.
2728 int USM::save_users(const char *file)
2729 {
2730   return usm_user_name_table->save_to_file(file, auth_priv);
2731 }
2732
2733 // Load users with their passwords from a file.
2734 int USM::load_users(const char *file)
2735 {
2736   return usm_user_name_table->load_from_file(file, auth_priv);
2737 }
2738
2739 // Lock the UsmUserNameTable for access through peek_first/next_user()
2740 void USM::lock_user_name_table()
2741 {
2742   usm_user_name_table->lock();
2743 }
2744
2745 // Get a const pointer to the first entry of the UsmUserNameTable.
2746 const UsmUserNameTableEntry *USM::peek_first_user()
2747 {
2748   return usm_user_name_table->peek_first();
2749 }
2750
2751 // Get a const pointer to the next entry of the UsmUserNameTable.
2752 const UsmUserNameTableEntry *USM::peek_next_user(const UsmUserNameTableEntry *e)
2753 {
2754   return usm_user_name_table->peek_next(e);
2755 }
2756
2757 // Unlock the UsmUserNameTable after access through peek_first/next_user()
2758 void USM::unlock_user_name_table()
2759 {
2760   usm_user_name_table->unlock();
2761 }
2762
2763 // Lock the UsmUserTable for access through peek_first/next_luser()
2764 void USM::lock_user_table()
2765 {
2766   usm_user_table->lock();
2767 }
2768
2769 // Get a const pointer to the first entry of the UsmUserTable.
2770 const UsmUserTableEntry *USM::peek_first_luser()
2771 {
2772   return usm_user_table->peek_first();
2773 }
2774
2775 // Get a const pointer to the next entry of the UsmUserTable.
2776 const UsmUserTableEntry *USM::peek_next_luser(const UsmUserTableEntry *e)
2777 {
2778   return usm_user_table->peek_next(e);
2779 }
2780
2781 // Unlock the UsmUserTable after access through peek_first/next_luser()
2782 void USM::unlock_user_table()
2783 {
2784   usm_user_table->unlock();
2785 }
2786
2787
2788 /* ----------------------- class USMTimeTable --------------------*/
2789
2790 USMTimeTable::USMTimeTable(const USM *owner,
2791                            const unsigned int engine_boots, int &result)
2792 {
2793   time_t now;
2794
2795   table = new struct Entry_T[5];
2796
2797   if (!table)
2798   {
2799     LOG_BEGIN(ERROR_LOG | 1);
2800     LOG("USMTimeTable: error constructing table.");
2801     LOG_END;
2802
2803     result = SNMPv3_USM_ERROR;
2804     return;
2805   }
2806
2807   usm = owner;
2808
2809   /* the first entry always contains the local engine id and time */
2810   time(&now);
2811
2812   table[0].time_diff     = - SAFE_LONG_CAST(now);
2813   table[0].engine_boots  = engine_boots;
2814   table[0].engine_id_len = min(usm->get_local_engine_id().len(),
2815                                MAXLENGTH_ENGINEID);
2816   memcpy(table[0].engine_id, usm->get_local_engine_id().data(),
2817          table[0].engine_id_len);
2818
2819   entries = 1;
2820   max_entries = 5;
2821
2822   result = SNMPv3_USM_OK;
2823 }
2824
2825 USMTimeTable::~USMTimeTable()
2826 {
2827   if (table)
2828   {
2829     delete [] table;
2830     table = NULL;
2831   }
2832   entries = 0;
2833   max_entries = 0;
2834 }
2835
2836 int USMTimeTable::add_entry(const OctetStr &engine_id,
2837                             const long int engine_boots,
2838                             const long int engine_time)
2839 {
2840   if (!table)
2841     return SNMPv3_USM_ERROR;
2842
2843   LOG_BEGIN(INFO_LOG | 11);
2844   LOG("USMTimeTable: Adding entry (engine id) (boot) (time)");
2845   LOG(engine_id.get_printable());
2846   LOG(engine_boots);
2847   LOG(engine_time);
2848   LOG_END;
2849
2850   BEGIN_REENTRANT_CODE_BLOCK;
2851
2852   if (entries == max_entries)
2853   {
2854     /* resize Table */
2855     struct Entry_T *tmp = new struct Entry_T[4 * max_entries];
2856
2857     if (!tmp)
2858       return SNMPv3_USM_ERROR;
2859
2860     memcpy(tmp, table, entries * sizeof(Entry_T));
2861
2862     struct Entry_T *victim = table;
2863     table = tmp;
2864     delete [] victim;
2865
2866     max_entries *= 4;
2867   }
2868
2869   time_t now;
2870   time(&now);
2871
2872   table[entries].engine_boots = engine_boots;
2873   table[entries].latest_received_time = engine_time;
2874   table[entries].time_diff = engine_time - SAFE_ULONG_CAST(now);
2875   table[entries].engine_id_len = engine_id.len();
2876   table[entries].engine_id_len = min(table[entries].engine_id_len,
2877                                      MAXLENGTH_ENGINEID);
2878   memcpy(table[entries].engine_id,
2879          engine_id.data(), table[entries].engine_id_len);
2880
2881   entries++;
2882
2883   return SNMPv3_USM_OK;
2884 }
2885
2886 // Delete this engine id from the table.
2887 int USMTimeTable::delete_entry(const OctetStr &engine_id)
2888 {
2889   if (!table)
2890     return SNMPv3_USM_ERROR;
2891
2892   LOG_BEGIN(INFO_LOG | 12);
2893   LOG("USMTimeTable: Deleting entry (engine id)");
2894   LOG(engine_id.get_printable());
2895   LOG_END;
2896
2897   BEGIN_REENTRANT_CODE_BLOCK;
2898
2899   for (int i=1; i < entries; i++) /* start from 1 */
2900     if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
2901                             engine_id.data(), engine_id.len()))
2902     {
2903       if (i != entries - 1)
2904         table[i] = table[entries - 1];
2905
2906       entries--;
2907
2908       return SNMPv3_USM_OK;
2909     }
2910
2911   return SNMPv3_USM_OK;
2912 }
2913
2914 unsigned long USMTimeTable::get_local_time()
2915 {
2916   if (!table)
2917     return 0;
2918
2919   BEGIN_REENTRANT_CODE_BLOCK;
2920
2921   time_t now;
2922   time(&now);
2923
2924   return table[0].time_diff + SAFE_ULONG_CAST(now);
2925 }
2926
2927 int USMTimeTable::get_local_time(long int &engine_boots,
2928                                  long int &engine_time)
2929 {
2930   if (!table)
2931     return SNMPv3_USM_ERROR;
2932
2933   BEGIN_REENTRANT_CODE_BLOCK;
2934
2935   time_t now;
2936   time(&now);
2937
2938   engine_boots = table[0].engine_boots;
2939   engine_time  = table[0].time_diff + SAFE_ULONG_CAST(now);
2940
2941   LOG_BEGIN(DEBUG_LOG | 11);
2942   LOG("USMTimeTable: returning local time (boots) (time)");
2943   LOG(engine_boots);
2944   LOG(engine_time);
2945   LOG_END;
2946
2947   return SNMPv3_USM_OK;
2948 }
2949
2950 int USMTimeTable::get_time(const OctetStr &engine_id,
2951                            long int &engine_boots, long int &engine_time)
2952 {
2953   if (!table)
2954     return SNMPv3_USM_ERROR;
2955
2956   BEGIN_REENTRANT_CODE_BLOCK;
2957
2958   for (int i=0; i < entries; i++)
2959     if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
2960                             engine_id.data(), engine_id.len()))
2961     {
2962       /* Entry found */
2963       time_t now;
2964       time(&now);
2965
2966       engine_boots = table[i].engine_boots;
2967       engine_time  = table[i].time_diff + SAFE_ULONG_CAST(now);
2968
2969       LOG_BEGIN(INFO_LOG | 4);
2970       LOG("USMTimeTable: Returning time (engine id) (boot) (time)");
2971       LOG(engine_id.get_printable());
2972       LOG(engine_boots);
2973       LOG(engine_time);
2974       LOG_END;
2975
2976       return SNMPv3_USM_OK;
2977     }
2978
2979   /* no entry */
2980   engine_boots = 0;
2981   engine_time = 0;
2982
2983   LOG_BEGIN(INFO_LOG | 4);
2984   LOG("USMTimeTable: No entry found for (engine id)");
2985   LOG(engine_id.get_printable());
2986   LOG_END;
2987
2988   return SNMPv3_USM_UNKNOWN_ENGINEID;
2989 }
2990
2991 int USMTimeTable::check_time(const OctetStr &engine_id,
2992                              const long int engine_boots,
2993                              const long int engine_time)
2994
2995 {
2996   if (!table)
2997     return SNMPv3_USM_ERROR;
2998
2999   BEGIN_REENTRANT_CODE_BLOCK;
3000
3001   time_t now;
3002   time(&now);
3003
3004   /* table[0] contains the local engine_id and time */
3005   if (unsignedCharCompare(table[0].engine_id, table[0].engine_id_len,
3006                           engine_id.data(), engine_id.len()))
3007   {
3008     /* Entry found, we are authoritative */
3009     if ((table[0].engine_boots == 2147483647) ||
3010         (table[0].engine_boots != engine_boots) ||
3011         (labs(SAFE_ULONG_CAST(now) + table[0].time_diff - engine_time) > 150))
3012     {
3013       LOG_BEGIN(DEBUG_LOG | 9);
3014       LOG("USMTimeTable: Check time failed, authoritative (id) (boot) (time)");
3015       LOG(engine_id.get_printable());
3016       LOG(engine_boots);
3017       LOG(engine_time);
3018       LOG_END;
3019
3020       return SNMPv3_USM_NOT_IN_TIME_WINDOW;
3021     }
3022     else
3023     {
3024       LOG_BEGIN(DEBUG_LOG | 9);
3025       LOG("USMTimeTable: Check time ok, authoritative (id)");
3026       LOG(engine_id.get_printable());
3027       LOG_END;
3028
3029       return SNMPv3_USM_OK;
3030     }
3031   }
3032
3033   for (int i=1; i < entries; i++)
3034     if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
3035                             engine_id.data(), engine_id.len()))
3036     {
3037       /* Entry found we are not authoritative */
3038       if ((engine_boots < table[i].engine_boots) ||
3039           ((engine_boots == table[i].engine_boots) &&
3040            (table[i].time_diff + now > engine_time + 150)) ||
3041           (table[i].engine_boots == 2147483647))
3042       {
3043         LOG_BEGIN(DEBUG_LOG | 9);
3044         LOG("USMTimeTable: Check time failed, not authoritative (id)");
3045         LOG(engine_id.get_printable());
3046         LOG_END;
3047
3048         return SNMPv3_USM_NOT_IN_TIME_WINDOW;
3049       }
3050       else
3051       {
3052         if ((engine_boots > table[i].engine_boots) ||
3053             ((engine_boots == table[i].engine_boots) &&
3054              (engine_time > table[i].latest_received_time)))
3055         {
3056           /* time ok, update values */
3057           table[i].engine_boots = engine_boots;
3058           table[i].latest_received_time  = engine_time;
3059           table[i].time_diff = engine_time - SAFE_ULONG_CAST(now);
3060         }
3061
3062         LOG_BEGIN(DEBUG_LOG | 9);
3063         LOG("USMTimeTable: Check time ok, not authoritative, updated (id)");
3064         LOG(engine_id.get_printable());
3065         LOG_END;
3066
3067         return SNMPv3_USM_OK;
3068       }
3069     }
3070
3071   LOG_BEGIN(DEBUG_LOG | 9);
3072   LOG("USMTimeTable: Check time, engine id not found");
3073   LOG(engine_id.get_printable());
3074   LOG_END;
3075
3076   return SNMPv3_USM_UNKNOWN_ENGINEID;
3077 }
3078
3079
3080 int USMTimeTable::check_engine_id(const OctetStr &engine_id)
3081 {
3082   if (!table)
3083     return SNMPv3_USM_ERROR;
3084
3085   {
3086     // Begin reentrant code block
3087     BEGIN_REENTRANT_CODE_BLOCK;
3088
3089     for (int i=0; i < entries; i++)
3090       if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
3091                               engine_id.data(), engine_id.len()))
3092         return SNMPv3_USM_OK;
3093   }
3094
3095   /* if in discovery mode:  accept all EngineID's (rfc2264 page 26) */
3096   if (usm->is_discovery_enabled())
3097     return add_entry(engine_id, 0, 0);
3098
3099   LOG_BEGIN(DEBUG_LOG | 9);
3100   LOG("USMTimeTable: Check id, not found (id)");
3101   LOG(engine_id.get_printable());
3102   LOG_END;
3103
3104   return SNMPv3_USM_ERROR;
3105 }
3106
3107
3108
3109 /* ------------------------- USMUserNameTable ----------------------*/
3110
3111 USMUserNameTable::USMUserNameTable(int &result)
3112 {
3113   /* init Table */
3114   table = new struct UsmUserNameTableEntry[10];
3115   if (!table)
3116   {
3117     result = SNMPv3_USM_ERROR;
3118     return;
3119   }
3120   max_entries = 10;
3121   entries = 0;
3122   result = SNMPv3_USM_OK;
3123 }
3124
3125 USMUserNameTable::~USMUserNameTable()
3126 {
3127   if (table)
3128   {
3129     for (int i=0; i < entries; i++)
3130     {
3131       if (table[i].authPassword)
3132       {
3133         memset(table[i].authPassword, 0, table[i].authPasswordLength);
3134         delete [] table[i].authPassword;
3135       }
3136
3137       if (table[i].privPassword)
3138       {
3139         memset(table[i].privPassword, 0, table[i].privPasswordLength);
3140         delete [] table[i].privPassword;
3141       }
3142     }
3143     delete [] table;
3144     table = NULL;
3145   }
3146   entries = 0;
3147   max_entries = 0;
3148 }
3149
3150 int USMUserNameTable::add_entry(const OctetStr& user_name,
3151                                 const OctetStr& security_name,
3152                                 const long int  auth_proto,
3153                                 const long int  priv_proto,
3154                                 const OctetStr& auth_pass,
3155                                 const OctetStr& priv_pass)
3156 {
3157   if (!table)
3158     return SNMPv3_USM_ERROR;
3159
3160   BEGIN_REENTRANT_CODE_BLOCK;
3161
3162   int found=0;
3163   int i;
3164   for (i = 0; i < entries; i++)
3165     if (table[i].usmUserName == user_name)
3166     {
3167       found=1;
3168       break;
3169     }
3170
3171   if (found)
3172   {
3173     /* replace user */
3174     table[i].usmUserSecurityName = security_name;
3175     table[i].usmUserAuthProtocol = auth_proto;
3176     table[i].usmUserPrivProtocol = priv_proto;
3177
3178     if (table[i].authPassword)
3179     {
3180       memset(table[i].authPassword, 0, table[i].authPasswordLength);
3181       delete [] table[i].authPassword;
3182     }
3183     table[i].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
3184     table[i].authPasswordLength = auth_pass.len();
3185
3186     if (table[i].privPassword)
3187     {
3188       memset(table[i].privPassword, 0, table[i].privPasswordLength);
3189       delete [] table[i].privPassword;
3190     }
3191     table[i].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
3192     table[i].privPasswordLength = priv_pass.len();
3193   }
3194   else
3195   {
3196     if (entries == max_entries)
3197     {
3198       /* resize Table */
3199       struct UsmUserNameTableEntry *tmp;
3200       tmp = new struct UsmUserNameTableEntry[4 * max_entries];
3201       if (!tmp)
3202         return SNMPv3_USM_ERROR;
3203       for (i=0; i < entries; i++)
3204         tmp[i] = table[i];
3205
3206       struct UsmUserNameTableEntry *victim = table;
3207       table = tmp;
3208       delete [] victim;
3209
3210       max_entries *= 4;
3211     }
3212
3213     table[entries].usmUserName          = user_name;
3214     table[entries].usmUserSecurityName  = security_name;
3215     table[entries].usmUserAuthProtocol  = auth_proto;
3216     table[entries].usmUserPrivProtocol  = priv_proto;
3217
3218     table[entries].authPasswordLength = auth_pass.len();
3219     table[entries].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
3220     if (!table[entries].authPassword)
3221       return SNMPv3_USM_ERROR;
3222
3223     table[entries].privPasswordLength = priv_pass.len();
3224     table[entries].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
3225     if (!table[entries].privPassword)
3226       return SNMPv3_USM_ERROR;
3227
3228     entries++;
3229   }
3230
3231   return SNMPv3_USM_OK;
3232 }
3233
3234 int USMUserNameTable::delete_security_name(const OctetStr& security_name)
3235 {
3236   if (!table)
3237     return SNMPv3_USM_ERROR;
3238
3239   BEGIN_REENTRANT_CODE_BLOCK;
3240
3241   for (int i = 0; i < entries; i++)
3242     if (table[i].usmUserSecurityName == security_name)
3243     {
3244       memset(table[i].authPassword, 0, table[i].authPasswordLength);
3245       delete [] table[i].authPassword;
3246       memset(table[i].privPassword, 0, table[i].privPasswordLength);
3247       delete [] table[i].privPassword;
3248       entries--;
3249       if (entries > i)
3250         table[i] = table[entries];
3251       break;
3252     }
3253   return SNMPv3_USM_OK;
3254 }
3255
3256 const struct UsmUserNameTableEntry* USMUserNameTable::get_entry(
3257                                           const OctetStr &security_name)
3258 {
3259   if (!table)
3260     return NULL;
3261
3262   for (int i = 0; i < entries; i++)
3263     if (table[i].usmUserSecurityName == security_name)
3264       return &table[i];
3265   return NULL;
3266 }
3267
3268 struct UsmUserNameTableEntry* USMUserNameTable::get_cloned_entry(const OctetStr &security_name)
3269 {
3270   lock();
3271   const struct UsmUserNameTableEntry *e = get_entry(security_name);
3272   struct UsmUserNameTableEntry *res = 0;
3273
3274   if (e)
3275   {
3276     res = new struct UsmUserNameTableEntry;
3277   }
3278
3279   if (res)
3280   {
3281     res->usmUserName = e->usmUserName;
3282     res->usmUserSecurityName = e->usmUserSecurityName;
3283     res->usmUserAuthProtocol = e->usmUserAuthProtocol;
3284     res->usmUserPrivProtocol = e->usmUserPrivProtocol;
3285     res->authPassword = v3strcpy(e->authPassword, e->authPasswordLength);
3286     res->authPasswordLength = e->authPasswordLength;
3287     res->privPassword = v3strcpy(e->privPassword, e->privPasswordLength);
3288     res->privPasswordLength = e->privPasswordLength;
3289
3290     if ((res->authPasswordLength && !res->authPassword) ||
3291         (res->privPasswordLength && !res->privPassword))
3292     {
3293       delete_cloned_entry(res);
3294     }
3295   }
3296
3297   unlock();
3298   return res;
3299 }
3300
3301 void USMUserNameTable::delete_cloned_entry(struct UsmUserNameTableEntry* &entry)
3302 {
3303   if (!entry) return;
3304
3305   if (entry->authPassword)
3306   {
3307     memset(entry->authPassword, 0, entry->authPasswordLength);
3308     delete [] entry->authPassword;
3309   }
3310
3311   if (entry->privPassword)
3312   {
3313     memset(entry->privPassword, 0, entry->privPasswordLength);
3314     delete [] entry->privPassword;
3315   }
3316
3317   delete entry;
3318
3319   entry = 0;
3320 }
3321
3322
3323 int USMUserNameTable::get_security_name(const unsigned char *user_name,
3324                                         const long int user_name_len,
3325                                         OctetStr &security_name)
3326 {
3327   if (!table)
3328     return SNMPv3_USM_ERROR;
3329
3330   BEGIN_REENTRANT_CODE_BLOCK;
3331
3332   for (int i = 0; i < entries; i++)
3333     if (unsignedCharCompare(table[i].usmUserName.data(),
3334                             table[i].usmUserName.len(),
3335                             user_name, user_name_len))
3336     {
3337       security_name = table[i].usmUserSecurityName;
3338
3339       LOG_BEGIN(INFO_LOG | 9);
3340       LOG("USMUserNameTable: Translated (user name) to (security name)");
3341       LOG(table[i].usmUserName.get_printable());
3342       LOG(security_name.get_printable());
3343       LOG_END;
3344
3345       return SNMPv3_USM_OK;
3346     }
3347
3348   int logclass = WARNING_LOG;
3349   if (user_name_len == 0) logclass = INFO_LOG;
3350   LOG_BEGIN(logclass | 5);
3351   LOG("USMUserNameTable: No entry for (user name) in table");
3352   LOG(OctetStr(user_name, user_name_len).get_printable());
3353   LOG_END;
3354
3355   return SNMPv3_USM_ERROR;
3356 }
3357
3358 int USMUserNameTable::get_user_name(unsigned char *user_name,
3359                                     long int *user_name_len,
3360                                     const unsigned char *security_name,
3361                                     const long int security_name_len)
3362 {
3363   unsigned long buf_len = *user_name_len;
3364   *user_name_len = 0;
3365
3366   if (!table)
3367     return SNMPv3_USM_ERROR;
3368
3369   BEGIN_REENTRANT_CODE_BLOCK;
3370
3371   for (int i = 0; i < entries; i++)
3372     if (unsignedCharCompare(table[i].usmUserSecurityName.data(),
3373                             table[i].usmUserSecurityName.len(),
3374                             security_name, security_name_len))
3375     {
3376       if (buf_len < table[i].usmUserName.len())
3377       {
3378           LOG_BEGIN(ERROR_LOG | 1);
3379           LOG("USMUserNameTable: Buffer for user name too small (is) (should)");
3380           LOG(buf_len);
3381           LOG(table[i].usmUserName.len());
3382           LOG_END;
3383
3384         return SNMPv3_USM_ERROR;
3385       }
3386       *user_name_len = table[i].usmUserName.len();
3387       memcpy(user_name, table[i].usmUserName.data(),
3388              table[i].usmUserName.len());
3389
3390       LOG_BEGIN(INFO_LOG | 9);
3391       LOG("USMUserNameTable: Translated (security name) to (user name)");
3392       LOG(table[i].usmUserSecurityName.get_printable());
3393       LOG(table[i].usmUserName.get_printable());
3394       LOG_END;
3395
3396       return SNMPv3_USM_OK;
3397     }
3398
3399   int logclass = WARNING_LOG;
3400   if (security_name_len == 0) logclass = INFO_LOG;
3401   LOG_BEGIN(logclass | 5);
3402   LOG("USMUserNameTable: No entry for (security  name) in table");
3403   LOG(OctetStr(security_name, security_name_len).get_printable());
3404   LOG_END;
3405
3406   return SNMPv3_USM_ERROR;
3407 }
3408
3409 // Save all entries into a file.
3410 int USMUserNameTable::save_to_file(const char *name, AuthPriv *ap)
3411 {
3412   char encoded[MAX_LINE_LEN * 2];
3413   FILE *file_out;
3414   char tmp_file_name[MAXLENGTH_FILENAME];
3415   bool failed = false;
3416
3417   if (!name || !ap)
3418   {
3419     LOG_BEGIN(ERROR_LOG | 1);
3420     LOG("USMUserNameTable: save_to_file called with illegal param");
3421     if (!name)
3422     {
3423       LOG("filename");
3424     }
3425     if (!ap)
3426     {
3427       LOG("AuthPriv pointer");
3428     }
3429     LOG_END;
3430
3431     return SNMPv3_USM_ERROR;
3432   }
3433
3434   LOG_BEGIN(INFO_LOG | 4);
3435   LOG("USMUserNameTable: Saving users to file");
3436   LOG(name);
3437   LOG_END;
3438
3439   sprintf(tmp_file_name, "%s.tmp", name);
3440   file_out = fopen(tmp_file_name, "w");
3441   if (!file_out)
3442   {
3443     LOG_BEGIN(ERROR_LOG | 1);
3444     LOG("USMUserNameTable: could not create tmpfile");
3445     LOG(tmp_file_name);
3446     LOG_END;
3447
3448     return SNMPv3_USM_FILECREATE_ERROR;
3449   }
3450
3451   {
3452     // Begin reentrant code block
3453     BEGIN_REENTRANT_CODE_BLOCK;
3454
3455     for (int i=0; i < entries; ++i)
3456     {
3457       LOG_BEGIN(INFO_LOG | 8);
3458       LOG("USMUserNameTable: Saving user to file");
3459       LOG(table[i].usmUserName.get_printable());
3460       LOG_END;
3461
3462       encodeString(table[i].usmUserName.data(), table[i].usmUserName.len(),
3463                    encoded);
3464       encoded[2 * table[i].usmUserName.len()] = '\n';
3465       if (fwrite(encoded, 2 * table[i].usmUserName.len() + 1, 1,
3466                  file_out) != 1)
3467       { failed = true; break; }
3468
3469       encodeString(table[i].usmUserSecurityName.data(),
3470                    table[i].usmUserSecurityName.len(), encoded);
3471       encoded[2 * table[i].usmUserSecurityName.len()] = '\n';
3472       if (fwrite(encoded, 2 * table[i].usmUserSecurityName.len() + 1, 1,
3473                  file_out) != 1)
3474       { failed = true; break; }
3475
3476       encodeString(table[i].authPassword, table[i].authPasswordLength,
3477                    encoded);
3478       encoded[2 * table[i].authPasswordLength] = '\n';
3479       if (fwrite(encoded, 2 * table[i].authPasswordLength + 1, 1,
3480                  file_out) != 1)
3481       { failed = true; break; }
3482
3483       encodeString(table[i].privPassword, table[i].privPasswordLength,
3484                    encoded);
3485       encoded[2 * table[i].privPasswordLength] = '\n';
3486       if (fwrite(encoded, 2 * table[i].privPasswordLength + 1, 1,
3487                  file_out) != 1)
3488       { failed = true; break; }
3489
3490       if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
3491       {
3492         if (fwrite("none\n", 5, 1, file_out) != 1)
3493         { failed = true; break; }
3494       }
3495       else
3496       {
3497         const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
3498         if (!a) { failed = true; break; }
3499         sprintf(encoded, "%s\n", a->get_id_string());
3500         if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
3501         { failed = true; break; }
3502       }
3503
3504       if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
3505       {
3506         if (fwrite("none\n", 5, 1, file_out) != 1)
3507         { failed = true; break; }
3508       }
3509       else
3510       {
3511         const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
3512         if (!p) { failed = true; break; }
3513         sprintf(encoded, "%s\n", p->get_id_string());
3514         if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
3515         { failed = true; break; }
3516       }
3517     }
3518   }
3519
3520   fclose(file_out);
3521   if (failed)
3522   {
3523     LOG_BEGIN(ERROR_LOG | 1);
3524     LOG("USMUserNameTable: Failed to write table entries.");
3525     LOG_END;
3526
3527 #ifdef WIN32
3528     _unlink(tmp_file_name);
3529 #else
3530     unlink(tmp_file_name);
3531 #endif
3532     return SNMPv3_USM_FILEWRITE_ERROR;
3533   }
3534 #ifdef WIN32
3535   _unlink(name);
3536 #else
3537   unlink(name);
3538 #endif
3539   if (rename(tmp_file_name, name))
3540   {
3541     LOG_BEGIN(ERROR_LOG | 1);
3542     LOG("USMUserNameTable: Could not rename file (from) (to)");
3543     LOG(tmp_file_name);
3544     LOG(name);
3545     LOG_END;
3546
3547     return SNMPv3_USM_FILERENAME_ERROR;
3548   }
3549
3550   LOG_BEGIN(INFO_LOG | 4);
3551   LOG("USMUserNameTable: Saving users to file finished");
3552   LOG_END;
3553
3554   return SNMPv3_USM_OK;
3555 }
3556
3557 // Load the table from a file.
3558 int USMUserNameTable::load_from_file(const char *name, AuthPriv *ap)
3559 {
3560   char decoded[MAX_LINE_LEN];
3561   FILE *file_in;
3562   unsigned char line[MAX_LINE_LEN * 2];
3563
3564   if (!name || !ap)
3565   {
3566     LOG_BEGIN(ERROR_LOG | 1);
3567     LOG("USMUserNameTable: load_to_file called with illegal param");
3568     if (!name)
3569     {
3570       LOG("filename");
3571     }
3572     if (!ap)
3573     {
3574       LOG("AuthPriv pointer");
3575     }
3576     LOG_END;
3577
3578     return SNMPv3_USM_ERROR;
3579   }
3580
3581   LOG_BEGIN(INFO_LOG | 4);
3582   LOG("USMUserNameTable: Loading users from file");
3583   LOG(name);
3584   LOG_END;
3585
3586   file_in = fopen(name, "r");
3587   if (!file_in)
3588   {
3589     LOG_BEGIN(ERROR_LOG | 1);
3590     LOG("USMUserNameTable: could not open file");
3591     LOG(name);
3592     LOG_END;
3593
3594     return SNMPv3_USM_FILEOPEN_ERROR;
3595   }
3596
3597   int len;
3598   bool failed = false;
3599   while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3600   {
3601     // user_name
3602     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
3603     decodeString(line, len, decoded);
3604     OctetStr user_name((unsigned char*)decoded, len / 2);
3605
3606     // security_name
3607     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3608     { failed = true; break; }
3609     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
3610     decodeString(line, len, decoded);
3611     OctetStr user_security_name((unsigned char*)decoded, len / 2);
3612
3613     // auth password
3614     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3615     { failed = true; break; }
3616     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
3617     decodeString(line, len, decoded);
3618     OctetStr auth_pass((unsigned char*)decoded, len / 2);
3619
3620     // priv password
3621     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3622     { failed = true; break; }
3623     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
3624     decodeString(line, len, decoded);
3625     OctetStr priv_pass((unsigned char*)decoded, len / 2);
3626
3627     // auth protocol
3628     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3629     { failed = true; break; }
3630     line[strlen((char*)line) - 1] = 0;
3631     int auth_prot = SNMP_AUTHPROTOCOL_NONE;
3632     if (strcmp((char*)line, "none") != 0)
3633     {
3634       auth_prot = ap->get_auth_id((char*)line);
3635       if (auth_prot < 0)
3636       { failed = true; break; }
3637     }
3638
3639     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
3640     { failed = true; break; }
3641     line[strlen((char*)line) - 1] = 0;
3642     int priv_prot = SNMP_PRIVPROTOCOL_NONE;
3643     if (strcmp((char*)line, "none") != 0)
3644     {
3645       priv_prot = ap->get_priv_id((char*)line);
3646       if (priv_prot < 0)
3647       { failed = true; break; }
3648     }
3649
3650     LOG_BEGIN(INFO_LOG | 7);
3651     LOG("USMUserNameTable: Adding user (user name) (sec name) (auth) (priv)");
3652     LOG(user_name.get_printable());
3653     LOG(user_security_name.get_printable());
3654     LOG(auth_prot);
3655     LOG(priv_prot);
3656     LOG_END;
3657
3658     if (add_entry(user_name, user_security_name, auth_prot, priv_prot,
3659                   auth_pass, priv_pass) == SNMPv3_USM_ERROR)
3660     {
3661       failed = true;
3662
3663       LOG_BEGIN(ERROR_LOG | 1);
3664       LOG("USMUserNameTable: Error adding (user name)");
3665       LOG(user_name.get_printable());
3666       LOG_END;
3667     }
3668   }
3669
3670   fclose(file_in);
3671   if (failed)
3672   {
3673     LOG_BEGIN(ERROR_LOG | 1);
3674     LOG("USMUserNameTable: Failed to read table entries");
3675     LOG_END;
3676
3677     return SNMPv3_USM_FILEREAD_ERROR;
3678   }
3679
3680   LOG_BEGIN(INFO_LOG | 4);
3681   LOG("USMUserNameTable: Loaded all users from file");
3682   LOG_END;
3683
3684   return SNMPv3_USM_OK;
3685 }
3686
3687 const UsmUserNameTableEntry *USMUserNameTable::peek_next(
3688                        const UsmUserNameTableEntry *e) const
3689 {
3690   if (e == 0) return 0;
3691   if (e - table < 0) return 0;
3692   if (e - table >= entries - 1) return 0;
3693   return (e + 1);
3694 }
3695
3696 /* ---------------------------- USMUserTable ------------------- */
3697
3698 USMUserTable::USMUserTable(int &result)
3699 {
3700   entries = 0;
3701
3702   table = new struct UsmUserTableEntry[10];
3703   if (!table)
3704   {
3705     result = SNMPv3_USM_ERROR;
3706     return;
3707   }
3708   max_entries = 10;
3709 }
3710
3711 USMUserTable::~USMUserTable()
3712 {
3713   if (table)
3714   {
3715     for (int i = 0; i < entries; i++)
3716     {
3717       if (table[i].usmUserEngineID)
3718         delete [] table[i].usmUserEngineID;
3719       if (table[i].usmUserName)
3720         delete [] table[i].usmUserName;
3721       if (table[i].usmUserSecurityName)
3722         delete [] table[i].usmUserSecurityName;
3723       if (table[i].usmUserAuthKey)
3724       {
3725         memset(table[i].usmUserAuthKey, 0, table[i].usmUserAuthKeyLength);
3726         delete [] table[i].usmUserAuthKey;
3727       }
3728       if (table[i].usmUserPrivKey)
3729       {
3730         memset(table[i].usmUserPrivKey, 0, table[i].usmUserPrivKeyLength);
3731         delete [] table[i].usmUserPrivKey;
3732       }
3733     }
3734     delete [] table;
3735     table = NULL;
3736     max_entries = 0;
3737     entries = 0;
3738   }
3739 }
3740
3741 int USMUserTable::get_user_name(unsigned char       *user_name,
3742                                 long int            *user_name_len,
3743                                 const unsigned char *sec_name,
3744                                 const long           sec_name_len)
3745
3746 {
3747   long buf_len = *user_name_len;
3748   *user_name_len = 0;
3749
3750   if (!table)
3751     return SNMPv3_USM_ERROR;
3752
3753   BEGIN_REENTRANT_CODE_BLOCK;
3754
3755   for (int i=0; i < entries; i++)
3756     if (unsignedCharCompare(table[i].usmUserSecurityName,
3757                             table[i].usmUserSecurityNameLength,
3758                             sec_name, sec_name_len))
3759     {
3760       if (buf_len < table[i].usmUserNameLength)
3761       {
3762         LOG_BEGIN(ERROR_LOG | 1);
3763         LOG("USMUserTable: Buffer for user name too small (is) (should)");
3764         LOG(buf_len);
3765         LOG(table[i].usmUserNameLength);
3766         LOG_END;
3767
3768         return SNMPv3_USM_ERROR;
3769       }
3770       *user_name_len = table[i].usmUserNameLength;
3771       memcpy(user_name, table[i].usmUserName, table[i].usmUserNameLength);
3772
3773       LOG_BEGIN(INFO_LOG | 9);
3774       LOG("USMUserTable: Translated (security name) to (user name)");
3775       LOG(OctetStr(sec_name, sec_name_len).get_printable());
3776       LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
3777       LOG_END;
3778
3779       return SNMPv3_USM_OK;
3780     }
3781
3782   int logclass = WARNING_LOG;
3783   if (sec_name_len == 0) logclass = INFO_LOG;
3784   LOG_BEGIN(logclass | 5);
3785   LOG("USMUserTable: No entry for (security  name) in table");
3786   LOG(OctetStr(sec_name, sec_name_len).get_printable());
3787   LOG_END;
3788
3789   return SNMPv3_USM_ERROR;
3790 }
3791
3792 int USMUserTable::get_security_name(const unsigned char *user_name,
3793                                     const long user_name_len,
3794                                     OctetStr &sec_name)
3795 {
3796   if (!table)
3797     return SNMPv3_USM_ERROR;
3798
3799   BEGIN_REENTRANT_CODE_BLOCK;
3800
3801   for (int i=0; i < entries; i++)
3802     if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
3803                             user_name, user_name_len))
3804     {
3805       sec_name.set_data(table[i].usmUserSecurityName,
3806                         table[i].usmUserSecurityNameLength);
3807       LOG_BEGIN(INFO_LOG | 9);
3808       LOG("USMUserTable: Translated (user name) to (security name)");
3809       LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
3810       LOG(sec_name.get_printable());
3811       LOG_END;
3812
3813       return SNMPv3_USM_OK;
3814     }
3815
3816   int logclass = WARNING_LOG;
3817   if (user_name_len == 0) logclass = INFO_LOG;
3818   LOG_BEGIN(logclass | 5);
3819   LOG("USMUserTable: No entry for (user name) in table");
3820   LOG(OctetStr(user_name, user_name_len).get_printable());
3821   LOG_END;
3822
3823   return SNMPv3_USM_ERROR;
3824 }
3825
3826 int USMUserTable::delete_entries(const OctetStr& user_name)
3827 {
3828   if (!table)
3829     return SNMPv3_USM_ERROR;
3830
3831   BEGIN_REENTRANT_CODE_BLOCK;
3832
3833   for (int i = 0; i < entries; i++)
3834     if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
3835                             user_name.data(), user_name.len()))
3836     {
3837       /* delete this entry and recheck this position */
3838       delete_entry(i);
3839       i--;
3840     }
3841   return SNMPv3_USM_OK;
3842 }
3843
3844 // Delete all entries of this user from the usmUserTable
3845 int USMUserTable::delete_engine_id(const OctetStr& engine_id)
3846 {
3847   if (!table)
3848     return SNMPv3_USM_ERROR;
3849
3850   BEGIN_REENTRANT_CODE_BLOCK;
3851
3852   for (int i = 0; i < entries; i++)
3853     if (unsignedCharCompare(table[i].usmUserEngineID,
3854                             table[i].usmUserEngineIDLength,
3855                             engine_id.data(), engine_id.len()))
3856     {
3857       /* delete this entry and recheck this position*/
3858       delete_entry(i);
3859       i--;
3860     }
3861   return SNMPv3_USM_OK;
3862 }
3863
3864 int USMUserTable::delete_entry(const OctetStr& engine_id,
3865                                const OctetStr& user_name)
3866 {
3867   if (!table)
3868     return SNMPv3_USM_ERROR;
3869
3870   BEGIN_REENTRANT_CODE_BLOCK;
3871
3872   for (int i = 0; i < entries; i++)
3873     if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
3874                             user_name.data(), user_name.len()))
3875       if (unsignedCharCompare(table[i].usmUserEngineID,
3876                               table[i].usmUserEngineIDLength,
3877                               engine_id.data(), engine_id.len()))
3878       {
3879         /* delete this entry and recheck this position*/
3880         delete_entry(i);
3881         i--;
3882       }
3883   return SNMPv3_USM_OK;
3884 }
3885
3886 const struct UsmUserTableEntry *USMUserTable::get_entry(const int number)
3887 {
3888   if ((entries < number) || (number < 1))
3889     return NULL;
3890
3891   return &table[number - 1];
3892 }
3893
3894 const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &engine_id,
3895                                                         const OctetStr &sec_name)
3896 {
3897   if (!table)
3898     return NULL;
3899
3900   for (int i = 0; i < entries; i++)
3901     if (unsignedCharCompare(table[i].usmUserSecurityName,
3902                             table[i].usmUserSecurityNameLength,
3903                             sec_name.data(), sec_name.len()))
3904       if (unsignedCharCompare(table[i].usmUserEngineID,
3905                               table[i].usmUserEngineIDLength,
3906                               engine_id.data(), engine_id.len()))
3907         return &table[i];
3908   return NULL;
3909 }
3910
3911 struct UsmUserTableEntry *USMUserTable::get_cloned_entry(
3912                                  const OctetStr &engine_id,
3913                                  const OctetStr &sec_name)
3914 {
3915   lock();
3916   const struct UsmUserTableEntry *e = get_entry(engine_id, sec_name);
3917   struct UsmUserTableEntry *res = 0;
3918
3919   if (e)
3920   {
3921     res = new struct UsmUserTableEntry;
3922   }
3923
3924   if (res)
3925   {
3926     res->usmUserEngineID       = v3strcpy(e->usmUserEngineID,
3927                                           e->usmUserEngineIDLength);
3928     res->usmUserEngineIDLength = e->usmUserEngineIDLength;
3929     res->usmUserName           = v3strcpy(e->usmUserName,
3930                                           e->usmUserNameLength);
3931     res->usmUserNameLength     = e->usmUserNameLength;
3932     res->usmUserSecurityName   = v3strcpy(e->usmUserSecurityName,
3933                                           e->usmUserSecurityNameLength);
3934     res->usmUserSecurityNameLength = e->usmUserSecurityNameLength;
3935     res->usmUserAuthProtocol   = e->usmUserAuthProtocol;
3936     res->usmUserAuthKey        = v3strcpy(e->usmUserAuthKey,
3937                                           e->usmUserAuthKeyLength);
3938     res->usmUserAuthKeyLength  = e->usmUserAuthKeyLength;
3939     res->usmUserPrivProtocol   = e->usmUserPrivProtocol;
3940     res->usmUserPrivKey        = v3strcpy(e->usmUserPrivKey,
3941                                           e->usmUserPrivKeyLength);
3942     res->usmUserPrivKeyLength  = e->usmUserPrivKeyLength;
3943
3944     if ((res->usmUserEngineIDLength && !res->usmUserEngineID) ||
3945         (res->usmUserNameLength && !res->usmUserName) ||
3946         (res->usmUserSecurityNameLength && !res->usmUserSecurityName) ||
3947         (res->usmUserAuthKeyLength && !res->usmUserAuthKey) ||
3948         (res->usmUserPrivKeyLength && !res->usmUserPrivKey))
3949     {
3950       delete_cloned_entry(res);
3951     }
3952   }
3953
3954   unlock();
3955   return res;
3956 }
3957
3958 void USMUserTable::delete_cloned_entry(struct UsmUserTableEntry* &entry)
3959 {
3960   if (!entry) return;
3961
3962   if (entry->usmUserEngineID) delete [] entry->usmUserEngineID;
3963   if (entry->usmUserName)     delete [] entry->usmUserName;
3964   if (entry->usmUserSecurityName) delete [] entry->usmUserSecurityName;
3965
3966   if (entry->usmUserAuthKey)
3967   {
3968     memset(entry->usmUserAuthKey, 0, entry->usmUserAuthKeyLength);
3969     delete [] entry->usmUserAuthKey;
3970   }
3971
3972   if (entry->usmUserPrivKey)
3973   {
3974     memset(entry->usmUserPrivKey, 0, entry->usmUserPrivKeyLength);
3975     delete [] entry->usmUserPrivKey;
3976   }
3977
3978   delete entry;
3979
3980   entry = 0;
3981 }
3982
3983
3984 const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &sec_name)
3985 {
3986   if (!table)
3987     return NULL;
3988
3989   for (int i = 0; i < entries; i++)
3990     if (unsignedCharCompare(table[i].usmUserSecurityName,
3991                             table[i].usmUserSecurityNameLength,
3992                             sec_name.data(), sec_name.len()))
3993       return &table[i];
3994   return NULL;
3995 }
3996
3997 int USMUserTable::add_entry(
3998                       const OctetStr &engine_id,
3999                       const OctetStr &user_name,  const OctetStr &sec_name,
4000                       const long int  auth_proto, const OctetStr &auth_key,
4001                       const long int  priv_proto, const OctetStr &priv_key)
4002 {
4003   LOG_BEGIN(INFO_LOG | 7);
4004   LOG("USMUserTable: Adding user (user name) (engine id) (auth) (priv)");
4005   LOG(user_name.get_printable());
4006   LOG(engine_id.get_printable());
4007   LOG(auth_proto);
4008   LOG(priv_proto);
4009   LOG_END;
4010
4011   if (!table)
4012     return SNMPv3_USM_ERROR;
4013
4014   BEGIN_REENTRANT_CODE_BLOCK;
4015
4016   if (entries == max_entries)
4017   {
4018     /* resize Table */
4019     struct UsmUserTableEntry *tmp;
4020     tmp = new struct UsmUserTableEntry[4 * max_entries];
4021     if (!tmp) return SNMPv3_USM_ERROR;
4022     for (int i = 0; i < entries; i++)
4023       tmp[i] = table[i];
4024     delete [] table;
4025     table = tmp;
4026     max_entries *= 4;
4027   }
4028
4029   for (int i = 0; i < entries; i++)
4030     if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
4031                             user_name.data(), user_name.len()))
4032       if (unsignedCharCompare(table[i].usmUserEngineID,
4033                               table[i].usmUserEngineIDLength,
4034                               engine_id.data(), engine_id.len()))
4035       {
4036         /* delete this entry */
4037         delete_entry(i);
4038         break;
4039       }
4040
4041   /* add user at the last position */
4042   table[entries].usmUserEngineIDLength = engine_id.len();
4043   table[entries].usmUserEngineID       = v3strcpy(engine_id.data(),
4044                                                   engine_id.len());
4045   table[entries].usmUserNameLength     = user_name.len();
4046   table[entries].usmUserName           = v3strcpy(user_name.data(),
4047                                                   user_name.len());
4048   table[entries].usmUserSecurityNameLength = sec_name.len();
4049   table[entries].usmUserSecurityName   = v3strcpy(sec_name.data(),
4050                                                   sec_name.len());
4051   table[entries].usmUserAuthProtocol   = auth_proto;
4052   table[entries].usmUserAuthKeyLength  = auth_key.len();
4053   table[entries].usmUserAuthKey        = v3strcpy(auth_key.data(),
4054                                                   auth_key.len());
4055   table[entries].usmUserPrivProtocol   = priv_proto;
4056   table[entries].usmUserPrivKeyLength  = priv_key.len();
4057   table[entries].usmUserPrivKey        = v3strcpy(priv_key.data(),
4058                                                   priv_key.len());
4059   entries++;
4060   return SNMPv3_USM_OK;
4061 }
4062
4063 int USMUserTable::update_key(const OctetStr &user_name,
4064                              const OctetStr &engine_id,
4065                              const OctetStr &new_key,
4066                              const int key_type)
4067 {
4068   LOG_BEGIN(INFO_LOG | 7);
4069   LOG("USMUserTable: Update key for user (name) (engine id) (type)");
4070   LOG(user_name.get_printable());
4071   LOG(engine_id.get_printable());
4072   LOG(key_type);
4073   LOG_END;
4074
4075   if (!table)
4076     return SNMPv3_USM_ERROR;
4077
4078   BEGIN_REENTRANT_CODE_BLOCK;
4079
4080   for (int i = 0; i < entries; i++)
4081     if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
4082                             user_name.data(), user_name.len()))
4083       if (unsignedCharCompare(table[i].usmUserEngineID,
4084                               table[i].usmUserEngineIDLength,
4085                               engine_id.data(), engine_id.len()))
4086       {
4087         LOG_BEGIN(DEBUG_LOG | 15);
4088         LOG("USMUserTable: New key");
4089         LOG(new_key.get_printable());
4090         LOG_END;
4091
4092         /* update key: */
4093         switch (key_type)
4094         {
4095           case AUTHKEY:
4096           case OWNAUTHKEY:
4097           {
4098             if (table[i].usmUserAuthKey)
4099             {
4100               memset(table[i].usmUserAuthKey, 0,
4101                      table[i].usmUserAuthKeyLength);
4102               delete [] table[i].usmUserAuthKey;
4103             }
4104             table[i].usmUserAuthKeyLength = new_key.len();
4105             table[i].usmUserAuthKey = v3strcpy(new_key.data(), new_key.len());
4106             return SNMPv3_USM_OK;
4107           }
4108           case PRIVKEY:
4109           case OWNPRIVKEY:
4110           {
4111             if (table[i].usmUserPrivKey)
4112             {
4113               memset(table[i].usmUserPrivKey, 0,
4114                      table[i].usmUserPrivKeyLength);
4115               delete [] table[i].usmUserPrivKey;
4116             }
4117             table[i].usmUserPrivKeyLength = new_key.len();
4118             table[i].usmUserPrivKey = v3strcpy(new_key.data(), new_key.len());
4119             return SNMPv3_USM_OK;
4120           }
4121           default:
4122           {
4123             LOG_BEGIN(WARNING_LOG | 3);
4124             LOG("USMUserTable: setting new key failed (wrong type).");
4125             LOG_END;
4126
4127             return SNMPv3_USM_ERROR;
4128           }
4129         }
4130       }
4131
4132   LOG_BEGIN(INFO_LOG | 7);
4133   LOG("USMUserTable: setting new key failed (user) not found");
4134   LOG(user_name.get_printable());
4135   LOG_END;
4136
4137   return SNMPv3_USM_ERROR;
4138 }
4139
4140 void USMUserTable::delete_entry(const int nr)
4141 {
4142   /* Table is locked through caller, so do NOT lock table!
4143    * All checks have been made, so dont check again!
4144    */
4145
4146   if (table[nr].usmUserEngineID)     delete [] table[nr].usmUserEngineID;
4147   if (table[nr].usmUserName)         delete [] table[nr].usmUserName;
4148   if (table[nr].usmUserSecurityName) delete [] table[nr].usmUserSecurityName;
4149   if (table[nr].usmUserAuthKey)
4150   {
4151     memset(table[nr].usmUserAuthKey, 0, table[nr].usmUserAuthKeyLength);
4152     delete [] table[nr].usmUserAuthKey;
4153   }
4154   if (table[nr].usmUserPrivKey)
4155   {
4156     memset(table[nr].usmUserPrivKey, 0, table[nr].usmUserPrivKeyLength);
4157     delete [] table[nr].usmUserPrivKey;
4158   }
4159
4160   /* We have now one entry less */
4161   entries--;
4162
4163   if (entries > nr)
4164   {
4165     /* move the last entry to the deleted position */
4166     table[nr] = table[entries];
4167   }
4168 }
4169
4170 // Save all entries into a file.
4171 int USMUserTable::save_to_file(const char *name, AuthPriv *ap)
4172 {
4173   char encoded[MAX_LINE_LEN * 2];
4174   FILE *file_out;
4175   char tmp_file_name[MAXLENGTH_FILENAME];
4176   bool failed = false;
4177
4178   if (!name || !ap)
4179   {
4180     LOG_BEGIN(ERROR_LOG | 1);
4181     LOG("USMUserTable: save_to_file called with illegal param");
4182     if (!name)
4183     {
4184       LOG("filename");
4185     }
4186     if (!ap)
4187     {
4188       LOG("AuthPriv pointer");
4189     }
4190     LOG_END;
4191
4192     return SNMPv3_USM_ERROR;
4193   }
4194
4195   LOG_BEGIN(INFO_LOG | 4);
4196   LOG("USMUserTable: Saving users to file");
4197   LOG(name);
4198   LOG_END;
4199
4200   sprintf(tmp_file_name, "%s.tmp", name);
4201   file_out = fopen(tmp_file_name, "w");
4202   if (!file_out)
4203   {
4204     LOG_BEGIN(ERROR_LOG | 1);
4205     LOG("USMUserTable: could not create tmpfile");
4206     LOG(tmp_file_name);
4207     LOG_END;
4208
4209     return SNMPv3_USM_FILECREATE_ERROR;
4210   }
4211
4212   {
4213     // Begin reentrant code block
4214     BEGIN_REENTRANT_CODE_BLOCK;
4215
4216     for (int i=0; i < entries; ++i)
4217     {
4218       LOG_BEGIN(INFO_LOG | 8);
4219       LOG("USMUserTable: Saving user to file");
4220       LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength)
4221                   .get_printable());
4222       LOG_END;
4223
4224       encodeString(table[i].usmUserEngineID, table[i].usmUserEngineIDLength,
4225                    encoded);
4226       encoded[2 * table[i].usmUserEngineIDLength] = '\n';
4227       if (fwrite(encoded, 2 * table[i].usmUserEngineIDLength + 1, 1,
4228                  file_out) != 1)
4229       { failed = true; break; }
4230
4231       encodeString(table[i].usmUserName, table[i].usmUserNameLength, encoded);
4232       encoded[2 * table[i].usmUserNameLength] = '\n';
4233       if (fwrite(encoded, 2 * table[i].usmUserNameLength + 1, 1,
4234                  file_out) != 1)
4235       { failed = true; break; }
4236
4237       encodeString(table[i].usmUserSecurityName,
4238                    table[i].usmUserSecurityNameLength, encoded);
4239       encoded[2 * table[i].usmUserSecurityNameLength] = '\n';
4240       if (fwrite(encoded, 2 * table[i].usmUserSecurityNameLength + 1, 1,
4241                  file_out) != 1)
4242       { failed = true; break; }
4243
4244       encodeString(table[i].usmUserAuthKey, table[i].usmUserAuthKeyLength,
4245                    encoded);
4246       encoded[2 * table[i].usmUserAuthKeyLength] = '\n';
4247       if (fwrite(encoded, 2 * table[i].usmUserAuthKeyLength + 1, 1,
4248                  file_out) != 1)
4249       { failed = true; break; }
4250
4251       encodeString(table[i].usmUserPrivKey, table[i].usmUserPrivKeyLength,
4252                    encoded);
4253       encoded[2 * table[i].usmUserPrivKeyLength] = '\n';
4254       if (fwrite(encoded, 2 * table[i].usmUserPrivKeyLength + 1, 1,
4255                  file_out) != 1)
4256       { failed = true; break; }
4257
4258       if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
4259       {
4260         if (fwrite("none\n", 5, 1, file_out) != 1)
4261         { failed = true; break; }
4262       }
4263       else
4264       {
4265         const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
4266         if (!a) { failed = true; break; }
4267         sprintf(encoded, "%s\n", a->get_id_string());
4268         if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
4269         { failed = true; break; }
4270       }
4271
4272       if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
4273       {
4274         if (fwrite("none\n", 5, 1, file_out) != 1)
4275         { failed = true; break; }
4276       }
4277       else
4278       {
4279         const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
4280         if (!p) { failed = true; break; }
4281         sprintf(encoded, "%s\n", p->get_id_string());
4282         if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
4283         { failed = true; break; }
4284       }
4285     }
4286   }
4287
4288   fclose(file_out);
4289   if (failed)
4290   {
4291     LOG_BEGIN(ERROR_LOG | 1);
4292     LOG("USMUserTable: Failed to write table entries.");
4293     LOG_END;
4294
4295 #ifdef WIN32
4296     _unlink(tmp_file_name);
4297 #else
4298     unlink(tmp_file_name);
4299 #endif
4300     return SNMPv3_USM_FILEWRITE_ERROR;
4301   }
4302 #ifdef WIN32
4303   _unlink(name);
4304 #else
4305   unlink(name);
4306 #endif
4307   if (rename(tmp_file_name, name))
4308   {
4309     LOG_BEGIN(ERROR_LOG | 1);
4310     LOG("USMUserTable: Could not rename file (from) (to)");
4311     LOG(tmp_file_name);
4312     LOG(name);
4313     LOG_END;
4314
4315     return SNMPv3_USM_FILERENAME_ERROR;
4316   }
4317
4318   LOG_BEGIN(INFO_LOG | 4);
4319   LOG("USMUserTable: Saving users to file finished");
4320   LOG_END;
4321
4322   return SNMPv3_USM_OK;
4323 }
4324
4325 // Load the table from a file.
4326 int USMUserTable::load_from_file(const char *name, AuthPriv *ap)
4327 {
4328   char decoded[MAX_LINE_LEN];
4329   FILE *file_in;
4330   unsigned char line[MAX_LINE_LEN * 2];
4331
4332   if (!name || !ap)
4333   {
4334     LOG_BEGIN(ERROR_LOG | 1);
4335     LOG("USMUserTable: load_from_file called with illegal param");
4336     if (!name)
4337     {
4338       LOG("filename");
4339     }
4340     if (!ap)
4341     {
4342       LOG("AuthPriv pointer");
4343     }
4344     LOG_END;
4345
4346     return SNMPv3_USM_ERROR;
4347   }
4348
4349   LOG_BEGIN(INFO_LOG | 4);
4350   LOG("USMUserTable: Loading users from file");
4351   LOG(name);
4352   LOG_END;
4353
4354   file_in = fopen(name, "r");
4355   if (!file_in)
4356   {
4357     LOG_BEGIN(ERROR_LOG | 1);
4358     LOG("USMUserTable: could not open file");
4359     LOG(name);
4360     LOG_END;
4361
4362     return SNMPv3_USM_FILEOPEN_ERROR;
4363   }
4364
4365   bool failed = false;
4366   int len;
4367   while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4368   {
4369     // engine_id
4370     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
4371     decodeString(line, len, decoded);
4372     OctetStr engine_id((unsigned char*)decoded, len / 2);
4373
4374     // user_name
4375     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4376     { failed = true; break; }
4377     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
4378     decodeString(line, len, decoded);
4379     OctetStr user_name((unsigned char*)decoded, len / 2);
4380
4381     // security_name
4382     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4383     { failed = true; break; }
4384     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
4385     decodeString(line, len, decoded);
4386     OctetStr user_security_name((unsigned char*)decoded, len / 2);
4387
4388     // auth key
4389     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4390     { failed = true; break; }
4391     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
4392     decodeString(line, len, decoded);
4393     OctetStr auth_key((unsigned char*)decoded, len / 2);
4394
4395     // priv key
4396     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4397     { failed = true; break; }
4398     len = SAFE_INT_CAST(strlen((char*)line)) - 1;
4399     decodeString(line, len, decoded);
4400     OctetStr priv_key((unsigned char*)decoded, len / 2);
4401
4402     // auth protocol
4403     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4404     { failed = true; break; }
4405     line[strlen((char*)line) - 1] = 0;
4406     int auth_prot = SNMP_AUTHPROTOCOL_NONE;
4407     if (strcmp((char*)line, "none") != 0)
4408     {
4409       auth_prot = ap->get_auth_id((char*)line);
4410       if (auth_prot < 0)
4411       { failed = true; break; }
4412     }
4413
4414     if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
4415     { failed = true; break; }
4416     line[strlen((char*)line) - 1] = 0;
4417     int priv_prot = SNMP_PRIVPROTOCOL_NONE;
4418     if (strcmp((char*)line, "none") != 0)
4419     {
4420       priv_prot = ap->get_priv_id((char*)line);
4421       if (priv_prot < 0)
4422       { failed = true; break; }
4423     }
4424
4425     LOG_BEGIN(INFO_LOG | 7);
4426     LOG("USMUserTable: Adding localized (user name) (eng id) (auth) (priv)");
4427     LOG(user_name.get_printable());
4428     LOG(engine_id.get_printable());
4429     LOG(auth_prot);
4430     LOG(priv_prot);
4431     LOG_END;
4432
4433     if (add_entry(engine_id, user_name, user_security_name,
4434                   auth_prot, auth_key, priv_prot, priv_key)
4435         == SNMPv3_USM_ERROR)
4436     {
4437       failed = true;
4438
4439       LOG_BEGIN(ERROR_LOG | 1);
4440       LOG("USMUserTable: Error adding (user name)");
4441       LOG(user_name.get_printable());
4442       LOG_END;
4443     }
4444   }
4445
4446   fclose(file_in);
4447   if (failed)
4448   {
4449     LOG_BEGIN(ERROR_LOG | 1);
4450     LOG("USMUserTable: Failed to read table entries");
4451     LOG_END;
4452
4453     return SNMPv3_USM_FILEREAD_ERROR;
4454   }
4455
4456   LOG_BEGIN(INFO_LOG | 4);
4457   LOG("USMUserTable: Loaded all users from file");
4458   LOG_END;
4459
4460   return SNMPv3_USM_OK;
4461 }
4462
4463 const UsmUserTableEntry *USMUserTable::peek_next(
4464                    const UsmUserTableEntry *e) const
4465 {
4466   if (e == 0) return 0;
4467   if (e - table < 0) return 0;
4468   if (e - table >= entries - 1) return 0;
4469   return (e + 1);
4470 }
4471
4472 #ifdef SNMP_PP_NAMESPACE
4473 }; // end of namespace Snmp_pp
4474 #endif
4475
4476 #endif // _SNMPv3