IServerConnect / open_s Example

 

The purpose of the open_s method is to allow passing of  connection information without using system strings so that the memory image of a running program does not contain the clear text connection string passed by the caller.  To that end, callers of this function must be careful not to leave copies of the input in memory.  Below is the source for in VB and  C++ for a small program that calls open_s without leaving the connection string in memory.

 

Visual Basic Example

This example builds an array of Bytes and fills it with the unicode characters that make up  the connection string.  As soon as the program is done with the array it fills it with spaces. 

Option Explicit

Private Sub Command1_Click()
On Error GoTo eh
  Dim srv As Server
  Set srv = Servers("myserver")
  Dim isc As IServerConnect
  Set isc = srv
  Dim arrCon() As Byte
  ReDim arrCon((23 + 1) * 2)
  arrCon(0) = &H55  'U
  arrCon(1) = 0
  arrCon(2) = &H49  'I
  arrCon(3) = 0
  arrCon(4) = &H44  'D
  arrCon(5) = 0
  arrCon(6) = &H3D  '=
  arrCon(7) = 0
  arrCon(8) = &H70  'p'
  arrCon(9) = 0
  arrCon(10) = &H69  'i'
  arrCon(11) = 0
  arrCon(12) = &H64 'd
  arrCon(13) = 0
  arrCon(14) = &H65  'e
  arrCon(15) = 0
  arrCon(16) = &H6D  'm
  arrCon(17) = 0
  arrCon(18) = &H6F  'o
  arrCon(19) = 0
  arrCon(20) = &H3B  ';
  arrCon(21) = 0
  arrCon(22) = &H70  'p
  arrCon(23) = 0
  arrCon(24) = &H77  'w
  arrCon(25) = 0
  arrCon(26) = &H64  'd
  arrCon(27) = 0
  arrCon(28) = &H3D  '=
  arrCon(29) = 0
  arrCon(30) = &H4D  'M
  arrCon(31) = 0
  arrCon(32) = &H61  'a
  arrCon(33) = 0
  arrCon(34) = &H74  't
  arrCon(35) = 0
  arrCon(36) = &H74  't
  arrCon(37) = 0
  arrCon(38) = &H68  'h
  arrCon(39) = 0
  arrCon(40) = &H65  'e
  arrCon(41) = 0
  arrCon(42) = &H77  'w
  arrCon(43) = 0
  arrCon(44) = &H41  'A
  arrCon(45) = 0
  arrCon(46) = &H0   'null
  arrCon(47) = 0
  
  isc.Open_s arrCon
  arrCon = Space(46)
  
  MsgBox "Open_s succeeded"
  Exit Sub
eh:
   MsgBox Err.Description
End Sub

C++ Example

This C++ example obtains a password from the user and builds a connection string in a wide character string (not a BSTR).  After the call the arrays and the variables are cleared so memory does not contain the connection string. The program pauses after connecting so memory can be inspected right after the open and also after the SDK obejcts wind down.  Note the seemingly meaningless assignment using the volatile key word. This is necessary to keep the code that cleans the buffer from being optimized away by the compiler.  This is necessary even if the buffer is on the stack rather than on the heap as shown here.


#include "stdafx.h"
#import "pisdkcommon.dll" no_namespace
#import "pitimeserver.dll" no_namespace
#import "pisdk.dll" no_namespace
#include 
#include 
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
   HRESULT hr;
   try
   {
      CoInitialize(NULL);
      IPISDK * pPISDK;
      hr = CoCreateInstance(_uuidof(PISDK),NULL,CLSCTX_INPROC_SERVER ,_uuidof(IPISDK),(void * *)&pPISDK);
      if(!SUCCEEDED(hr))
      {
         std::cout << "Failed to create PISDK object. " << hr << endl;
         return -1;
      }
      Servers * pServers;
      hr = pPISDK->get_Servers(&pServers);
      if(!SUCCEEDED(hr))
      {
         std::cout << "Failed to obtain Servers object. " << hr << endl;
         return -1;
      }
      Server * pServer;
      BSTR bServerName = SysAllocString(L"myserver");
      hr = pServers->get_Item(bServerName,&pServer);
      if(!SUCCEEDED(hr))
      {
         std::cout << "Failed to obtain Server object. " << hr << endl;
         return -1;
      }

      wchar_t * pszConnString = new wchar_t[200];
      //wsprintf(pszConnString,L"UID=pidemo;PWD=%s",pszPW);
      //size_t lenConnString = wcslen(pszConnString);
      size_t lenConnString = 23;
      wsprintf(pszConnString,L"UID=pidemo;");//PWD=%s",pszPW);
      pszConnString[11]=L'P';
      pszConnString[12]=L'W';
      pszConnString[13]=L'D';
      pszConnString[14]=L'=';
      pszConnString[15]=L'M';
      pszConnString[16]=L'a';
      pszConnString[17]=L't';
      pszConnString[18]=L't';
      pszConnString[19]=L'h';
      pszConnString[20]=L'e';
      pszConnString[21]=L'w';
      pszConnString[22]=L'A';
      pszConnString[23]=0;
      // Build an array of wide chars with the connection string
      IServerConnectPtr pIPIServerConnect = pServer;
      SAFEARRAY *pArray;
//      SAFEARRAYBOUND bounds = {((ULONG)lenConnString + 1) * 2,0};
      SAFEARRAYBOUND bounds = {(23+ 1) * 2,0};
      pArray = SafeArrayCreate(VT_UI1,1,&bounds);
      if(!pArray)
      {
         std::cout << "Failed to create SafeArray " << GetLastError() << endl;
         return -1;
      }
      WORD * pWord;
      HRESULT hr = SafeArrayAccessData(pArray,(void **)&pWord);
      if(!SUCCEEDED(hr))
      {
         std::cout << "Falied to access SafeArray " << hr << endl;
      }
      for(unsigned int i=0; i< lenConnString; ++i)
      {
         pWord[i] = pszConnString[i];
      }
      pWord[lenConnString] = 0;
      hr = SafeArrayUnaccessData(pArray);
      pIPIServerConnect->Open_s(&pArray);
      // clear the array before destroying
      hr = SafeArrayAccessData(pArray,(void **)&pWord);
      memset(pWord,0,lenConnString * 2);
      hr = SafeArrayUnaccessData(pArray);
      hr = SafeArrayDestroy(pArray);

      // clean up strings we have used
      memset(pszConnString,0,200);
      *(volatile wchar_t *)pszConnString = *(volatile wchar_t *)pszConnString ;
      delete []pszConnString;
      std::cout << "Open:  Waiting for key to exit try loop and destruct sdk objs" << endl;
      _getch();
   }
   catch(_com_error err)
   {
      std::cout << "COM Exception " << err.Error() << endl;
   }
      std::cout << "Out of Try loop just before exiting: Hit a key: " << endl; 
      _getch();
   CoUninitialize();
	return 0;
}


Enabling Operational Intelligence