1 /*
2 **   SNMPv1/2C Community String Checking Medusa Module
3 **
4 **   ------------------------------------------------------------------------
5 **    Copyright (C) 2009 Joe Mondloch
6 **    JoMo-Kun / jmk@foofus.net
7 **
8 **    This program is free software; you can redistribute it and/or modify
9 **    it under the terms of the GNU General Public License version 2,
10 **    as published by the Free Software Foundation
11 **
12 **    This program is distributed in the hope that it will be useful,
13 **    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **    GNU General Public License for more details.
16 **
17 **    http://www.gnu.org/licenses/gpl.txt
18 **
19 **    This program is released under the GPL with the additional exemption
20 **    that compiling, linking, and/or using OpenSSL is allowed.
21 **
22 **   ------------------------------------------------------------------------
23 **
24 **    Based on ideas from:
25 **      Hydra 5.2 [van Hauser <vh@thc.org>]
26 **      onesixtyone [solareclipse@phreedom.org]
27 **
28 */
29 
30 #include <sys/types.h>
31 #include <libgen.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include "module.h"
36 
37 #define MODULE_NAME    "snmp.mod"
38 #define MODULE_AUTHOR  "JoMo-Kun <jmk@foofus.net>"
39 #define MODULE_SUMMARY_USAGE  "Brute force module for SNMP Community Strings"
40 #define MODULE_VERSION    "2.1"
41 #define MODULE_VERSION_SVN "$Id: snmp.c 9217 2015-05-07 18:07:03Z jmk $"
42 #define MODULE_SUMMARY_FORMAT  "%s : version %s"
43 #define MODULE_SUMMARY_FORMAT_WARN  "%s : version %s (%s)"
44 
45 #define PORT_SNMP 161
46 
47 #define SNMP_VER_V1 1
48 #define SNMP_VER_V2C 2
49 #define SNMP_READ 1
50 #define SNMP_WRITE 2
51 #define SNMP_SUCCESS_READ 1
52 #define SNMP_SUCCESS_WRITE 2
53 
54 #define SEND_DELAY 200 /* Delay between sending SNMP requests (usec) */
55 #define RECEIVE_DELAY 5*1000000 /* Response wait time (usec) */
56 
57 typedef struct __SNMP_DATA {
58   int nVersion;
59   int nReadWrite;
60   int nReadTimeout;
61   int nSendDelay;
62 } _SNMP_DATA;
63 
64 // Tells us whether we are to continue processing or not
65 enum MODULE_STATE
66 {
67   MSTATE_NEW,
68   MSTATE_RUNNING,
69   MSTATE_EXITING,
70   MSTATE_COMPLETE,
71   MSTATE_FAILURE
72 };
73 
74 // Forward declarations
75 int sendRead(int hSocket, _SNMP_DATA* _psSessionData, char* szPassword);
76 int sendWrite(int hSocket, _SNMP_DATA* _psSessionData, char* szPassword, char* szLocation);
77 int receiveRequest(int hSocket, _SNMP_DATA* _psSessionData, int* nPassCount, char*** arrszPassList, char** szLocation);
78 int initModule(sLogin* login, _SNMP_DATA *_psSessionData);
79 
80 // Tell medusa how many parameters this module allows
getParamNumber()81 int getParamNumber()
82 {
83   return 0;    // we don't need no stinking parameters
84 }
85 
86 // Displays information about the module and how it must be used
summaryUsage(char ** ppszSummary)87 void summaryUsage(char **ppszSummary)
88 {
89   // Memory for ppszSummary will be allocated here - caller is responsible for freeing it
90   int  iLength = 0;
91 
92   if (*ppszSummary == NULL)
93   {
94     iLength = strlen(MODULE_SUMMARY_USAGE) + strlen(MODULE_VERSION) + strlen(MODULE_SUMMARY_FORMAT) + 1;
95     *ppszSummary = (char*)malloc(iLength);
96     memset(*ppszSummary, 0, iLength);
97     snprintf(*ppszSummary, iLength, MODULE_SUMMARY_FORMAT, MODULE_SUMMARY_USAGE, MODULE_VERSION);
98   }
99   else
100   {
101     writeError(ERR_ERROR, "%s reports an error in summaryUsage() : ppszSummary must be NULL when called", MODULE_NAME);
102   }
103 }
104 
105 /* Display module usage information */
showUsage()106 void showUsage()
107 {
108   writeVerbose(VB_NONE, "%s (%s) %s :: %s\n", MODULE_NAME, MODULE_VERSION, MODULE_AUTHOR, MODULE_SUMMARY_USAGE);
109   writeVerbose(VB_NONE, "Available module options:");
110   writeVerbose(VB_NONE, "  TIMEOUT:? ");
111   writeVerbose(VB_NONE, "    Sets the number of seconds to wait for the UDP responses (default: 5 sec).");
112   writeVerbose(VB_NONE, "  SEND_DELAY:? ");
113   writeVerbose(VB_NONE, "    Sets the number of microseconds to wait between sending queries (default: 200 usec).");
114   writeVerbose(VB_NONE, "  VERSION:? (1*, 2C)");
115   writeVerbose(VB_NONE, "    Set the SNMP client version.");
116   writeVerbose(VB_NONE, "  ACCESS:? (READ*, WRITE)");
117   writeVerbose(VB_NONE, "    Set level of access to test for with the community string.");
118   writeVerbose(VB_NONE, "");
119   writeVerbose(VB_NONE, "(*) Default value");
120   writeVerbose(VB_NONE, "");
121   writeVerbose(VB_NONE, "It should be noted that when testing for WRITE capability, the module will read");
122   writeVerbose(VB_NONE, "the current value of sysLocation and then write that same value back to the system.");
123   writeVerbose(VB_NONE, "");
124   writeVerbose(VB_NONE, "Since SNMP is a UDP-based protocol, there is no handshaking between sending and ");
125   writeVerbose(VB_NONE, "receiving transport-layer entities. Due to this connectionless communication, about");
126   writeVerbose(VB_NONE, "the only time we know a SNMP service exists, is if we send the correct community");
127   writeVerbose(VB_NONE, "string and the server sends a response. All other queries result in no response");
128   writeVerbose(VB_NONE, "whatsoever. The approach we use here is to initially just send all of our SNMP GET");
129   writeVerbose(VB_NONE, "requests. After that completes, we wait TIMEOUT seconds for any responses. If we");
130   writeVerbose(VB_NONE, "get any responses back, we examine them to see which community strings were successful.");
131   writeVerbose(VB_NONE, "If ACCESS:WRITE was specified, we check for write access on each of the previously");
132   writeVerbose(VB_NONE, "successful values. This techique should allow for quick brute forcing. However, one");
133   writeVerbose(VB_NONE, "should take care with the TIMEOUT and SEND_DELAY values as to avoid causing issues");
134   writeVerbose(VB_NONE, "with the target service or missing response data.");
135   writeVerbose(VB_NONE, "");
136   writeVerbose(VB_NONE, "  Usage example: \"-M snmp -m TIMEOUT:2 -m ACCESS:WRITE\"");
137   writeVerbose(VB_NONE, "");
138 }
139 
140 // The "main" of the medusa module world - this is what gets called to actually do the work
go(sLogin * logins,int argc,char * argv[])141 int go(sLogin* logins, int argc, char *argv[])
142 {
143   int i;
144   char *strtok_ptr, *pOpt, *pOptTmp;
145   _SNMP_DATA *psSessionData;
146 
147   psSessionData = malloc(sizeof(_SNMP_DATA));
148   memset(psSessionData, 0, sizeof(_SNMP_DATA));
149 
150   psSessionData->nVersion = SNMP_VER_V1;
151   psSessionData->nReadWrite = SNMP_READ;
152   psSessionData->nReadTimeout = RECEIVE_DELAY;
153   psSessionData->nSendDelay = SEND_DELAY;
154 
155   if ((argc < 0) || (argc > 4))
156   {
157     writeError(ERR_ERROR, "%s: Incorrect number of parameters passed to module (%d). Use \"-q\" option to display module usage.", MODULE_NAME, argc);
158     return FAILURE;
159   }
160   else
161   {
162     writeError(ERR_DEBUG_MODULE, "OMG teh %s module has been called!!", MODULE_NAME);
163 
164     for (i=0; i<argc; i++) {
165       pOptTmp = malloc( strlen(argv[i]) + 1);
166       memset(pOptTmp, 0, strlen(argv[i]) + 1);
167       strncpy(pOptTmp, argv[i], strlen(argv[i]));
168       writeError(ERR_DEBUG_MODULE, "Processing complete option (%d/%d): %s", i+1, argc, pOptTmp);
169       pOpt = strtok_r(pOptTmp, ":", &strtok_ptr);
170       writeError(ERR_DEBUG_MODULE, "Processing option: %s", pOpt);
171 
172       if (strcmp(pOpt, "TIMEOUT") == 0)
173       {
174         pOpt = strtok_r(NULL, "\0", &strtok_ptr);
175         writeError(ERR_DEBUG_MODULE, "Processing option parameter: %s", pOpt);
176 
177         if ( pOpt )
178           psSessionData->nReadTimeout = atoi(pOpt) * 1000000;
179         else
180           writeError(ERR_WARNING, "Method TIMEOUT requires value to be set.");
181       }
182       else if (strcmp(pOpt, "SEND_DELAY") == 0)
183       {
184         pOpt = strtok_r(NULL, "\0", &strtok_ptr);
185         writeError(ERR_DEBUG_MODULE, "Processing option parameter: %s", pOpt);
186 
187         if ( pOpt )
188           psSessionData->nSendDelay = atoi(pOpt);
189         else
190           writeError(ERR_WARNING, "Method TIMEOUT requires value to be set.");
191       }
192       else if (strcmp(pOpt, "VERSION") == 0)
193       {
194         pOpt = strtok_r(NULL, "\0", &strtok_ptr);
195         writeError(ERR_DEBUG_MODULE, "Processing option parameter: %s", pOpt);
196 
197         if (pOpt == NULL)
198           writeError(ERR_WARNING, "Method VERSION requires value to be set.");
199         else if ( strcmp(pOpt, "1") == 0 )
200           psSessionData->nVersion = SNMP_VER_V1;
201         else if ( strcmp(pOpt, "2C") == 0 )
202           psSessionData->nVersion = SNMP_VER_V2C;
203         else
204           writeError(ERR_WARNING, "Method VERSION requires a value of either \"1\" or \"2C\" to be set.");
205       }
206       else if (strcmp(pOpt, "ACCESS") == 0)
207       {
208         pOpt = strtok_r(NULL, "\0", &strtok_ptr);
209         writeError(ERR_DEBUG_MODULE, "Processing option parameter: %s", pOpt);
210 
211         if (pOpt == NULL)
212           writeError(ERR_WARNING, "Method ACCESS requires value to be set.");
213         else if ( strcmp(pOpt, "READ") == 0 )
214           psSessionData->nReadWrite = SNMP_READ;
215         else if ( strcmp(pOpt, "WRITE") == 0 )
216           psSessionData->nReadWrite = SNMP_WRITE;
217         else
218           writeError(ERR_WARNING, "Method ACCESS requires value of \"READ\" or \"WRITE\" to be set.");
219       }
220       else
221          writeError(ERR_WARNING, "Invalid method: %s.", pOpt);
222 
223       free(pOptTmp);
224     }
225 
226     initModule(logins, psSessionData);
227   }
228 
229   FREE(psSessionData);
230   return SUCCESS;
231 }
232 
initModule(sLogin * psLogin,_SNMP_DATA * _psSessionData)233 int initModule(sLogin* psLogin, _SNMP_DATA *_psSessionData)
234 {
235   int hSocket = -1;
236   enum MODULE_STATE nState = MSTATE_NEW;
237   int i = 0, nPassCount, nPassCountWrite;
238   char **arrszPassList = NULL;
239   char **arrszPassListWrite = NULL;
240   char *szLocation = NULL;
241   sCredentialSet *psCredSet = NULL;
242   sUser *psUser = NULL;
243   sConnectParams params;
244 
245   psCredSet = malloc( sizeof(sCredentialSet) );
246   memset(psCredSet, 0, sizeof(sCredentialSet));
247 
248   if (getNextCredSet(psLogin, psCredSet) == FAILURE)
249   {
250     writeError(ERR_ERROR, "[%s] Error retrieving next credential set to test.", MODULE_NAME);
251     nState = MSTATE_COMPLETE;
252   }
253   else if (psCredSet->psUser)
254   {
255     writeError(ERR_DEBUG_MODULE, "[%s] module started for host: %s user: %s", MODULE_NAME, psLogin->psServer->pHostIP, psCredSet->psUser->pUser);
256   }
257   else
258   {
259     writeError(ERR_DEBUG_MODULE, "[%s] module started for host: %s - no more available users to test.", MODULE_NAME);
260     nState = MSTATE_COMPLETE;
261   }
262 
263   memset(&params, 0, sizeof(sConnectParams));
264   params.nPort = PORT_SNMP;
265   initConnectionParams(psLogin, &params);
266 
267   writeError(ERR_DEBUG_MODULE, "[%s] module started for host: %s", MODULE_NAME, psLogin->psServer->pHostIP);
268 
269   while (nState != MSTATE_COMPLETE)
270   {
271     switch (nState)
272     {
273       case MSTATE_NEW:
274         if (hSocket > 0)
275           medusaDisconnect(hSocket);
276 
277         hSocket = medusaConnectUDP(&params);
278         if (hSocket < 0)
279         {
280           writeError(ERR_NOTICE, "%s: failed to connect, port %d was not open on %s", MODULE_NAME, params.nPort, psLogin->psServer->pHostIP);
281           psLogin->iResult = LOGIN_RESULT_UNKNOWN;
282           return FAILURE;
283         }
284 
285         writeError(ERR_DEBUG_MODULE, "Connected");
286         nState = MSTATE_RUNNING;
287         break;
288       case MSTATE_RUNNING:
289         nState = sendRead(hSocket, _psSessionData, psCredSet->pPass);
290         if (nState == MSTATE_FAILURE)
291         {
292           psLogin->iResult = LOGIN_RESULT_UNKNOWN;
293           return FAILURE;
294         }
295 
296         /* don't want to overwhelm the device being tested */
297         writeError(ERR_DEBUG_MODULE, "Delaying %d microseconds before sending next query.", _psSessionData->nSendDelay);
298         usleep(_psSessionData->nSendDelay);
299 
300         /* initially set all passwords as invalid -- we don't know their validity yet */
301         psLogin->iResult = LOGIN_RESULT_FAIL;
302         setPassResult(psLogin, psCredSet->pPass);
303 
304         if (psLogin->iResult != LOGIN_RESULT_UNKNOWN)
305         {
306           if (getNextCredSet(psLogin, psCredSet) == FAILURE)
307           {
308             writeError(ERR_ERROR, "[%s] Error retrieving next credential set to test.", MODULE_NAME);
309             nState = MSTATE_EXITING;
310           }
311           else
312           {
313             if (psCredSet->iStatus == CREDENTIAL_DONE)
314             {
315               writeError(ERR_DEBUG_MODULE, "[%s] No more available credential sets to test.", MODULE_NAME);
316 
317               /* Medusa has exhausted all credential sets and reset psLogin->psUser to NULL. This
318                  creates issues as we haven't actually received the responses yet from our SNMP
319                  queries. Our solution is to create a temporary sUser structure, which allows us
320                  to report on successful community strings via normal methods. */
321               psUser = malloc(sizeof(sUser));
322               memset(psUser, 0, sizeof(sUser));
323               psLogin->psUser = psUser;
324 
325               nState = MSTATE_EXITING;
326             }
327             else if (psCredSet->iStatus == CREDENTIAL_NEW_USER)
328             {
329               writeError(ERR_DEBUG_MODULE, "[%s] Starting testing for new user: %s.", MODULE_NAME, psCredSet->psUser->pUser);
330               nState = MSTATE_RUNNING;
331             }
332             else
333               writeError(ERR_DEBUG_MODULE, "[%s] Next credential set - user: %s password: %s", MODULE_NAME, psCredSet->psUser->pUser, psCredSet->pPass);
334           }
335         }
336         break;
337       case MSTATE_EXITING:
338         nState = MSTATE_COMPLETE;
339         break;
340       default:
341         writeError(ERR_CRITICAL, "Unknown %s module state %d", MODULE_NAME, nState);
342         if (hSocket > 0)
343           medusaDisconnect(hSocket);
344         hSocket = -1;
345         psLogin->iResult = LOGIN_RESULT_UNKNOWN;
346         return FAILURE;
347     }
348   }
349 
350   /* check if server responded to GET queries */
351   writeError(ERR_DEBUG_MODULE, "[%s] Checking for server responses.", MODULE_NAME);
352   if (receiveRequest(hSocket, _psSessionData, &nPassCount, &arrszPassList, &szLocation) == FAILURE)
353   {
354     writeError(ERR_DEBUG_MODULE, "[%s] Failed to find valid READ community string.", MODULE_NAME);
355     return SUCCESS;
356   }
357 
358   for (i=0; i < nPassCount; i++)
359   {
360     writeError(ERR_DEBUG_MODULE, "[%s] Located valid community string (%d/%d): %s.", MODULE_NAME, i+1, nPassCount, arrszPassList[i]);
361 
362     if (_psSessionData->nReadWrite == SNMP_WRITE)
363     {
364       writeError(ERR_DEBUG_MODULE, "[%s] Checking if community string has WRITE access.", MODULE_NAME);
365 
366       /* send SET request to server */
367       if (sendWrite(hSocket, _psSessionData, arrszPassList[i], szLocation))
368       {
369         writeError(ERR_ERROR, "[%s] Failed to send SET request.", MODULE_NAME);
370         return FAILURE;
371       }
372       FREE(szLocation);
373 
374       /* check if community string has WRITE access */
375       if (receiveRequest(hSocket, _psSessionData, &nPassCountWrite, &arrszPassListWrite, &szLocation) == SUCCESS)
376       {
377         writeError(ERR_DEBUG_MODULE, "[%s] Located valid WRITE community string: %s.", MODULE_NAME, arrszPassList[i]);
378         psLogin->iResult = LOGIN_RESULT_SUCCESS;
379         setPassResult(psLogin, arrszPassList[i]);
380       }
381       else
382       {
383         writeError(ERR_ERROR, "[%s] Community string appears to have only READ access.", MODULE_NAME);
384         psLogin->iResult = LOGIN_RESULT_ERROR;
385         setPassResult(psLogin, arrszPassList[i]);
386       }
387       FREE(arrszPassListWrite);
388     }
389     else
390     {
391       writeError(ERR_DEBUG_MODULE, "[%s] Located valid READ community string: %s.", MODULE_NAME, arrszPassList[i]);
392       psLogin->iResult = LOGIN_RESULT_SUCCESS;
393       setPassResult(psLogin, arrszPassList[i]);
394     }
395 
396     FREE(arrszPassList[i]);
397     FREE(szLocation);
398   }
399 
400   if (hSocket > 0)
401     medusaDisconnect(hSocket);
402 
403   FREE(psUser);
404   FREE(psCredSet);
405   FREE(arrszPassList);
406   FREE(arrszPassListWrite);
407   return SUCCESS;
408 }
409 
410 /* Module Specific Functions */
411 
412 /*
413   http://book.opensourceproject.org.cn/embedded/tcpipembedded/opensource/0061.html
414 
415   The first TLV in the request is called sequence and is used to identify the length of the following TLVs.
416   The sequence type is 0x30 and the next octet is used to decode the length of this TLV. If the length octet
417   has the high-order bit set (0x80), then the length octet masked with 0x7f yields the number of bytes that
418   follow that will make up the value length (in big-endian order). If the high-order bit is not set, then
419   this octet is the length (no length octets follow).
420 
421   Example:  0x30 0x2f 0x02 0x01 0x00
422   Sequence: 0x30 0x2f
423   Version:  0x02 0x01 0x00
424 
425   Example:  0x30 0x82 0x00 0x2f 0x02 0x01 0x00
426   Sequence: 0x30 0x82 0x00 0x2f
427   Version:  0x02 0x01 0x00
428 */
parseLength(unsigned char * bufReceive)429 int parseLength(unsigned char* bufReceive)
430 {
431   int nLength = 0;
432   int nOctets = 0;
433 
434   if (bufReceive[0] == 0x30)
435   {
436     if (bufReceive[1] & 0x80) /* multi-octet mode */
437     {
438       nOctets = bufReceive[1] & 0x7f;
439 
440       /* limited to 4 octets worth of length data */
441       if (nOctets == 1)
442         nLength = bufReceive[2];
443       else if (nOctets == 2)
444         nLength = (bufReceive[2] << 8) + bufReceive[3];
445       else if (nOctets == 3)
446         nLength = (bufReceive[2] << 16) + (bufReceive[3] << 8) + bufReceive[4];
447       else if (nOctets == 4)
448         nLength = (bufReceive[2] << 24) + (bufReceive[3] << 16) + (bufReceive[4] << 8) + bufReceive[5];
449 
450       if ((nLength > 0) && ((bufReceive[2+nOctets] == 0x02) && (bufReceive[2+nOctets+1] == 0x01)))
451         writeError(ERR_DEBUG_MODULE, "[%s] Multi-octet mode length: %d", MODULE_NAME, nLength);
452       else
453       {
454         writeError(ERR_ERROR, "[%s] Failed to parse length or SNMP version (multi-octet mode).", MODULE_NAME);
455         nLength = -1;
456       }
457     }
458     else if ((bufReceive[2] == 0x02) && (bufReceive[3] == 0x01))  /* single octet mode, version check */
459     {
460       nLength = bufReceive[1];
461       writeError(ERR_DEBUG_MODULE, "[%s] Single octet mode length: %d", MODULE_NAME, nLength);
462     }
463     else
464     {
465       writeError(ERR_ERROR, "[%s] Failed to parse length or SNMP version.", MODULE_NAME);
466       nLength = -1;
467     }
468   }
469 
470   return nLength;
471 }
472 
473 
countResponses(int nReceiveBufferSize,unsigned char * bufReceive)474 int countResponses(int nReceiveBufferSize, unsigned char* bufReceive)
475 {
476   int i = 0;
477   int nLength = 0;
478   int nResponseCount = 0;
479 
480   for (i = 0; i < nReceiveBufferSize; i++) {
481     if (bufReceive[i] == 0x30)
482     {
483       nLength = parseLength(&bufReceive[i]);
484       if (nLength > 0)
485       {
486         writeError(ERR_DEBUG_MODULE, "[%s] Located start of SNMP response (%d bytes).", MODULE_NAME, nLength);
487         nResponseCount++;
488         i += nLength;
489       }
490     }
491   }
492 
493   return nResponseCount;
494 }
495 
processResponse(int nReceiveBufferSize,unsigned char * bufReceive,int * nSNMPLength,char ** szPassword,char ** szLocation)496 int processResponse(int nReceiveBufferSize, unsigned char* bufReceive, int *nSNMPLength, char** szPassword, char** szLocation)
497 {
498   int i;
499   writeError(ERR_DEBUG_MODULE, "[%s] Parsing SNMP response data.", MODULE_NAME);
500 
501   for (i = 0; i < nReceiveBufferSize; i++) {
502     *nSNMPLength = parseLength(&bufReceive[i]);
503     if (*nSNMPLength > 0)
504     {
505       writeError(ERR_DEBUG_MODULE, "[%s] Located start of SNMP response (%d bytes).", MODULE_NAME, *nSNMPLength);
506 
507       for (; i < nReceiveBufferSize; i++) {
508         if (bufReceive[i] == 0x04) {
509           writeError(ERR_DEBUG_MODULE, "[%s] Located start of SNMP community string.", MODULE_NAME);
510           if (bufReceive[i+1] > 0)
511           {
512             writeError(ERR_DEBUG_MODULE, "[%s] Located SNMP community string size: %d.", MODULE_NAME, bufReceive[i+1]);
513             *szPassword = malloc(bufReceive[i+1] + 1);
514             memset(*szPassword, 0, bufReceive[i+1] + 1);
515             memcpy(*szPassword, bufReceive + i + 2, bufReceive[i+1]);
516             writeError(ERR_DEBUG_MODULE, "[%s] Located community string: %s.", MODULE_NAME, *szPassword);
517           }
518           else
519           {
520             writeError(ERR_DEBUG_MODULE, "[%s] Failed to locate community string.", MODULE_NAME);
521             return FAILURE;
522           }
523 
524           for (i = i + bufReceive[i + 1]; i + 2 < nReceiveBufferSize; i++) { /* skip community string */
525             if (bufReceive[i] == 0xa2) {
526               writeError(ERR_DEBUG_MODULE, "[%s] Located PDU Response.", MODULE_NAME);
527               for (; i + 2 < nReceiveBufferSize; i++) {
528                 if (bufReceive[i] == 0x02) {
529                   writeError(ERR_DEBUG_MODULE, "[%s] Located ID.", MODULE_NAME);
530                   for (i = i + (bufReceive[i + 1]); i + 2 < nReceiveBufferSize; i++) { /* skip Request ID */
531                     if ((bufReceive[i] == 0x02) && (bufReceive[i + 1] == 0x01) && (bufReceive[i + 2] == 0x00)) {
532                       writeError(ERR_DEBUG_MODULE, "[%s] Located success status flag.", MODULE_NAME);
533 
534                       *szLocation = malloc(bufReceive[i + 6 + 14 + 1] + 1);
535                       memset(*szLocation, 0, bufReceive[i + 6 + 14 + 1] + 1);
536                       memcpy(*szLocation, bufReceive + i + 6 + 14 + 2, bufReceive[i + 6 + 14 + 1]);
537 
538                       writeError(ERR_DEBUG_MODULE, "[%s] sysLocation: %s.", MODULE_NAME, *szLocation);
539                       return(SUCCESS);
540                     }
541                   }
542                 }
543               }
544             }
545           }
546         }
547       }
548     }
549   }
550 
551   return FAILURE;
552 }
553 
sendRead(int hSocket,_SNMP_DATA * _psSessionData,char * szPassword)554 int sendRead(int hSocket, _SNMP_DATA* _psSessionData, char* szPassword)
555 {
556   unsigned char* bufSend;
557   int nSendBufferSize = 0;
558 
559   struct _SNMPV1_A {
560     char ID;
561     char len;
562     char ver[3];
563     char comid;
564     char comlen;
565   } snmpv1_a = {
566     .ID = '\x30',
567     .len = '\x00',
568     .ver = "\x02\x01\x00",  /* \x02\x01\x01 for snmp v2c */
569     .comid = '\x04',
570     .comlen = '\x00'
571   };
572 
573   struct _SNMPV1_R {
574     char type[2];
575     char identid[2];
576     char ident[4];
577     char errstat[3];
578     char errind[3];
579     char objectid[2];
580     char object[12];
581     char value[3];
582   } snmpv1_r = {
583     .type = "\xa0\x1c",                                       /* GET */
584     .identid = "\x02\x04",
585     .ident = "\x6f\x67\x4e\xe1",                              /* request id - doesn't matter */
586     .errstat = "\x02\x01\x00",                                /* no error */
587     .errind = "\x02\x01\x00",                                 /* error index 0 */
588     .objectid = "\x30\x0e",
589     .object = "\x30\x0c\x06\x08\x2b\x06\x01\x02\x01\x01\x06\x00", /* sysLocation */
590     .value = "\x05\x00"                                       /* we just read, so value = 0 */
591   };
592 
593   if (_psSessionData->nVersion == SNMP_VER_V2C)
594     snmpv1_a.ver[2] = '\x01';
595 
596   /* GET system.sysLocation */
597   nSendBufferSize = sizeof(snmpv1_a) + sizeof(snmpv1_r) + strlen(szPassword);
598   snmpv1_a.comlen = (char) strlen(szPassword);
599   snmpv1_a.len = nSendBufferSize - 3;
600 
601   bufSend = malloc(nSendBufferSize);
602   memset(bufSend, 0, nSendBufferSize);
603   memcpy(bufSend, &snmpv1_a, sizeof(snmpv1_a));
604   memcpy(bufSend + sizeof(snmpv1_a), szPassword, strlen(szPassword));
605   memcpy(bufSend + sizeof(snmpv1_a) + strlen(szPassword), &snmpv1_r, sizeof(snmpv1_r));
606 
607   writeError(ERR_DEBUG_MODULE, "[%s] Sending GET request for system.sysLocation.", MODULE_NAME);
608   if (medusaSend(hSocket, bufSend, nSendBufferSize - 1, 0) < 0)
609   {
610     writeError(ERR_ERROR, "%s failed: medusaSend was not successful", MODULE_NAME);
611     free(bufSend);
612     return(MSTATE_FAILURE);
613   }
614   free(bufSend);
615 
616   return(MSTATE_RUNNING);
617 }
618 
sendWrite(int hSocket,_SNMP_DATA * _psSessionData,char * szPassword,char * szLocation)619 int sendWrite(int hSocket, _SNMP_DATA* _psSessionData, char* szPassword, char* szLocation)
620 {
621   unsigned char* bufSend;
622   int nSendBufferSize = 0;
623 
624   struct _SNMPV1_A {
625     char ID;
626     char len;
627     char ver[3];
628     char comid;
629     char comlen;
630   } snmpv1_a = {
631     .ID = '\x30',
632     .len = '\x00',
633     .ver = "\x02\x01\x00",  /* \x02\x01\x01 for snmp v2c */
634     .comid = '\x04',
635     .comlen = '\x00'
636   };
637 
638   struct _SNMPV1_W {
639     char type[2];
640     char identid[2];
641     char ident[4];
642     char errstat[3];
643     char errind[3];
644     char objectid[2];
645     char object[12];
646     char value[2];
647   } snmpv1_w = {
648     .type = "\xa3\x20",                                       /* SET */
649     .identid = "\x02\x04",
650     .ident = "\x6f\x67\x4e\xe1",                              /* request id - doesn't matter */
651     .errstat = "\x02\x01\x00",                                /* no error */
652     .errind = "\x02\x01\x00",                                 /* error index 0 */
653     .objectid = "\x30\x0c",
654     .object = "\x30\x0c\x06\x08\x2b\x06\x01\x02\x01\x01\x06\x00", /* sysLocation */
655     .value = "\x04\x00"                                       /* write value */
656   };
657 
658   if (_psSessionData->nVersion == SNMP_VER_V2C)
659     snmpv1_a.ver[2] = '\x01';
660 
661   if (szLocation == NULL)
662     szLocation = "";
663 
664   nSendBufferSize = sizeof(snmpv1_a) + sizeof(snmpv1_w) + strlen(szPassword) + strlen(szLocation) + 1;
665   snmpv1_a.comlen = (char) strlen(szPassword);
666   snmpv1_a.len = nSendBufferSize - 3;
667 
668   bufSend = malloc(nSendBufferSize);
669   memset(bufSend, 0, nSendBufferSize);
670   memcpy(bufSend, &snmpv1_a, sizeof(snmpv1_a));
671   memcpy(bufSend + sizeof(snmpv1_a), szPassword, strlen(szPassword));
672   memcpy(bufSend + sizeof(snmpv1_a) + strlen(szPassword), &snmpv1_w, sizeof(snmpv1_w));
673   memset(bufSend + sizeof(snmpv1_a) + strlen(szPassword) + 1, 28 + strlen(szLocation), 1); /* set length remaining */
674   memset(bufSend + sizeof(snmpv1_a) + strlen(szPassword) + 15, 14 + strlen(szLocation), 1); /* set length remaining */
675   memset(bufSend + sizeof(snmpv1_a) + strlen(szPassword) + 17, 12 + strlen(szLocation), 1); /* set length remaining */
676   memset(bufSend + sizeof(snmpv1_a) + strlen(szPassword) + sizeof(snmpv1_w) - 1, strlen(szLocation), 1);
677   strncpy((char *)bufSend + sizeof(snmpv1_a) + strlen(szPassword) + sizeof(snmpv1_w), szLocation, strlen(szLocation));
678 
679   writeError(ERR_DEBUG_MODULE, "[%s] Sending SET request for system.sysLocation.", MODULE_NAME);
680   if (medusaSend(hSocket, bufSend, nSendBufferSize - 1, 0) < 0)
681   {
682     writeError(ERR_ERROR, "%s failed: medusaSend was not successful", MODULE_NAME);
683     free(bufSend);
684     return(FAILURE);
685   }
686   free(bufSend);
687 
688   return(SUCCESS);
689 }
690 
receiveRequest(int hSocket,_SNMP_DATA * _psSessionData,int * nPassCount,char *** arrszPassList,char ** szLocation)691 int receiveRequest(int hSocket, _SNMP_DATA* _psSessionData, int* nPassCount, char*** arrszPassList, char** szLocation)
692 {
693   unsigned char *bufReceive = NULL;
694   unsigned char *bufReceiveTmp = NULL;
695   int i, nReceiveBufferSize, nReceiveBufferSizeTmp;
696   int nResponse = FAILURE;
697   int nSNMPLength;
698 
699   nReceiveBufferSize = 0;
700   bufReceive = medusaReceiveRawDelay(hSocket, &nReceiveBufferSize, _psSessionData->nReadTimeout, _psSessionData->nReadTimeout);
701   if (bufReceive == NULL)
702   {
703     writeError(ERR_DEBUG_MODULE, "[%s] No data received. Possible incorrect community string.", MODULE_NAME);
704     return(FAILURE);
705   }
706 
707   *nPassCount = countResponses(nReceiveBufferSize, bufReceive);
708   if (*nPassCount <= 0)
709   {
710     writeError(ERR_ERROR, "[%s] Responses received, however, no community strings were located.", MODULE_NAME);
711     return(FAILURE);
712   }
713   else
714   {
715     writeError(ERR_DEBUG_MODULE, "[%s] Creating password array for %d entries.", MODULE_NAME, *nPassCount);
716     *arrszPassList = malloc(*nPassCount * sizeof(char*));
717     memset(*arrszPassList, 0, *nPassCount * sizeof(char*));
718   }
719 
720   bufReceiveTmp = bufReceive;
721   nReceiveBufferSizeTmp = nReceiveBufferSize;
722   for (i = 0; i < *nPassCount; i++)
723   {
724     writeError(ERR_DEBUG_MODULE, "[%s] Retrieving data for response: %d.", MODULE_NAME, i+1);
725     nResponse = processResponse(nReceiveBufferSizeTmp, bufReceiveTmp, &nSNMPLength, &(*arrszPassList)[i], szLocation);
726     if (nResponse == SUCCESS)
727     {
728       writeError(ERR_DEBUG_MODULE, "[%s] Retrieved SNMP data (%d bytes). Community String: %s Location: %s.", MODULE_NAME, nSNMPLength, (*arrszPassList)[i], *szLocation);
729     }
730     else
731       writeError(ERR_ERROR, "[%s] Error processing SNMP response (%d).", MODULE_NAME, i+1);
732 
733     bufReceiveTmp += (nSNMPLength + 2);
734     nReceiveBufferSizeTmp -= (nSNMPLength + 2);
735   }
736 
737   free(bufReceive);
738 
739   return(nResponse);
740 }
741