snmp_community_mib_impl.c
Go to the documentation of this file.
1 /**
2  * @file snmp_community_mib_impl.c
3  * @brief SNMP COMMUNITY MIB module implementation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The SNMP-MIB describes managed objects which describe the behavior
30  * of an SNMP entity. Refer to RFC 3418 for more details
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 1.9.6
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL SNMP_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/net.h"
41 #include "mibs/mib_common.h"
44 #include "snmp/snmp_agent.h"
45 #include "snmp/snmp_agent_misc.h"
46 #include "core/crypto.h"
47 #include "encoding/asn1.h"
48 #include "encoding/oid.h"
49 #include "debug.h"
50 
51 //Check TCP/IP stack configuration
52 #if (SNMP_COMMUNITY_MIB_SUPPORT == ENABLED)
53 
54 
55 /**
56  * @brief SNMP COMMUNITY MIB module initialization
57  * @return Error code
58  **/
59 
61 {
62  //Debug message
63  TRACE_INFO("Initializing SNMP COMMUNITY MIB base...\r\n");
64 
65  //Clear SNMP COMMUNITY MIB base
66  memset(&snmpCommunityMibBase, 0, sizeof(snmpCommunityMibBase));
67 
68  //Successful processing
69  return NO_ERROR;
70 }
71 
72 
73 /**
74  * @brief Load SNMP COMMUNITY MIB module
75  * @param[in] context Pointer to the SNMP agent context
76  * @return Error code
77  **/
78 
80 {
81  //Register SNMP agent context
82  snmpCommunityMibBase.context = context;
83 
84  //Successful processing
85  return NO_ERROR;
86 }
87 
88 
89 /**
90  * @brief Unload SNMP COMMUNITY MIB module
91  * @param[in] context Pointer to the SNMP agent context
92  **/
93 
94 void snmpCommunityMibUnload(void *context)
95 {
96  //Unregister SNMP agent context
98 }
99 
100 
101 /**
102  * @brief Lock SNMP COMMUNITY MIB base
103  **/
104 
106 {
107  //Clear temporary community
108  memset(&snmpCommunityMibBase.tempCommunity, 0, sizeof(SnmpUserEntry));
109 }
110 
111 
112 /**
113  * @brief Unlock SNMP COMMUNITY MIB base
114  **/
115 
117 {
118  //Clear temporary user
119  memset(&snmpCommunityMibBase.tempCommunity, 0, sizeof(SnmpUserEntry));
120 }
121 
122 
123 /**
124  * @brief Set snmpCommunityEntry object value
125  * @param[in] object Pointer to the MIB object descriptor
126  * @param[in] oid Object identifier (object name and instance identifier)
127  * @param[in] oidLen Length of the OID, in bytes
128  * @param[in] value Object value
129  * @param[in] valueLen Length of the object value, in bytes
130  * @param[in] commit This flag tells whether the changes shall be committed
131  * to the MIB base
132  * @return Error code
133  **/
134 
136  size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
137 {
138  error_t error;
139  size_t n;
140  char_t index[SNMP_MAX_USER_NAME_LEN + 1];
141  SnmpAgentContext *context;
142  SnmpUserEntry *community;
143 
144  //Point to the instance identifier
145  n = object->oidLen;
146 
147  //snmpCommunityIndex is used as instance identifier
148  error = mibDecodeString(oid, oidLen, &n, index,
150  //Invalid instance identifier?
151  if(error)
152  return error;
153 
154  //Sanity check
155  if(n != oidLen)
157 
158  //Point to the SNMP agent context
160  //Sanity check
161  if(context == NULL)
163 
164  //Search the community table for the specified community string
165  community = snmpFindCommunityEntry(context, index, strlen(index));
166 
167  //snmpCommunityName object?
168  if(!strcmp(object->name, "snmpCommunityName"))
169  {
170  //Ensure the length of the community string is valid
171  if(valueLen > SNMP_MAX_USER_NAME_LEN)
172  return ERROR_INVALID_LENGTH;
173 
174  //Test if the conceptual row exists in the agent
175  if(community != NULL)
176  {
177  //Commit phase?
178  if(commit)
179  {
180  //Set community string
181  memcpy(community->name, value->octetString, valueLen);
182  //Properly terminate the string with a NULL character
183  community->name[valueLen] = '\0';
184  }
185  }
186  else
187  {
188  //Prepare phase?
189  if(!commit)
190  {
191  //Save the community string for later use
193  value->octetString, valueLen);
194 
195  //Properly terminate the string with a NULL character
196  snmpCommunityMibBase.tempCommunity.name[valueLen] = '\0';
197  }
198  }
199  }
200  //snmpCommunitySecurityName object?
201  else if(!strcmp(object->name, "snmpCommunitySecurityName"))
202  {
203  //Write access is not required
204  }
205  //snmpCommunityContextEngineID object?
206  else if(!strcmp(object->name, "snmpCommunityContextEngineID"))
207  {
208  //Write access is not required
209  }
210  //snmpCommunityContextName object?
211  else if(!strcmp(object->name, "snmpCommunityContextName"))
212  {
213  //Write access is not required
214  }
215  //snmpCommunityTransportTag object?
216  else if(!strcmp(object->name, "snmpCommunityTransportTag"))
217  {
218  //Write access is not required
219  }
220  //snmpCommunityStorageType object?
221  else if(!strcmp(object->name, "snmpCommunityStorageType"))
222  {
223  //The snmpCommunityStorageType object specifies the storage type
224  //for this conceptual row
225  if(value->integer != MIB_STORAGE_TYPE_OTHER &&
226  value->integer != MIB_STORAGE_TYPE_VOLATILE &&
227  value->integer != MIB_STORAGE_TYPE_NON_VOLATILE &&
228  value->integer != MIB_STORAGE_TYPE_PERMANENT &&
229  value->integer != MIB_STORAGE_TYPE_READ_ONLY)
230  {
231  return ERROR_WRONG_VALUE;
232  }
233  }
234  //snmpCommunityStatus object?
235  else if(!strcmp(object->name, "snmpCommunityStatus"))
236  {
237  MibRowStatus status;
238 
239  //Get row status
240  status = (MibRowStatus) value->integer;
241 
242  //Check the value specified by the set operation
243  if(status == MIB_ROW_STATUS_ACTIVE ||
245  {
246  //No matching row found?
247  if(community == NULL)
249 
250  //Commit phase?
251  if(commit)
252  {
253  //Valid community string specified?
255  strcpy(community->name, snmpCommunityMibBase.tempCommunity.name);
256 
257  //A newly created row cannot be made active until a value has been
258  //set for snmpCommunityName
259  if(community->name[0] == '\0')
261 
262  //Update the status of the conceptual row
263  community->status = status;
264  }
265  }
266  else if(status == MIB_ROW_STATUS_CREATE_AND_GO)
267  {
268  //Row already instantiated?
269  if(community != NULL)
271 
272  //Create a new row
273  community = snmpCreateCommunityEntry(context);
274  //Row creation failed?
275  if(community == NULL)
276  return ERROR_WRITE_FAILED;
277 
278  //Commit phase?
279  if(commit)
280  {
281  //Valid community string specified?
283  {
284  //Save community string
285  strcpy(community->name, snmpCommunityMibBase.tempCommunity.name);
286  //Set default access rights
287  community->mode = SNMP_ACCESS_READ_WRITE;
288 
289  //The conceptual row is now available for use by the managed device
290  community->status = MIB_ROW_STATUS_ACTIVE;
291  }
292  else
293  {
294  //The newly created row cannot be made active
296  }
297  }
298  }
299  else if(status == MIB_ROW_STATUS_CREATE_AND_WAIT)
300  {
301  //Row already instantiated?
302  if(community != NULL)
304 
305  //Create a new row
306  community = snmpCreateCommunityEntry(context);
307  //Row creation failed?
308  if(community == NULL)
309  return ERROR_WRITE_FAILED;
310 
311  //Commit phase?
312  if(commit)
313  {
314  //Ensure the community string is valid
317 
318  //Copy the community string
319  strcpy(community->name, snmpCommunityMibBase.tempCommunity.name);
320  //Set default access rights
321  community->mode = SNMP_ACCESS_READ_WRITE;
322 
323  //Instances of all corresponding columns are now configured
325  }
326  }
327  else if(status == MIB_ROW_STATUS_DESTROY)
328  {
329  //Test if the conceptual row exists in the agent
330  if(community != NULL)
331  {
332  //Commit phase?
333  if(commit)
334  {
335  //Delete the conceptual row from the table
336  community->status = MIB_ROW_STATUS_UNUSED;
337  }
338  }
339  }
340  else
341  {
342  //Unsupported action
344  }
345  }
346  //Unknown object?
347  else
348  {
349  //The specified object does not exist
350  error = ERROR_OBJECT_NOT_FOUND;
351  }
352 
353  //Return status code
354  return error;
355 }
356 
357 
358 /**
359  * @brief Get snmpCommunityEntry object value
360  * @param[in] object Pointer to the MIB object descriptor
361  * @param[in] oid Object identifier (object name and instance identifier)
362  * @param[in] oidLen Length of the OID, in bytes
363  * @param[out] value Object value
364  * @param[in,out] valueLen Length of the object value, in bytes
365  * @return Error code
366  **/
367 
369  size_t oidLen, MibVariant *value, size_t *valueLen)
370 {
371  error_t error;
372  size_t n;
373  char_t index[SNMP_MAX_USER_NAME_LEN + 1];
374  SnmpAgentContext *context;
375  SnmpUserEntry *community;
376 
377  //Point to the instance identifier
378  n = object->oidLen;
379 
380  //snmpCommunityIndex is used as instance identifier
381  error = mibDecodeString(oid, oidLen, &n, index,
383  //Invalid instance identifier?
384  if(error)
385  return error;
386 
387  //Sanity check
388  if(n != oidLen)
390 
391  //Point to the SNMP agent context
393  //Sanity check
394  if(context == NULL)
396 
397  //Search the community table for the specified community string
398  community = snmpFindCommunityEntry(context, index, strlen(index));
399  //Unknown community string?
400  if(community == NULL)
402 
403  //snmpCommunityName object?
404  if(!strcmp(object->name, "snmpCommunityName"))
405  {
406  //Retrieve the length of the community string
407  n = strlen(community->name);
408 
409  //Make sure the buffer is large enough to hold the entire object
410  if(*valueLen >= n)
411  {
412  //Copy object value
413  memcpy(value->octetString, community->name, n);
414  //Return object length
415  *valueLen = n;
416  }
417  else
418  {
419  //Report an error
420  error = ERROR_BUFFER_OVERFLOW;
421  }
422  }
423  //snmpCommunitySecurityName object?
424  else if(!strcmp(object->name, "snmpCommunitySecurityName"))
425  {
426  //Retrieve the length of the community string
427  n = strlen(community->name);
428 
429  //Make sure the buffer is large enough to hold the entire object
430  if(*valueLen >= n)
431  {
432  //Copy object value
433  memcpy(value->octetString, community->name, n);
434  //Return object length
435  *valueLen = n;
436  }
437  else
438  {
439  //Report an error
440  error = ERROR_BUFFER_OVERFLOW;
441  }
442  }
443  //snmpCommunityContextEngineID object?
444  else if(!strcmp(object->name, "snmpCommunityContextEngineID"))
445  {
446  //Retrieve the length of the context engine identifier
447  n = context->contextEngineLen;
448 
449  //Make sure the buffer is large enough to hold the entire object
450  if(*valueLen >= n)
451  {
452  //Copy object value
453  memcpy(value->octetString, context->contextEngine, n);
454  //Return object length
455  *valueLen = n;
456  }
457  else
458  {
459  //Report an error
460  error = ERROR_BUFFER_OVERFLOW;
461  }
462  }
463  //snmpCommunityContextName object?
464  else if(!strcmp(object->name, "snmpCommunityContextName"))
465  {
466  //Retrieve the length of the context name
467  n = strlen(context->contextName);
468 
469  //Make sure the buffer is large enough to hold the entire object
470  if(*valueLen >= n)
471  {
472  //Copy object value
473  memcpy(value->octetString, context->contextName, n);
474  //Return object length
475  *valueLen = n;
476  }
477  else
478  {
479  //Report an error
480  error = ERROR_BUFFER_OVERFLOW;
481  }
482  }
483  //snmpCommunityTransportTag object?
484  else if(!strcmp(object->name, "snmpCommunityTransportTag"))
485  {
486  //The default value is the empty string
487  *valueLen = 0;
488  }
489  //snmpCommunityStorageType object?
490  else if(!strcmp(object->name, "snmpCommunityStorageType"))
491  {
492  //Get the storage type for this conceptual row
493  value->integer = MIB_STORAGE_TYPE_VOLATILE;
494  }
495  //snmpCommunityStatus object?
496  else if(!strcmp(object->name, "snmpCommunityStatus"))
497  {
498  //Get the status of this conceptual row
499  value->integer = community->status;
500  }
501  //Unknown object?
502  else
503  {
504  //The specified object does not exist
505  error = ERROR_OBJECT_NOT_FOUND;
506  }
507 
508  //Return status code
509  return error;
510 }
511 
512 
513 /**
514  * @brief Get next snmpCommunityEntry object
515  * @param[in] object Pointer to the MIB object descriptor
516  * @param[in] oid Object identifier
517  * @param[in] oidLen Length of the OID, in bytes
518  * @param[out] nextOid OID of the next object in the MIB
519  * @param[out] nextOidLen Length of the next object identifier, in bytes
520  * @return Error code
521  **/
522 
524  size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
525 {
526  error_t error;
527  uint_t i;
528  size_t n;
529  bool_t acceptable;
530  SnmpAgentContext *context;
531  SnmpUserEntry *entry;
532  SnmpUserEntry *nextEntry;
533 
534  //Initialize variables
535  nextEntry = NULL;
536 
537  //Point to the SNMP agent context
539  //Sanity check
540  if(context == NULL)
541  return ERROR_OBJECT_NOT_FOUND;
542 
543  //Make sure the buffer is large enough to hold the OID prefix
544  if(*nextOidLen < object->oidLen)
545  return ERROR_BUFFER_OVERFLOW;
546 
547  //Copy OID prefix
548  memcpy(nextOid, object->oid, object->oidLen);
549 
550  //Loop through the list of community strings
551  for(i = 0; i < SNMP_AGENT_MAX_COMMUNITIES; i++)
552  {
553  //Point to the current entry
554  entry = &context->communityTable[i];
555 
556  //Check the status of the row
557  if(entry->status != MIB_ROW_STATUS_UNUSED)
558  {
559  //Append the instance identifier to the OID prefix
560  n = object->oidLen;
561 
562  //snmpCommunityIndex is used as instance identifier
563  error = mibEncodeString(nextOid, *nextOidLen, &n, entry->name, TRUE);
564  //Any error to report?
565  if(error)
566  return error;
567 
568  //Check whether the resulting object identifier lexicographically
569  //follows the specified OID
570  if(oidComp(nextOid, n, oid, oidLen) > 0)
571  {
572  //Perform lexicographic comparison
573  if(nextEntry == NULL)
574  acceptable = TRUE;
575  else if(strcmp(entry->name, nextEntry->name) < 0)
576  acceptable = TRUE;
577  else
578  acceptable = FALSE;
579 
580  //Save the closest object identifier that follows the specified
581  //OID in lexicographic order
582  if(acceptable)
583  nextEntry = entry;
584  }
585  }
586  }
587 
588  //The specified OID does not lexicographically precede the name
589  //of some object?
590  if(nextEntry == NULL)
591  return ERROR_OBJECT_NOT_FOUND;
592 
593  //Append the instance identifier to the OID prefix
594  n = object->oidLen;
595 
596  //snmpCommunityIndex is used as instance identifier
597  error = mibEncodeString(nextOid, *nextOidLen, &n, nextEntry->name, TRUE);
598  //Any error to report?
599  if(error)
600  return error;
601 
602  //Save the length of the resulting object identifier
603  *nextOidLen = n;
604  //Next object found
605  return NO_ERROR;
606 }
607 
608 #endif
@ MIB_ROW_STATUS_NOT_IN_SERVICE
Definition: mib_common.h:104
error_t mibEncodeString(uint8_t *oid, size_t maxOidLen, size_t *pos, const char_t *string, bool_t implied)
Encode instance identifier (string)
Definition: mib_common.c:129
SNMP COMMUNITY MIB module implementation.
SnmpCommunityMibBase snmpCommunityMibBase
SNMP COMMUNITY MIB base.
int bool_t
Definition: compiler_port.h:49
void snmpCommunityMibUnload(void *context)
Unload SNMP COMMUNITY MIB module.
@ SNMP_ACCESS_READ_WRITE
SnmpUserEntry * snmpFindCommunityEntry(SnmpAgentContext *context, const char_t *community, size_t length)
Search the community table for a given community string.
@ MIB_ROW_STATUS_CREATE_AND_GO
Definition: mib_common.h:106
@ MIB_STORAGE_TYPE_NON_VOLATILE
Definition: mib_common.h:120
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:140
SnmpAccess mode
Access mode.
OID (Object Identifier)
@ MIB_STORAGE_TYPE_OTHER
Definition: mib_common.h:118
#define TRUE
Definition: os_port.h:50
__start_packed struct @205 MibVariant
Variant data type.
User table entry.
int_t oidComp(const uint8_t *oid1, size_t oidLen1, const uint8_t *oid2, size_t oidLen2)
Compare object identifiers.
Definition: oid.c:101
@ MIB_ROW_STATUS_DESTROY
Definition: mib_common.h:108
@ MIB_STORAGE_TYPE_READ_ONLY
Definition: mib_common.h:122
error_t snmpCommunityMibLoad(void *context)
Load SNMP COMMUNITY MIB module.
SnmpUserEntry * snmpCreateCommunityEntry(SnmpAgentContext *context)
Create a new community entry.
SNMP agent (Simple Network Management Protocol)
error_t snmpCommunityMibSetCommunityEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, const MibVariant *value, size_t valueLen, bool_t commit)
Set snmpCommunityEntry object value.
#define FALSE
Definition: os_port.h:46
error_t snmpCommunityMibGetCommunityEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, MibVariant *value, size_t *valueLen)
Get snmpCommunityEntry object value.
error_t
Error codes.
Definition: error.h:42
@ ERROR_INSTANCE_NOT_FOUND
Definition: error.h:251
#define SNMP_MAX_USER_NAME_LEN
Definition: snmp_common.h:81
SNMP COMMUNITY MIB module.
error_t snmpCommunityMibInit(void)
SNMP COMMUNITY MIB module initialization.
@ ERROR_INVALID_LENGTH
Definition: error.h:109
@ MIB_ROW_STATUS_UNUSED
Definition: mib_common.h:102
General definitions for cryptographic algorithms.
uint8_t oid[1]
Definition: mib_common.h:186
Helper functions for SNMP agent.
#define SNMP_AGENT_MAX_COMMUNITIES
Definition: snmp_agent.h:76
#define TRACE_INFO(...)
Definition: debug.h:94
MibRowStatus status
Status of the user.
char char_t
Definition: compiler_port.h:43
@ MIB_ROW_STATUS_ACTIVE
Definition: mib_common.h:103
char_t name[SNMP_MAX_USER_NAME_LEN+1]
User name.
MibRowStatus
Row status.
Definition: mib_common.h:100
Common definitions for MIB modules.
uint8_t n
@ ERROR_WRONG_VALUE
Definition: error.h:121
@ ERROR_WRITE_FAILED
Definition: error.h:219
@ ERROR_OBJECT_NOT_FOUND
Definition: error.h:250
void snmpCommunityMibUnlock(void)
Unlock SNMP COMMUNITY MIB base.
#define MibObject
Definition: mib_common.h:46
@ MIB_ROW_STATUS_CREATE_AND_WAIT
Definition: mib_common.h:107
@ MIB_STORAGE_TYPE_VOLATILE
Definition: mib_common.h:119
#define SnmpAgentContext
Definition: snmp_agent.h:36
void snmpCommunityMibLock(void)
Lock SNMP COMMUNITY MIB base.
error_t mibDecodeString(const uint8_t *oid, size_t oidLen, size_t *pos, char_t *string, size_t maxStringLen, bool_t implied)
Decode instance identifier (string)
Definition: mib_common.c:149
uint8_t value[]
Definition: dtls_misc.h:150
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
@ ERROR_INCONSISTENT_VALUE
Definition: error.h:122
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
@ MIB_STORAGE_TYPE_PERMANENT
Definition: mib_common.h:121
error_t snmpCommunityMibGetNextCommunityEntry(const MibObject *object, const uint8_t *oid, size_t oidLen, uint8_t *nextOid, size_t *nextOidLen)
Get next snmpCommunityEntry object.