1 /***********************************************************************/
2 /*  TABMAC: Author Olivier Bertrand -- PlugDB -- 2008-2012             */
3 /*  From the article and sample code by Khalid Shaikh.                 */
4 /*  TABMAC: virtual table to get the list of MAC addresses.            */
5 /***********************************************************************/
6 #if defined(_WIN32)
7 #include "my_global.h"
8 //#include <iphlpapi.h>
9 #else   // !_WIN32
10 #error This is a WINDOWS only table type
11 #endif  // !_WIN32
12 #include "global.h"
13 #include "plgdbsem.h"
14 //#include "catalog.h"
15 //#include "reldef.h"
16 #include "xtable.h"
17 #include "colblk.h"
18 #include "tabmac.h"
19 
20 #if 0    // This is placed here just to know what are the actual values
21 #define MAX_ADAPTER_DESCRIPTION_LENGTH  128
22 #define MAX_ADAPTER_NAME_LENGTH         256
23 #define MAX_ADAPTER_ADDRESS_LENGTH      8
24 #define DEFAULT_MINIMUM_ENTITIES        32
25 #define MAX_HOSTNAME_LEN                128
26 #define MAX_DOMAIN_NAME_LEN             128
27 #define MAX_SCOPE_ID_LEN                256
28 
29 #define BROADCAST_NODETYPE              1
30 #define PEER_TO_PEER_NODETYPE           2
31 #define MIXED_NODETYPE                  4
32 #define HYBRID_NODETYPE                 8
33 
34 #define IP_ADAPTER_DDNS_ENABLED               0x01
35 #define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX    0x02
36 #define IP_ADAPTER_DHCP_ENABLED               0x04
37 #define IP_ADAPTER_RECEIVE_ONLY               0x08
38 #define IP_ADAPTER_NO_MULTICAST               0x10
39 #define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
40 #endif // 0
41 
42 /* -------------- Implementation of the MAC classes  ------------------ */
43 
44 /***********************************************************************/
45 /*  DefineAM: define specific AM block values from MAC file.           */
46 /***********************************************************************/
DefineAM(PGLOBAL g,LPCSTR am,int poff)47 bool MACDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
48   {
49   return false;
50   } // end of DefineAM
51 
52 /***********************************************************************/
53 /*  GetTable: makes a new TDB of the proper type.                      */
54 /***********************************************************************/
GetTable(PGLOBAL g,MODE m)55 PTDB MACDEF::GetTable(PGLOBAL g, MODE m)
56   {
57   return new(g) TDBMAC(this);
58   } // end of GetTable
59 
60 /* ------------------------------------------------------------------- */
61 
62 /***********************************************************************/
63 /*  Implementation of the TDBMAC class.                               */
64 /***********************************************************************/
TDBMAC(PMACDEF tdp)65 TDBMAC::TDBMAC(PMACDEF tdp) : TDBASE(tdp)
66   {
67   FixedInfo = NULL;
68   Piaf = NULL;
69   Curp = NULL;
70   Next = NULL;
71   Buflen = 0;
72   Fix = false;
73   Adap = false;
74   N = 0;
75   } // end of TDBMAC constructor
76 
77 /***********************************************************************/
78 /*  Allocate MAC column description block.                             */
79 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)80 PCOL TDBMAC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
81   {
82   PCOL colp;
83 
84   colp = new(g) MACCOL(cdp, this, n);
85 
86   if (cprec) {
87     colp->SetNext(cprec->GetNext());
88     cprec->SetNext(colp);
89   } else {
90     colp->SetNext(Columns);
91     Columns = colp;
92   } // endif cprec
93 
94   return colp;
95   } // end of MakeCol
96 
97 /***********************************************************************/
98 /*  MAC: Get the number of found adapters.                             */
99 /***********************************************************************/
MakeErrorMsg(PGLOBAL g,DWORD drc)100 void TDBMAC::MakeErrorMsg(PGLOBAL g, DWORD drc)
101   {
102   if (drc == ERROR_BUFFER_OVERFLOW)
103     sprintf(g->Message,
104       "GetAdaptersInfo: Buffer Overflow buflen=%d maxsize=%d",
105       Buflen, MaxSize);
106   else if (drc == ERROR_INVALID_PARAMETER)
107     strcpy(g->Message, "GetAdaptersInfo: Invalid parameters");
108   else if (drc == ERROR_NO_DATA)
109     strcpy(g->Message,
110            "No adapter information exists for the local computer");
111   else if (drc == ERROR_NOT_SUPPORTED)
112     strcpy(g->Message, "GetAdaptersInfo is not supported");
113   else
114     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
115                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
116                   0, g->Message, sizeof(g->Message), NULL);
117 
118   } // end of MakeErrorMsg
119 
120 /***********************************************************************/
121 /*  GetMacInfo: Get info for all found adapters.                       */
122 /***********************************************************************/
GetMacInfo(PGLOBAL g)123 bool TDBMAC::GetMacInfo(PGLOBAL g)
124   {
125   DWORD drc;
126 
127   if (GetMaxSize(g) < 0)
128     return true;
129   else if (MaxSize == 0)
130     return false;
131 
132   Piaf = (PIP_ADAPTER_INFO)PlugSubAlloc(g, NULL, Buflen);
133   drc = GetAdaptersInfo(Piaf, &Buflen);
134 
135   if (drc == ERROR_SUCCESS) {
136     Next = Piaf;               // Next is the first one
137     return false;               // Success
138     } // endif drc
139 
140   MakeErrorMsg(g, drc);
141   return true;
142   } // end of GetMacInfo
143 
144 /***********************************************************************/
145 /*  GetFixedInfo: Get info for network parameters.                     */
146 /***********************************************************************/
GetFixedInfo(PGLOBAL g)147 bool TDBMAC::GetFixedInfo(PGLOBAL g)
148   {
149   ULONG len;
150   DWORD drc;
151 
152   FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, sizeof(FIXED_INFO));
153   len = sizeof(FIXED_INFO);
154   drc = GetNetworkParams(FixedInfo, &len);
155 
156   if (drc == ERROR_BUFFER_OVERFLOW) {
157     FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
158     drc = GetNetworkParams(FixedInfo, &len);
159     } // endif drc
160 
161   if (drc != ERROR_SUCCESS) {
162     sprintf(g->Message,  "GetNetworkParams failed. Rc=%08x\n", drc);
163     return true;
164     } // endif drc
165 
166   return false;
167   } // end of GetFixedInfo
168 
169 /***********************************************************************/
170 /*  MAC: Get the number of found adapters.                             */
171 /***********************************************************************/
GetMaxSize(PGLOBAL g)172 int TDBMAC::GetMaxSize(PGLOBAL g)
173   {
174   if (Use != USE_OPEN)
175     // Called from info, Adap and Fix are not set yet
176     return 1;
177 
178   if (MaxSize < 0) {
179     // Best method
180     if (Adap) {
181       DWORD drc = GetAdaptersInfo(NULL, &(Buflen = 0));
182 
183       if (drc == ERROR_SUCCESS)
184         MaxSize = (Fix) ? 1 : 0;
185       else if (drc == ERROR_BUFFER_OVERFLOW) {
186         // sizeof(IP_ADAPTER_INFO) was returning 640 but is now sometimes
187         // returning 648 while the Buflen setting remains the same (n*640)
188         // >> Of course, the code above contains a race condition....
189         // if the size of the structure Windows wants to return grows after
190         // the first call to GetAdaptersInfo() but before the second call
191         // to GetAdaptersInfo(), the second call to GetAdaptersInfo() will
192         // fail with ERROR_BUFFER_OVERFLOW as well, and your function won't
193         // work (by Jeremy Friesner on stackoverflow.com).
194         // That's why we add something to it to be comfortable.
195         MaxSize = (Buflen + 600) / sizeof(IP_ADAPTER_INFO);
196 
197         // Now Buflen must be updated if 648 is true.
198         Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
199       } else
200         MakeErrorMsg(g, drc);
201 
202     } else
203       MaxSize = (Fix) ? 1 : 0;
204 
205 #if 0
206     // This method returns too many adapters
207     DWORD dw, drc = GetNumberOfInterfaces((PDWORD)&dw);
208 
209     if (drc == NO_ERROR) {
210       MaxSize = (int)dw;
211       Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
212     } else
213       MakeErrorMsg(g, 0);
214 #endif
215     } // endif MaxSize
216 
217   return MaxSize;
218   } // end of GetMaxSize
219 
220 /***********************************************************************/
221 /*  MAC Access Method opening routine.                                 */
222 /***********************************************************************/
OpenDB(PGLOBAL g)223 bool TDBMAC::OpenDB(PGLOBAL g)
224   {
225   if (Use == USE_OPEN) {
226     /*******************************************************************/
227     /*  Table already open, this should not happen.                    */
228     /*******************************************************************/
229     strcpy(g->Message, "TDBMAC should not be reopened");
230     return true;
231     } // endif use
232 
233   if (Mode != MODE_READ) {
234     /*******************************************************************/
235     /* MAC tables cannot be modified.                                  */
236     /*******************************************************************/
237     strcpy(g->Message, "MAC tables are read only");
238     return true;
239   } else
240     Use = USE_OPEN;
241 
242   /*********************************************************************/
243   /*  Get the adapters info.                                           */
244   /*********************************************************************/
245   if (Adap && GetMacInfo(g))
246     return true;
247 
248   if (Fix && GetFixedInfo(g))
249     return true;
250 
251   /*********************************************************************/
252   /*  All is done.                                                     */
253   /*********************************************************************/
254   return false;
255   } // end of OpenDB
256 
257 /***********************************************************************/
258 /*  Data Base read routine for MAC access method.                      */
259 /***********************************************************************/
ReadDB(PGLOBAL g)260 int TDBMAC::ReadDB(PGLOBAL g)
261   {
262   Curp = Next;
263 
264   if (Curp)
265     Next = Curp->Next;
266   else if (N || !Fix)
267     return RC_EF;
268 
269   N++;
270   return RC_OK;
271   } // end of ReadDB
272 
273 /***********************************************************************/
274 /*  WriteDB: Data Base write routine for MAC access methods.           */
275 /***********************************************************************/
WriteDB(PGLOBAL g)276 int TDBMAC::WriteDB(PGLOBAL g)
277   {
278   strcpy(g->Message, "MAC tables are read only");
279   return RC_FX;
280   } // end of WriteDB
281 
282 /***********************************************************************/
283 /*  Data Base delete line routine for MAC access methods.              */
284 /***********************************************************************/
DeleteDB(PGLOBAL g,int irc)285 int TDBMAC::DeleteDB(PGLOBAL g, int irc)
286   {
287   strcpy(g->Message, "Delete not enabled for MAC tables");
288   return RC_FX;
289   } // end of DeleteDB
290 
291 // ------------------------ MACCOL functions ----------------------------
292 
293 /***********************************************************************/
294 /*  MACCOL public constructor.                                         */
295 /***********************************************************************/
MACCOL(PCOLDEF cdp,PTDB tdbp,int n)296 MACCOL::MACCOL(PCOLDEF cdp, PTDB tdbp, int n)
297       : COLBLK(cdp, tdbp, n)
298   {
299   Tdbp = (PTDBMAC)tdbp;
300   Flag = cdp->GetOffset();
301 
302   if (Flag < 10)
303     Tdbp->Fix = true;
304   else
305     Tdbp->Adap = true;
306 
307   } // end of MACCOL constructor
308 
309 /***********************************************************************/
310 /*  Read the next MAC address elements.                                */
311 /***********************************************************************/
ReadColumn(PGLOBAL g)312 void MACCOL::ReadColumn(PGLOBAL g)
313   {
314   // Type conversion is handled by Value set routines
315   char            *p = NULL, buf[260] = "";
316   unsigned int     i;
317   int             n = 0;
318   PIP_ADAPTER_INFO adp = Tdbp->Curp;
319   FIXED_INFO      *fip = Tdbp->FixedInfo;
320 
321   if (!adp && Flag >= 10) {
322     // Fix info row, no adapter info available
323     switch (Flag) {
324       case 13:
325       case 14:
326       case 19:
327       case 22:
328       case 23:
329         n = 0;
330         break;
331       default:
332         p = PlugDup(g, "");
333       } // endswitch Flag
334 
335   } else switch (Flag) {
336     // FIXED INFO
337     case 1:                      // Host Name
338       p = fip->HostName;
339       break;
340     case 2:                      // Domain Name
341       p = fip->DomainName;
342       break;
343     case 3:                      // DNS IPaddress
344       p = (fip->CurrentDnsServer)
345         ? (char*)&fip->CurrentDnsServer->IpAddress
346         : (char*)&fip->DnsServerList.IpAddress;
347       break;
348     case 4:                      // Node Type
349       n = (int)fip->NodeType;
350       break;
351     case 5:                      // Scope ID ???
352       p = fip->ScopeId;
353       break;
354     case 6:                      // Routing enabled
355       n = (int)fip->EnableRouting;
356       break;
357     case 7:                      // Proxy enabled
358       n = (int)fip->EnableProxy;
359       break;
360     case 8:                      // DNS enabled
361       n = (int)fip->EnableDns;
362       break;
363     // ADAPTERS INFO
364     case 10:                    // Name
365       p = adp->AdapterName;
366       break;
367     case 11:                    // Description
368       if ((p = strstr(adp->Description, " - Packet Scheduler Miniport"))) {
369         strncpy(buf, adp->Description, p - adp->Description);
370         i = (int)(p - adp->Description);
371         strncpy(buf, adp->Description, i);
372         buf[i] = 0;
373         p = buf;
374       } else if ((p = strstr(adp->Description,
375                   " - Miniport d'ordonnancement de paquets"))) {
376         i = (int)(p - adp->Description);
377         strncpy(buf, adp->Description, i);
378         buf[i] = 0;
379         p = buf;
380       } else
381         p = adp->Description;
382 
383       break;
384     case 12:                    // MAC Address
385       for (p = buf, i = 0; i < adp->AddressLength; i++) {
386         if (i)
387           strcat(p++, "-");
388 
389         p += sprintf(p, "%.2X", adp->Address[i]);
390         } // endfor i
391 
392       p = buf;
393       break;
394     case 13:                    // Type
395 #if 0                        // This is not found in the SDK
396       switch (adp->Type) {
397         case IF_ETHERNET_ADAPTERTYPE:   p = "Ethernet Adapter";      break;
398         case IF_TOKEN_RING_ADAPTERTYPE: p = "Token Ring Adapter";   break;
399         case IF_FDDI_ADAPTERTYPE:       p = "FDDI Adapter";          break;
400         case IF_PPP_ADAPTERTYPE:         p = "PPP Adapter";          break;
401         case IF_LOOPBACK_ADAPTERTYPE:   p = "Loop Back Adapter";    break;
402 //      case IF_SLIP_ADAPTERTYPE:        p = "Generic Slip Adapter";  break;
403         default:
404           sprintf(buf, "Other Adapter, type=%d", adp->Type);
405           p = buf;
406         } // endswitch Type
407 #endif // 0
408       n = (int)adp->Type;
409       break;
410     case 14:                    // DHCP enabled
411       n = (int)adp->DhcpEnabled;
412       break;
413     case 15:                    // IP Address
414       p = (adp->CurrentIpAddress)
415         ? (char*)&adp->CurrentIpAddress->IpAddress
416         : (char*)&adp->IpAddressList.IpAddress;
417       break;
418     case 16:                    // Subnet Mask
419       p = (adp->CurrentIpAddress)
420         ? (char*)&adp->CurrentIpAddress->IpMask
421         : (char*)&adp->IpAddressList.IpMask;
422       break;
423     case 17:                    // Gateway
424       p = (char*)&adp->GatewayList.IpAddress;
425       break;
426     case 18:                    // DHCP Server
427       p = (char*)&adp->DhcpServer.IpAddress;
428       break;
429     case 19:                    // Have WINS
430       n = (adp->HaveWins) ? 1 : 0;
431       break;
432     case 20:                    // Primary WINS
433       p = (char*)&adp->PrimaryWinsServer.IpAddress;
434       break;
435     case 21:                    // Secondary WINS
436       p = (char*)&adp->SecondaryWinsServer.IpAddress;
437       break;
438     case 22:                    // Lease obtained
439       n = (int)adp->LeaseObtained;
440       break;
441     case 23:                    // Lease expires
442       n = (int)adp->LeaseExpires;
443       break;
444     default:
445       if (Buf_Type == TYPE_STRING) {
446         sprintf(buf, "Invalid flag value %d", Flag);
447         p = buf;
448       } else
449         n = 0;
450 
451     } // endswitch Flag
452 
453   if (p)
454     Value->SetValue_psz(p);
455   else
456     Value->SetValue(n);
457 
458   } // end of ReadColumn
459