SMBIOS Library
SmbiosStrategy_Windows.cpp
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
3  *
4  * Copyright (C) 2005 Dell Inc.
5  * by Michael Brown <Michael_E_Brown@dell.com>
6  * Licensed under the Open Software License version 2.1
7  *
8  * Alternatively, you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundation; either version 2 of the License,
11  * or (at your option) any later version.
12 
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  */
18 
19 // compat header should always be first header if including system headers
20 #define LIBSMBIOS_SOURCE
21 #include "smbios/compat.h"
22 
23 #include <iostream>
24 #include <sstream>
25 
26 /* stuff for WMI. needs SDK, so is optional. */
27 #ifdef LIBSMBIOS_WIN_USE_WMI
28 # ifndef _WIN32_DCOM
29 # define _WIN32_DCOM
30 # endif
31 
32 // this pragma statment will automatically add the 'wbemuuid.lib' library
33 // to program library link list
34 # pragma comment(lib, "wbemuuid")
35 
36 # include <objbase.h>
37 # include <wbemcli.h>
38 #endif
39 
40 #include "smbios/IMemory.h"
41 #include "SmbiosImpl.h"
42 #include "miniddk.h"
43 
44 // message.h should be included last.
45 #include "smbios/message.h"
46 
47 using namespace smbiosLowlevel;
48 using namespace std;
49 
50 namespace smbios
51 {
52  // Non Member Functions
53  GetSystemFirmwareTablePtr GetSystemFirmwareTable = 0;
54 
55  int LoadNtdllFuncs(void)
56  {
57  HMODULE hKerneldll;
58 
59  hKerneldll = GetModuleHandle( L"kernel32.dll" );
60  if (!hKerneldll)
61  return FALSE;
62 
63  // Donot return false since these APIs are only available on W2K3 SP1 and higher.
64  // returning FALSE will break libsmbios on W2K and W2K3( no SP )
65  GetSystemFirmwareTable = (GetSystemFirmwareTablePtr) GetProcAddress(hKerneldll, "GetSystemFirmwareTable");
66 
67  return TRUE;
68  }
69 
70 
71  bool SmbiosWinGetFirmwareTableStrategy::getSmbiosTable(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point *table_header, bool )
72  {
73  // new throws exception, no need to test.
74  u8 *newSmbiosBuffer = 0;
75 
76  DWORD iSignature = 'R'; //RSMB
77  iSignature = iSignature << 8 | 'S';
78  iSignature = iSignature << 8 | 'M';
79  iSignature = iSignature << 8 | 'B';
80 
82  if( !LoadNtdllFuncs() )
83  throw ParseExceptionImpl( _("Could not load dll functions.") );
84 
86  throw ParseExceptionImpl( _("Could not access GetSystemFirmwareTable() API.") );
87 
88  int iBufferSizeNeeded = GetSystemFirmwareTable( iSignature, 0, 0, 0 );
89  if( iBufferSizeNeeded <= 0 )
90  throw ParseExceptionImpl( _("GetSystemFirmwareTable returned 0 for table length.") );
91 
92  newSmbiosBuffer = new u8[iBufferSizeNeeded];
93  if( ! newSmbiosBuffer )
94  throw ParseExceptionImpl( _("Failed to allocate memory for Firmware table.") );
95  memset( newSmbiosBuffer, 0, sizeof(u8) * iBufferSizeNeeded );
96 
97  // populate buffer with table.
98  // Note that this is not the actual smbios table:
99  // From MS: The layout of the data returned by the raw SMBIOS table
100  // provider is identical to the data returned by the
101  // MSSmBIOS_RawSMBiosTables WMI class. The
102  // MSSmBIOS_RawSMBiosTables class is located in the root\wmi
103  // namespace.
104  GetSystemFirmwareTable( iSignature, 0, newSmbiosBuffer, iBufferSizeNeeded );
105 
106  // Have to manually set values in header because we cannot get table entry point using this api
107  table_header->dmi.table_length = static_cast<u16>(iBufferSizeNeeded);
108  table_header->major_ver = newSmbiosBuffer[1];
109  table_header->minor_ver = newSmbiosBuffer[2];
110  table_header->dmi.table_num_structs = 9999;
111 
112  // get rid of header that MS tacks on.
113 # define MS_RSMB_HEADER_SIZE 8
114 
115  memmove(newSmbiosBuffer, newSmbiosBuffer + MS_RSMB_HEADER_SIZE, iBufferSizeNeeded - MS_RSMB_HEADER_SIZE);
116  memset( newSmbiosBuffer + iBufferSizeNeeded - MS_RSMB_HEADER_SIZE, 0, MS_RSMB_HEADER_SIZE);
117 
118  //delete old one, if necessary
119  if( *smbiosBuffer )
120  {
121  memset (const_cast<u8 *>(*smbiosBuffer), 0, sizeof (**smbiosBuffer));
122  delete [] const_cast<u8 *>(*smbiosBuffer);
123  *smbiosBuffer = 0;
124  }
125 
126  *smbiosBuffer = (const u8 *) newSmbiosBuffer;
127  return true;
128  }
129 
130 
131 
132 #ifdef LIBSMBIOS_WIN_USE_WMI
133  /* NON-MEMBER functions to help parse WMI data. */
134  static void GetWMISMBIOSEntry( IWbemClassObject **pSmbios )
135  {
136  BSTR path = SysAllocString(L"root\\wmi");
137  BSTR className = SysAllocString(L"MSSmBios_RawSMBiosTables");
138  ULONG uReturned = 1;
139  HRESULT hr = S_FALSE;
140  IWbemLocator *pLocator = NULL;
141  IWbemServices *pNamespace = NULL;
142  IEnumWbemClassObject *pEnumSMBIOS = NULL;
143 
144  try
145  {
146  hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE,
147  NULL, EOAC_SECURE_REFS, NULL );
148 
149  /* No need to throw exception on failure for CoInitializeSecurity() because other user may have already
150  initialized it properly.
151  */
152 
153  hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLocator );
154 
155  if (! SUCCEEDED( hr ) )
156  throw InternalErrorImpl(_("CoCreateInstance() failed for locator. "
157  "Check that the security levels have been "
158  "properly initialized."
159  ));
160 
161  hr = pLocator->ConnectServer(path, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace );
162  pLocator->Release();
163 
164  if( WBEM_S_NO_ERROR != hr )
165  throw InternalErrorImpl(_("ConnectServer() failed for namespace"));
166 
167  hr = pNamespace->CreateInstanceEnum( className, 0, NULL, &pEnumSMBIOS );
168  pNamespace->Release();
169 
170  if (! SUCCEEDED( hr ) )
171  throw InternalErrorImpl(_("CreateInstanceEnum() failed for MSSmBios_RawSMBiosTables"));
172 
173  hr = pEnumSMBIOS->Next( 4000, 1, pSmbios, &uReturned );
174  pEnumSMBIOS->Release();
175 
176  if ( 1 != uReturned )
177  throw InternalErrorImpl(_("Next() failed for pEnumSMBIOS"));
178  }
179  catch(const exception &)
180  {
181  SysFreeString(className);
182  SysFreeString(path);
183  throw;
184  }
185  }
186 
187 
188  static void GetWMISMBIOSTable( IWbemClassObject *pSmbios, WMISMBIOSINFO &smbiosData )
189  {
190  BSTR propName;
191  CIMTYPE type;
192  VARIANT pVal;
193  SAFEARRAY *parray = NULL;
194 
195  if ( NULL == pSmbios )
196  throw ParseExceptionImpl( _("GetWMISMBIOSTable: NULL pointer to SMBIOS Entry specified.") );
197 
198  VariantInit(&pVal);
199 
200  propName = SysAllocString(L"SMBiosData");
201  pSmbios->Get( propName, 0L, &pVal, &type, NULL);
202  SysFreeString(propName);
203 
204  if ( ( VT_UI1 | VT_ARRAY ) != pVal.vt )
205  throw ParseExceptionImpl( _("GetWMISMBIOSTable: SMBiosData returned unknown entry type.") );
206 
207  parray = V_ARRAY(&pVal);
208 
209  smbiosData.bufferSize = parray->rgsabound[0].cElements;
210 
211  if ( smbiosData.bufferSize == 0 )
212  throw ParseExceptionImpl( _("GetWMISMBIOSTable: Buffer size was zero.") );
213 
214  smbiosData.buffer = new u8[smbiosData.bufferSize];
215  if ( ! smbiosData.buffer )
216  throw ParseExceptionImpl( _("GetWMISMBIOSTable: Failed to allocate memory for SMBIOS table.") );
217 
218  memcpy(smbiosData.buffer, (u8 *)parray->pvData, smbiosData.bufferSize);
219  }
220 
221  static void GetWMISMBIOSVersion( IWbemClassObject *pSmbios, u8 *majorVersion, u8 *minorVersion )
222  {
223  BSTR propName;
224  HRESULT hr = S_OK;
225  CIMTYPE type;
226  VARIANT pVal;
227 
228  if ( NULL == pSmbios )
229  throw ParseExceptionImpl( _("GetWMISMBIOSVersion: null pointer passed as pSmbios.") );
230 
231  VariantInit( &pVal );
232  propName = SysAllocString( L"SmbiosMajorVersion" );
233  hr = pSmbios->Get( propName, 0L, &pVal, &type, NULL );
234  SysFreeString( propName );
235 
236  if ( ! SUCCEEDED( hr ) || VT_UI1 != pVal.vt )
237  throw ParseExceptionImpl( _("GetWMISMBIOSVersion: problem accessing WMI SmbiosMajorVersion.") );
238 
239  if(majorVersion)
240  *majorVersion = V_UI1(&pVal);
241 
242  VariantClear( &pVal );
243  propName = SysAllocString( L"SmbiosMinorVersion" );
244  hr = pSmbios->Get( propName, 0L, &pVal, &type, NULL );
245  SysFreeString( propName );
246 
247  if ( !SUCCEEDED( hr ) || pVal.vt != VT_UI1 )
248  throw ParseExceptionImpl( _("GetWMISMBIOSVersion: problem accessing WMI SmbiosMinorVersion.") );
249 
250  if(minorVersion)
251  *minorVersion = V_UI1(&pVal);
252  }
253 
254  static void GetWMISMBIOSData( WMISMBIOSINFO &smbiosData )
255  {
256  IWbemClassObject *pSmbios = NULL;
257 
258  try
259  {
260  if (! SUCCEEDED( CoInitialize(0) ) )
261  throw InternalErrorImpl( _("Could not initialize COM.") );
262 
263  GetWMISMBIOSEntry( &pSmbios );
264  GetWMISMBIOSTable( pSmbios, smbiosData );
265  GetWMISMBIOSVersion( pSmbios, &smbiosData.majorVersion, &smbiosData.minorVersion );
266  }
267  catch(const exception &)
268  {
269  delete [] smbiosData.buffer;
270  smbiosData.buffer = 0;
271  throw;
272  }
273  CoUninitialize();
274  }
275 
276 
277  bool SmbiosWinWMIStrategy::getSmbiosTable(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point *table_header, bool )
278  {
279  // new throws exception, no need to test.
280  WMISMBIOSINFO wmi_smbiosData;
281  memset(&wmi_smbiosData, 0, sizeof(wmi_smbiosData));
282 
283  GetWMISMBIOSData( wmi_smbiosData );
284 
285  if( wmi_smbiosData.bufferSize <= 0 || ! wmi_smbiosData.buffer )
286  throw ParseExceptionImpl( _("getSmbiosTable(): GetWMISMBIOSData returned 0 for buffer size.") );
287 
288  // fake version information for now.
289  table_header->dmi.table_length = static_cast<u16>(wmi_smbiosData.bufferSize);
290  table_header->major_ver = wmi_smbiosData.majorVersion;
291  table_header->minor_ver = wmi_smbiosData.minorVersion;
292  table_header->dmi.table_num_structs = 9999;
293 
294  //delete old one, if necessary
295  if( *smbiosBuffer )
296  {
297  memset (const_cast<u8 *>(*smbiosBuffer), 0, sizeof (**smbiosBuffer));
298  delete [] const_cast<u8 *>(*smbiosBuffer);
299  *smbiosBuffer = 0;
300  }
301 
302  *smbiosBuffer = (const u8 *) wmi_smbiosData.buffer;
303  return true;
304  }
305 #else
306  bool SmbiosWinWMIStrategy::getSmbiosTable(const u8 **, smbiosLowlevel::smbios_table_entry_point *, bool )
307  {
308  return false;
309  }
310 #endif /* LIBSMBIOS_WIN_USE_WMI */
311 }
312