Using CoolKey CSP on Windows XP with OpenSC PKCS#11

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



As I had said in January, I was working on using the CoolKey CSP on
Windows with OpenSC. Attached is a diff file against the CVS which
can be found from this Wiki pages:
 http://directory.fedoraproject.org/wiki/CoolKey
and
 http://directory.fedoraproject.org/wiki/BuildWindowsCSP

These changes will allow for the CoolKey CSP source to be compiled
to work with the original CoolKey pkcs11, or to be compiled to use
with OpenSC pkcs11, based on options in the makefile.

The changes were compiled on Vista, using Microsoft Visual Studio 9.0,
with SDK v6.1 using the SDK SetEnv.cmd /xp /x86 /Release. I have tested
it on Windows XP SP3 with login and screen unlock with opensc-wingw-002
with the opensc*.dll's replaced by opensc-0.11.7-rc1 with one mod. This
configuration is not well tested, and there may still be many issues.

Microsoft System 7 has a built in PIV smart card driver that works in
our environment and there are commercial versions of drivers available
for XP, so we will most likely not by using this CoolKey code in production.
But someone might find the code changes interesting.

Changes made to the code:

 o Allow the same source to build multiple CSPs, each capable of calling
   a different pkcs#11. This was done by adding CSPNAME, CSPRESNAME,
   PROVIDER_NAME, DEFAULT_PKCS11_MODULE to the Makefile. The regcert.exe
   is the same for all CSPs, and takes the CSP name as a parameter.
   So it only needs to be built once. The Makefile changes have the
   CoolKey versions of these parameters commented, and the OpenSC uncommented.

 o The method of storing the signature of the CSP has changed over the years.
   W2000 had it as a separate file. XP has the signature as a resource
   in the rc file, added by the cspSign.exe. The Makefile was change to
   not create the *.dll.sig files.

 o Other Makefile changes include:
    remove debug and debug version of the libs; handling the manifest;
    using del rather the rm and setting CAPISDK.

 o Default WINVER, _WIN32_WINDOWS and _WIN32_IE were changed to target
   XP SP2 and W2003 SP1, and IE 7.0

 o Version numbers where changed in th csp.rc file.

 o Better debug message logging:
     Process number added to log message; hKey and Session are logged when
     ever possible. Default log file is C:\CSPDEBUG.log.txt.

 o When run as a CSP from winlogin, there is no stdout or stderr, and no HKCU
   Changes made to opening the log to account for this.

 o Original code tried to do a shutdown from the DllMain routines. The shutdown
   would then try an unload the pkcs11. No load/unload module code is allowed
   from the DllMain. Shutdown is now called when the last session is released.
   shutdown may now be called from two places, and passes a why option.
   A startup was also added for the same reason.

 o Processing of the qualified container name was changed so the same container
   name is returned when requested. the format is: \\.\<readername>\<container>

 o Some changes made to the parse routine and StringifyByte to get NULL
   terminated strings correct.

 o When called in silent mode, it will assume that a certificate has a matching
   public and private key, even if not visible with PKCS#11 public session.

 o When ever window presents a PIN, will call C_Logout, C_Login to make sure we
   still have a valid session.


Other Windows specific issues:

 o Winlogin, and will keep a session open while the user is logged in, This
   will keep the PKCS#11 DLL loaded, and open PKCS#11 sessions.

 o OpenSC debug logs can write to a file, but the file must be world writable,
   as the LSA, winlogin and the user may write to it. The file will stay open
   as long as the DLL is loaded. During login there is no stdout or stderr
   so the debug or error files can not use them.

 o PC/SC SCardBeginTranaction can fail with 80100069 SCARD_W_REMOVED_CARD
   when called for lock, unlock or any other operation.  OpenSC is not setup
   to handle this correctly, as I outlines in my 02/17/2009 and 02/20/2009
   notes. One solution is to remove the line in opensc src/pkcs11/slot.c:
     if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT))
   This will force a check for a card at the start of ever C_OpenSession.
   This is very important with the screen unlock.

Other info related to the CoolKey Wiki pages:

  There is no *.sig file, so it does not need to be copied to \WINDOWS\system32.

  If built for OpenSC: the two files clkcsp-opensc.dll and clkcspres-opensc.dll
  need to be copied to \WINDOWS\system32, and the command:
    regsvr32 clkcsp-opensc.dll
  needs to be run to cause the dll to register itself under
  [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Default\Provider\CoolKey OpenSC CSP]

Then for each card ATR you want to use with OpenSC, add something like this
to the registry, changing the location and ATR, and ATRMask:

 Windows Registry Editor Version 5.00

 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Oberthur PIV via CoolKey OpenSC]
 "ATR"=hex:3b,db,96,00,81,b1,fe,45,1f,03,80,f9,a0,00,00,03,08,00,00,10,00,18
 "ATRMask"=hex:ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
 "Crypto Provider"="CoolKey OpenSC CSP"

Since CSPs must be signed by Microsoft, for testing you will need to find on
the Internet the changes need to advapi32.dll to skip the signature test. Google for
   advapi32.dll CSP patch xp
should get you the information for SP2 and SP3.

To register a certificate in the Certificate Store, insert the card, then run
 regcerts.exe "CoolKey OpenSC CSP"
This will read the cert from the card, and add it to the cert store. This in
not needed for login, but needed if used for other Windows applications.

Good luck.

--

 Douglas E. Engert  <DEEngert@xxxxxxx>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439
 (630) 252-5444
--- ./src/windows/csp/,Makefile	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp/Makefile	Thu Jan 29 13:28:49 2009
@@ -16,30 +16,56 @@
 # All rights reserved.
 # END COPYRIGHT BLOCK 
 #
+CAPISDK=c:\opt\zipfiles\Microsoft\CSP
+#
+# Multiple versions of the package can be built by 
+# setting: 
+# CSPNAME, CSPRESNAME, PROVIDER_NAME and DEFAULT_PKCS11_MODULE
+# this will build CSPNAME.dll and CSPRESNAME.dll 
+# PROVIDER_NAME is the name used in the registry, 
+# DEFAULT_PKCS11_MODULE is the PKCS#11 DLL name added to the registry. 
+#
+# Note that regcert.exe is the same for all. 
+#
+# For the original Coolkey use:
+#CSPNAME=clkcsp
+#CSPRESNAME=cspres
+#PROVIDER_NAME=CoolKey PKCS ^#11 CSP
+#DEFAULT_PKCS11_MODULE=coolkeypk11.dll
+#
+# For OpenSC use:
+CSPNAME=clkcsp-opensc
+CSPRESNAME=clkcspres-opensc
+PROVIDER_NAME=CoolKey OpenSC CSP
+DEFAULT_PKCS11_MODULE=opensc-pkcs11.dll
 #
 # Nmake capable makefile.
 # 
-LCFLAGS=-Od -I$(CAPISDK)/sdkinc -DWIN32 -D_DEBUG -D_WINDOWS -D_USRDLL    \
-          -D_CONSOLE -DCSP_EXPORTS -D_WINDLL -DIDA_PROMPT_PINGUI -D_MBCS \
+LCFLAGS=-Od -I$(CAPISDK)\sdkinc -DWIN32  -D_WINDOWS -D_USRDLL    \
+	  -DPROVIDER_NAME="\"$(PROVIDER_NAME)\"" \
+	  -DCSPNAME=$(CSPNAME) \
+	  -DCSPRESNAME=$(CSPRESNAME) \
+	  -DDEFAULT_PKCS11_MODULE="\"$(DEFAULT_PKCS11_MODULE)\"" \
+    -D_CONSOLE -DCSP_EXPORTS -D_WINDLL -DIDA_PROMPT_PINGUI -D_MBCS \
 	  -Gm -EHsc -RTC1 -W3 -nologo -c -ZI -TP
 
-CSPRESFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"cspres.def" /DEBUG     \
-            /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"cspres.lib" \
+CSPRESFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:cspres.def   \
+            /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:$(CSPRESNAME).lib \
             /MACHINE:X86
 
-CSPFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"csp.def" /DEBUG               \
-	 /SUBSYSTEM:WINDOWS /IMPLIB:"clkcsp.lib" /MACHINE:X86 crypt32.lib \
-	 RpcRT4.Lib winscard.lib Scarddlg.lib cspres.lib  kernel32.lib    \
+CSPFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:csp.def                \
+	 /SUBSYSTEM:WINDOWS /IMPLIB:$(CSPNAME).lib /MACHINE:X86 crypt32.lib \
+	 RpcRT4.Lib winscard.lib Scarddlg.lib $(CSPRESNAME).lib  kernel32.lib    \
          user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib      \
          shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
 
-REGCERTSFLAGS=/INCREMENTAL:NO /NOLOGO /DEBUG /SUBSYSTEM:CONSOLE /MACHINE:X86 \
+REGCERTSFLAGS=/INCREMENTAL:NO /NOLOGO  /SUBSYSTEM:CONSOLE /MACHINE:X86 \
               kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib    \
               advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib       \
               odbc32.lib odbccp32.lib 
 CC=cl
 
-TARGETS=cspres.dll clkcsp.dll regcerts.exe clkcsp.sig
+TARGETS=$(CSPRESNAME).dll $(CSPNAME).dll regcerts.exe
 TRASH=*.pdb *.lib *.exp *.idb
 
 CSP_OBJ =  \
@@ -64,35 +90,36 @@
     RegCerts.obj \
     $(NULL)
 
-.SUFFIXES: .cpp .obj .OBJ .rc .res .Obj .dll .sig
+.SUFFIXES: .cpp .obj .OBJ .rc .res .Obj .dll
 
 .cpp.obj:
-	$(CC) $(LCFLAGS) -MTd $<
+	$(CC) $(LCFLAGS) -MT $<
 
 .cpp.Obj:
-	$(CC) $(LCFLAGS) -MLd -Wp64 $<
+	$(CC) $(LCFLAGS) -MD -Wp64 $<
 
 .cpp.OBJ:
 	$(CC) $(LCFLAGS) -D_AFXDLL -MD $<
 
-.dll.sig: 
-	cmd /c "$(CAPISDK)/cspSign s $< $@"
-	cmd /c "$(CAPISDK)/cspSign.exe v $< $@"
-
 .rc.res:
 	rc $(DEFINES) -D_AFXDLL $<
 
 all:	$(TARGETS)
 
 clean:
-	rm -f $(TARGETS) $(CSP_OBJ) $(CSP_RES_OBJ) $(REG_CERTS_OBJ) $(TRASH)
-
-cspres.dll: $(CSP_RES_OBJ)
-	link  /OUT:cspres.dll $(CSP_RES_OBJ) $(CSPRESFLAGS)
+	del  $(TARGETS) $(CSP_OBJ) $(CSP_RES_OBJ) $(REG_CERTS_OBJ) $(TRASH)
 
-clkcsp.dll: $(CSP_OBJ) 
-	link  /OUT:clkcsp.dll $(CSP_OBJ) $(CSPFLAGS)
+$(CSPRESNAME).dll: $(CSP_RES_OBJ)
+	link  /OUT:$*.dll $(CSP_RES_OBJ) $(CSPRESFLAGS)
+	if EXIST $*.dll.manifest mt -manifest $*.dll.manifest -outputresource:$*.dll;2
+
+$(CSPNAME).dll: $(CSP_OBJ) 
+	link  /OUT:$*.dll $(CSP_OBJ) $(CSPFLAGS)
+	if EXIST $*.dll.manifest mt -manifest $*.dll.manifest -outputresource:$*.dll;2
+	"$(CAPISDK)/cspSign.exe" c $*.dll
+	"$(CAPISDK)/cspSign.exe" d $*.dll
 
 regcerts.exe: $(REG_CERTS_OBJ)
 	link  /OUT:regcerts.exe $(REG_CERTS_OBJ) $(REGCERTSFLAGS)
+	if EXIST regcerts.exe.manifest mt -manifest regcerts.exe.manifest -outputresource:regcerts.exe;2
 
--- ./src/windows/csp/,stdafx.h	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp/stdafx.h	Mon Jan 19 17:04:29 2009
@@ -28,20 +28,16 @@
 
 // Modify the following defines if you have to target a platform prior to the ones specified below.
 // Refer to MSDN for the latest info on corresponding values for different platforms.
-#ifndef WINVER				// Allow use of features specific to Windows 95 and Windows NT 4 or later.
-#define WINVER 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#ifndef WINVER				// Allow use of features specific to Windows
+#define WINVER 0x0502		// Default to target XP SP2 and W2003 SP1 
 #endif
 
-#ifndef _WIN32_WINNT		// Allow use of features specific to Windows NT 4 or later.
-#define _WIN32_WINNT 0x0400	// Change this to the appropriate value to target Windows 2000 or later.
+#ifndef _WIN32_WINNT		// Allow use of features specific to Windows
+#define _WIN32_WINNT 0x0502	// Default to target XP SP2 or W2003 SP1
 #endif						
 
-#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
-#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
-#endif
-
-#ifndef _WIN32_IE			// Allow use of features specific to IE 4.0 or later.
-#define _WIN32_IE 0x0400	// Change this to the appropriate value to target IE 5.0 or later.
+#ifndef _WIN32_IE			// Allow use of features specific to IE.
+#define _WIN32_IE 0x0700	// Default to target IE 7.0
 #endif
 
 #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit
--- ./src/windows/csp/,csp.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp/csp.cpp	Tue Feb 17 16:54:20 2009
@@ -50,7 +50,7 @@
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
       LOG("Dllmain: DLL_PROCESS_DETACH\n");
-      g_state.shutdown();
+      g_state.shutdown(0);
    }
 
    return TRUE;
@@ -82,10 +82,10 @@
     IN  DWORD dwFlags,
     IN  PVTableProvStruc pVTable)
 {
-   BEGIN_API_CALL;
-   LOG("Build: %s\n", "$Id: csp.cpp,v 1.3 2007/04/30 23:30:58 jmagne Exp $");
+   BEGIN_API_CALL_ACQUIRE;
+ //  LOG("Build: %s\n", "$Id: csp.cpp,v 1.3 2007/04/30 23:30:58 jmagne Exp $");
    LOG("Executable: \"%s\" (%s)\n", GetCurrentExecutable().c_str(), GetCurrentDLL().c_str());
-   LOG("Container: \"%s\" Flags: %s (0x%X)\n", 
+   LOG("Container: \"%s\" Flags: %s (0x%X)\n",
       szContainer, StringifyAquireFlags(dwFlags).c_str(), dwFlags);
 
    BOOL rv = TRUE;
@@ -175,7 +175,7 @@
          if (g_state.p11->C_GetSessionInfo(context->p11_, &info) == CKR_OK && 
             ((info.state == CKS_RO_USER_FUNCTIONS) || (info.state == CKS_RW_USER_FUNCTIONS)))
          {
-            LOG("PKCS#11 module in user mode, PIN verification skipped");
+            LOG("PKCS#11  module in user mode, PIN verification skipped Session:0x%x\n",context->p11_);
          }
          else
          {
@@ -193,11 +193,11 @@
 
             if (ck_rv != CKR_OK)
             {
-               DisplayError(context, "Error during PIN verification");
+               DisplayError(context, "Error during PIN verification Session:0x%x\n",context->p11_);
                Throw(NTE_FAIL);
             }
             else
-               LOG("PIN Verification Successful\n");
+               LOG("PIN Verification Successful Session:0x%x\n",context->p11_);
 #endif /* LOGIN_FOR_SESSION */
             g_state.login(context);
          }
@@ -212,10 +212,19 @@
          }
          else if (!context->newKeyset_)
          {
+           if (context->silent_)  
+           {
+			/* PKCS#11 private objects not visable in public session */
+			/* will assume there is a private key matching cert */
+			LOG("Assuming there is a default private key\n");
+           }
+           else 
+           {
             if (g_state.logging())
                DisplayError(context, "Could not find matching key-pair. This may just mean you are trying to use a certificate that does not have a matching key.\n\nIf you are attempting to install a certificate then it will not function properly. Your card may also be corrupt.");
 
             ThrowMsg(NTE_KEYSET_NOT_DEF, "Invalid container name and not CRYPT_NEWKEYSET");
+           }
          }
       }
 
@@ -643,6 +652,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey= 0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDestroyKey(hKey);
@@ -822,7 +832,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
-   LOG("dwParam:0x%X dwFlags:0x%X\n", dwParam, dwFlags);
+   LOG("hKey:0x%X dwParam:0x%X dwFlags:0x%X\n", hKey,dwParam, dwFlags);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptGetKeyParam(hKey, dwParam, pbData, pcbDataLen, dwFlags);
@@ -856,6 +866,11 @@
                ThrowMsg(NTE_FAIL, "C_GetAttributeValue failed");
          }
       }
+      else if (dwParam == KP_PERMISSIONS)
+      {
+		/* TODO For now say ENCRYPT and DECRYPT */
+        *(LPDWORD)pbData = CRYPT_ENCRYPT|CRYPT_DECRYPT;
+      }
       else
          ThrowMsg(NTE_BAD_TYPE, "Can't handle dwParam type");
    }
@@ -924,10 +939,18 @@
             CK_SESSION_INFO info;
             if (g_state.p11->C_GetSessionInfo(context->p11_, &info) == CKR_OK && 
                ((info.state == CKS_RO_USER_FUNCTIONS) || (info.state == CKS_RW_USER_FUNCTIONS)))
+#if 1
+            {
+              /* DEE OpenSC has problems, lets try C_lLogout, then C_Login if we get PIN */
+              CK_RV ck_rv = g_state.p11->C_Logout(context->p11_); 
+              LOG("PKCS#11 module in user mode, C_Logout=%d Sesssion: 0x%x\n", ck_rv, context->p11_);
+            }
+#else
             {
-               LOG("PKCS#11 module in user mode, PIN verification skipped");
+               LOG("PKCS#11 module in user mode, PIN verification skipped Session: 0x%x\n",context->p11_);
             }
             else
+#endif
             {
                CK_RV ck_rv = g_state.p11->C_Login(context->p11_, CKU_USER, 
                               (CK_UTF8CHAR*)pbData, (CK_ULONG)strlen((char*)pbData));
@@ -935,7 +958,7 @@
                if (ck_rv != CKR_OK)
                   ThrowMsg(NTE_FAIL, "Error during PIN verification");
                else
-                  LOG("PIN Verification Successful: 0x%X\n", dwParam);
+                  LOG("PIN Verification Successful: 0x%X Session:0x%x\n", dwParam, context->p11_);
             }
          }
          break;
@@ -957,9 +980,10 @@
             else
             {
                Session temp(false);
+               
                temp.p11_ = context->p11_;
-               temp.containerName_ = (char*)pbData;
-               temp.CKAID_ = (char*)pbData;
+               Session::parseFQCN((char*)pbData, &temp.containerName_, &temp.readerName_);
+               temp.CKAID_ = temp.containerName_;
                temp.CKAID_.pop_back(); // remove null
                temp.CKAID_.HexToBin();
                if (!FindObject(&temp, &hCert, CKO_CERTIFICATE))
@@ -999,14 +1023,15 @@
 
             BinStr containerName = (char*)pbData;
             CRYPT_KEY_PROV_INFO provInfo;
-            provInfo.pwszContainerName = new unsigned short[containerName.size()];
-            provInfo.pwszProvName = new unsigned short[strlen(PROVIDER_NAME) + 1];;
+            provInfo.pwszContainerName = new WCHAR[containerName.size()];
+            provInfo.pwszProvName = new WCHAR[strlen(PROVIDER_NAME) + 1];;
             provInfo.dwProvType = PROVIDER_TYPE;
             provInfo.dwFlags = 0;
             provInfo.cProvParam = 0;
             provInfo.rgProvParam = 0;
             provInfo.dwKeySpec = AT_SIGNATURE;
 
+/*DEE may need more info */
             mbstowcs(provInfo.pwszContainerName, (char*)&containerName[0], containerName.size());
             mbstowcs(provInfo.pwszProvName, PROVIDER_NAME, strlen(PROVIDER_NAME) + 1);
 
@@ -1102,6 +1127,9 @@
          if (context->verifyContext_)
             Throw(ERROR_INVALID_PARAMETER);
 
+/* DEE - should this be \\.\reader\container  and null terminated? */
+/* MSDN says this should match what was provided by CryptAcquireContext */
+
          PutDataIntoBuffer(pbData, pcbDataLen, &context->containerName_[0],
                            context->containerName_.size());
          break;
@@ -1112,7 +1140,8 @@
          GetProvParam_PP_ENUMALGS_EX(context, dwFlags, pbData, pcbDataLen);
          break;
       case PP_ENUMCONTAINERS:
-         GetProvParam_PP_ENUMCONTAINERS(context, dwFlags, pbData, pcbDataLen);
+         /* will setLastError and rv=FALSE on ERROR_NO_MORE_ITEMS */
+         rv = GetProvParam_PP_ENUMCONTAINERS(context, dwFlags, pbData, pcbDataLen);
          break;
       case PP_IMPTYPE:
          {
@@ -1143,6 +1172,7 @@
          }
          break;
       case PP_UNIQUE_CONTAINER:
+/* DEE see comments on PP_CONTAINER */
          PutDataIntoBuffer(pbData, pcbDataLen, &context->containerName_[0],
                            context->containerName_.size());
          break;
@@ -1792,6 +1822,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptEncrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen, cbBufLen);
@@ -1862,6 +1893,8 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
+
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDecrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen);
@@ -1954,6 +1987,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);
@@ -2065,6 +2099,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptHashSessionKey(hHash, hKey, dwFlags);
@@ -2267,7 +2302,7 @@
          }
          else if (ck_rv != CKR_OK)
          {
-            LOG("Error during Sign %x\n", ck_rv);
+            LOG("Error during Sign 0x%x\n", ck_rv);
             Throw(NTE_FAIL);
          }
 
@@ -2492,9 +2527,14 @@
 #else
    try
    {
+      CK_RV ret;
       Session::Ptr context = g_state.checkValidSession(hProv);
-      if (g_state.p11->C_GenerateRandom(context->p11_, pbBuffer, cbLen) != CKR_OK)
+      ret = g_state.p11->C_GenerateRandom(context->p11_, pbBuffer, cbLen);
+      if ( ret != CKR_OK)
          ThrowMsg(NTE_FAIL, "C_GenerateRandom failed");
+      LOG("Random data (len %d): \"%s\"\n", 
+             cbLen, StringifyBin(pbBuffer, cbLen, true).c_str());
+      rv = TRUE;
    }
    catch(Error& e)
    {
@@ -2556,10 +2596,13 @@
 
       // Find the objects we want
       if (!FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
-         ThrowMsg(NTE_NO_KEY, "ERROR: Could not find the private key");
+      {
+	     hPrivKey = CK_INVALID_HANDLE;
+		 LOG("Defer obtaining private key till needed");
+      }
       if (!FindObject(context, &hPubKey, CKO_PUBLIC_KEY))
       {
-         hPubKey = -1;
+         hPubKey = CK_INVALID_HANDLE;
          LOG("WARNING: Could not find the public key (will attempt to get it from cert when needed)\n");
       }
 
@@ -2669,6 +2712,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDuplicateKey(hKey, pdwReserved, dwFlags, phKey);
--- ./src/windows/csp/,RegDll.cpp	Fri Aug 10 19:57:06 2007
+++ ./src/windows/csp/RegDll.cpp	Mon Jan 26 10:49:38 2009
@@ -37,14 +37,16 @@
 // Windows key values
 #define TYPE_KEY		"Type"
 #define IMAGE_KEY		"Image Path"
-#define SIG_KEY			"Signature"
+// Signature is in RC in XP 
 
 // CSP specific key values
 #define LOG_KEY			"Logging"
 #define KEYGEN_KEY		"KeyGenHack"
 #define PIN_KEY			"PIN"
 #define MODULE_KEY		"PKCS11Module"
+#ifndef DEFAULT_PKCS11_MODULE
 #define DEFAULT_PKCS11_MODULE	"coolkeypk11.dll"
+#endif
 #define DEFAULT_PIN		"1234"
 
 
@@ -95,7 +97,7 @@
 {
     int libLen = strlen(libName);
     char *sigFile = (char *)malloc(libLen+sizeof(SIG_SUFFIX));
-    char *ext;
+    const char *ext;
 
     if (sigFile == NULL) {
 	return NULL;
@@ -253,19 +255,7 @@
     if (wrc != ERROR_SUCCESS) {
 	goto loser;
     }
-    wrc = getSignature(cspLibrary, &signature, &signatureLen);
-    if (wrc != ERROR_SUCCESS) {
-	goto loser;
-    }
-    wrc = RegSetValueEx(cspKey, SIG_KEY, 0, REG_BINARY, 
-			signature, signatureLen);
-    if (wrc != ERROR_SUCCESS) {
-	goto loser;
-    }
 loser:
-    if (signature) {
-	free(signature);
-    }
     if (cspLibrary) {
 	free(cspLibrary);
     }
--- ./src/windows/csp/,cspx.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp/cspx.cpp	Thu Jan 29 14:02:41 2009
@@ -53,12 +53,14 @@
    struct tm* time_s = localtime(&t);
 
    char timestr[32];
-   sprintf(timestr, "%.2d/%.2d %.2d:%.2d:%.2d ", 
+   sprintf(timestr, "%.2d/%.2d %.2d:%.2d:%.2d [%.4X] ", 
                   time_s->tm_mon+1, 
                   time_s->tm_mday, 
                   time_s->tm_hour, 
                   time_s->tm_min, 
-                  time_s->tm_sec);
+                  time_s->tm_sec,
+                  GetProcessId(GetCurrentProcess()));
+
 
    out << timestr;
 
@@ -66,7 +68,7 @@
    for (size_t i = 0; msg[i] != 0x00; i++)
    {
       if (last == '\n')
-         out << "               ";
+         out << "                      ";
 
       if (msg[i] == '\n' && last != '\r')
          out << '\r';
@@ -94,17 +96,21 @@
 void flogf(const char* msg0, ...)
 {
    if (!g_state.logging())
-      return;
+     return;
 
    // Preserve error state
    DWORD lastErr = GetLastError();
 
-   FILE* fp = fopen("C:\\CSPDEBUG.log", "ab");
+   FILE* fp = fopen(g_state.logFilename().c_str(), "ab");
 
    if (!fp)
    {
       fp = stderr;
-      fprintf(fp, "ERROR: no log file");
+      if (!fp)  /* if running as login CSP, no stderr... */
+      {
+          SetLastError(lastErr);
+          return;
+      }
    }
 
    string msg1 = clean_flogf(msg0);
@@ -131,12 +137,16 @@
 //  hexMode - (optional) If hexMode is on then the return string will be hex
 //            characters.  Otherwise it returns a string of printable
 //            characters (unprintable characters are converted to '.').
+//            if hexMode is off dont convert trailing '\0' to . 
 //
 // Returns:
 //  string of hex data or printable characters
 ///////////////////////////////////////////////////////////////////////////////
 string StringifyBin(const BinStr& data, bool hexMode)
 {
+//   if (hexMode == FALSE && (LPBYTE)&data[data.size() - 1] == '\0')
+//    return StringifyBin((LPBYTE)&data[0], data.size() - 1 , hexMode);
+//   else
    return StringifyBin((LPBYTE)&data[0], data.size(), hexMode);
 }
 
@@ -496,13 +506,15 @@
 //  pcbDataLen - Same as GetProvParam call
 //
 // Returns:
-//  none
+//  TRUE       - found a container
+//  FALSE      - no more containers or error
 ///////////////////////////////////////////////////////////////////////////////
-void GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
+BOOL GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
                                     OUT LPBYTE pbData,
                                     IN OUT LPDWORD pcbDataLen)
 {
    LOG("GetProvParam_PP_ENUMCONTAINERS called\n");
+   LOG("dwFlags=%d pbData=%p pcbDataLen=%d\n",dwFlags, pbData, *pcbDataLen);
 
    if (dwFlags & CRYPT_FIRST)
    {
@@ -552,10 +564,28 @@
    }
 
    if (context->containerItr_ == context->containers_.end())
-      Throw(ERROR_NO_MORE_ITEMS);
+   {
+      /* This is normal, don't throw... */
+      SetLastError(ERROR_NO_MORE_ITEMS);
+      *pcbDataLen = 0;
+      return FALSE;
+   }
+
+   {
+     /* we need to return a container name. i.e. "\\.\reader\container" */
+
+	std::string  fullcontainer = "\\\\.\\";
+
+    fullcontainer.append((const char *)&context->readerName_[0], context->readerName_.size() -1);
+    fullcontainer.append("\\");
+	fullcontainer.append((const char *)&(*context->containerItr_)[0], (*(context->containerItr_)).size() -1);  
+    fullcontainer.push_back(0);
+    LOG("returning %s\n", fullcontainer.c_str());
    
-   PutDataIntoBuffer(pbData, pcbDataLen, &(*context->containerItr_)[0], 
-         context->containerItr_->size());
+     PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)fullcontainer.data(), 
+         fullcontainer.size());
+     *pcbDataLen=fullcontainer.size();
+   }
 
    if (pbData)
       context->containerItr_++;
@@ -680,7 +710,7 @@
          if (ulNumFound == 0)
             break;
 
-         LOG("FindDefaultCert. Num Certs found %d hcert %d. \n",ulNumFound,hCert);
+         LOG("FindDefaultCert. Num Certs found %d hCert %d. \n",ulNumFound,hCert);
          // First we want the CKA_ID and CKA_VALUE lengths
          attrib[0].pValue = 0;
          attrib[1].pValue = 0;
@@ -732,6 +762,7 @@
 
    g_state.p11->C_FindObjectsFinal(context->p11_);
    
+   LOG("%s 0x%X %p\n", __FUNCTION__, GetLastError(), *phCert);
    if (*phCert)
       return true;
    else 
--- ./src/windows/csp/,State.h	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp/State.h	Thu Feb 12 13:59:44 2009
@@ -49,6 +49,8 @@
 
 public:
    CK_FUNCTION_LIST_PTR p11;
+   HMODULE p11lib; 
+
 
 public:
    State();
@@ -103,7 +105,7 @@
 
    void login(Session* session);
 
-   bool shutdown();
+   bool shutdown(int why);
 
    void lock()
       { ::WaitForSingleObject(lock_, INFINITE); }
--- ./src/windows/csp/,State.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp/State.cpp	Thu Feb 12 15:42:38 2009
@@ -35,7 +35,8 @@
 namespace MCSP {
 
 State::State()
-   : init_(false), logging_(false), logFilename_("C:\\CSPDEBUG.log"), slot_(0), keyGenHack_(false), pkcs11dllname_("PKCS11.dll"),
+   : init_(false), logging_(false), logFilename_("C:\\CSPDEBUG.log.txt"), slot_(0), keyGenHack_(false), pkcs11dllname_("PKCS11.dll"),
+     p11lib(NULL),
      p11_(CK_INVALID_HANDLE)
 {
    lock_ = ::CreateMutex(NULL, FALSE, NULL); 
@@ -60,7 +61,7 @@
       size = 0;
       if (RegQueryValueEx(hKey, TEXT("LogFilename"), 0, 0, 0, &size) == ERROR_SUCCESS)
       {
-         LOG("LogFilename size is: %u\n", size);
+         /* Can not log, until file name is set */ 
          std::string value;
          value.resize(size);
 
@@ -101,7 +102,7 @@
 
 State::~State()
 {
-   shutdown();
+   shutdown(0);
    ::CloseHandle(lock_);
 }
 
@@ -124,6 +125,7 @@
    sessions_.erase(session); 
    delete session; 
    unlock();
+   shutdown(1); /* if no more sessions unload p11lib */
 }
 
 Session* State::checkValidSession(HCRYPTPROV hProv)
@@ -175,9 +177,17 @@
 
    if (ck_rv == CKR_OK)
    {
+/*
+ * DEE why the following, looks like it is closing a session then 
+ * then opening a new one.  (But code is not used???)
+ * PKCS#11 says to C_OpenSession then C_Login, and all open sessions are
+ * promoted from Public to User( or SO)
+ * This code is closing then reopening. If its the only session 
+ * PKCS#11 lib may cleanup everything
+ */
       if (p11_ != CK_INVALID_HANDLE)
       {
-         LOG("Existing invalid session must be destroyed. \n");
+         LOG("Existing invalid session must be destroyed. 0x%x\n",p11_);
 
          g_state.p11->C_CloseSession(p11_);
          p11_ = CK_INVALID_HANDLE;
@@ -191,18 +201,21 @@
       Throw(NTE_FAIL);
    }
    else
-      LOG("PIN Verification Successful\n");
+      LOG("PIN Verification Successful Session:0x%x\n",p11_);
 
 }
 
 
-bool State::shutdown()
+bool State::shutdown(int why)
 {
+
+   if (why == 0 || sessions_.empty()) /* if detach process or last session close */
+   {
    if (init())
    {
       lock();
 
-      LOG("Shutting down CSP\n");
+      LOG("Shutting down CSP why=%d\n",why);
       
       { 
          set<Session*>::iterator itr = sessions_.begin();
@@ -231,9 +244,18 @@
 
       g_state.p11->C_Finalize(0);
       init(false);
+      LOG("Called C_Finalize\n");
+
+      if (why == 1 && p11lib)
+      {
+         LOG("FreeLibrary p11lib\n");
+         FreeLibrary(p11lib);
+         p11lib = NULL;
+      }
 
       unlock();
    }
+   }
 
    return true;
 }
@@ -253,7 +275,7 @@
 
    try
    {
-      HMODULE p11lib = LoadLibrary(pkcs11dllname_.c_str());
+      p11lib = LoadLibrary(pkcs11dllname_.c_str());
       if (p11lib == NULL)
       {
          LOG("Failed to load PKCS11 library \"%s\"\n", pkcs11dllname_.c_str());
@@ -358,7 +380,7 @@
 
                token_count++;
 
-               if (reader_name.empty())
+               if (reader_name.empty() || (char)reader_name[0] == '\0')
                {
                   // If multiple tokens, ask user
                   if (token_count > 1 && !silent)
--- ./src/windows/csp/,csp.h	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp/csp.h	Wed Jan 28 10:42:07 2009
@@ -34,11 +34,13 @@
 
 #undef UNICODE
 
+#ifndef PROVIDER_NAME
 #ifndef CSP_PASSTHROUGH
 #define PROVIDER_NAME "CoolKey PKCS #11 CSP"
 #else
 #define PROVIDER_NAME "CoolKey PKCS #11 CSP - Passthrough"
 #endif
+#endif
 
 #define PROVIDER_TYPE PROV_RSA_FULL
 #define PROVIDER_MAJOR_VERSION 1
@@ -48,8 +50,9 @@
 
 // Logging macros
 #define LOG flogf
-#define BEGIN_API_CALL LOG("+%s() - called\n", __FUNCTION__)
-#define END_API_CALL LOG(" -%s() - finished: %s (0x%X)\n", __FUNCTION__, rv ? "TRUE" : "FALSE", GetLastError());
+#define BEGIN_API_CALL LOG("+%s() - called hProv: 0x%X\n", __FUNCTION__, hProv)
+#define BEGIN_API_CALL_ACQUIRE LOG("+%s() - called\n", __FUNCTION__)
+#define END_API_CALL LOG("-%s() - finished: %s (0x%X)\n\n", __FUNCTION__, rv ? "TRUE" : "FALSE", GetLastError());
 
 #include <windows.h>
 #include <wincrypt.h>
@@ -107,7 +110,7 @@
                                  OUT LPBYTE pbData,
                                  IN OUT LPDWORD pcbDataLen);
 
-void GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
+BOOL GetProvParam_PP_ENUMCONTAINERS(Session* context, DWORD dwFlags,
                                     OUT LPBYTE pbData,
                                     IN OUT LPDWORD pcbDataLen);
 
--- ./src/windows/csp/,Session.cpp	Thu Jul 27 17:23:07 2006
+++ ./src/windows/csp/Session.cpp	Thu Jan 22 08:32:01 2009
@@ -81,7 +81,9 @@
 void Session::parseFQCN(const char* fqcn0, BinStr* container_name, BinStr* reader_name)
 {
    container_name->clear();
+   container_name->push_back(0); /* make sure we have a string */
    reader_name->clear();
+   reader_name->push_back(0);
 
    if (fqcn0 == 0 || fqcn0[0] == 0)
    {
--- ./src/windows/csp/,csp.rc	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp/csp.rc	Mon Jan 26 09:41:41 2009
@@ -108,10 +108,10 @@
         BEGIN
             VALUE "CompanyName", "Identity Alliance"
             VALUE "FileDescription", "Identity Alliance Cryptographic Service Provider"
-            VALUE "FileVersion", "1, 1, 0, 10"
+            VALUE "FileVersion", "1, 1, 0, 1099"
             VALUE "InternalName", "CLKCSP"
             VALUE "LegalCopyright", "Copyright © 2003-2005 Identity Alliance"
-            VALUE "ProductVersion", "1, 1, 0, 10"
+            VALUE "ProductVersion", "1, 1, 0, 1099"
         END
     END
     BLOCK "VarFileInfo"
--- ./src/windows/csp.single.dll/,Makefile	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp.single.dll/Makefile	Wed Jan 14 14:29:02 2009
@@ -16,30 +16,31 @@
 # All rights reserved.
 # END COPYRIGHT BLOCK 
 #
+CAPISDK=c:\opt\zipfiles\Microsoft\CSP
 #
 # Nmake capable makefile.
 # 
-LCFLAGS=-Od -I$(CAPISDK)/sdkinc -DWIN32 -D_DEBUG -D_WINDOWS -D_USRDLL    \
+LCFLAGS=-Od -I$(CAPISDK)\sdkinc -DWIN32  -D_WINDOWS -D_USRDLL    \
           -D_CONSOLE -DCSP_EXPORTS -D_WINDLL -DIDA_PROMPT_PINGUI -D_MBCS \
 	  -Gm -EHsc -RTC1 -W3 -nologo -c -ZI -TP
 
-CSPRESFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"cspres.def" /DEBUG     \
+CSPRESFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"cspres.def"      \
             /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"cspres.lib" \
             /MACHINE:X86
 
-CSPFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"csp.def" /DEBUG               \
+CSPFLAGS=/INCREMENTAL:NO /NOLOGO /DLL /DEF:"csp.def"                \
 	 /SUBSYSTEM:WINDOWS /IMPLIB:"clkcsp.lib" /MACHINE:X86 crypt32.lib \
 	 RpcRT4.Lib winscard.lib Scarddlg.lib cspres.lib  kernel32.lib    \
          user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib      \
          shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
 
-REGCERTSFLAGS=/INCREMENTAL:NO /NOLOGO /DEBUG /SUBSYSTEM:CONSOLE /MACHINE:X86 \
+REGCERTSFLAGS=/INCREMENTAL:NO /NOLOGO  /SUBSYSTEM:CONSOLE /MACHINE:X86 \
               kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib    \
               advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib       \
               odbc32.lib odbccp32.lib 
 CC=cl
 
-TARGETS=cspres.dll clkcsp.dll regcerts.exe clkcsp.sig
+TARGETS=cspres.dll clkcsp.dll regcerts.exe
 TRASH=*.pdb *.lib *.exp *.idb
 
 CSP_OBJ =  \
@@ -64,35 +65,36 @@
     RegCerts.obj \
     $(NULL)
 
-.SUFFIXES: .cpp .obj .OBJ .rc .res .Obj .dll .sig
+.SUFFIXES: .cpp .obj .OBJ .rc .res .Obj .dll
 
 .cpp.obj:
-	$(CC) $(LCFLAGS) -MTd $<
+	$(CC) $(LCFLAGS) -MT $<
 
 .cpp.Obj:
-	$(CC) $(LCFLAGS) -MLd -Wp64 $<
+	$(CC) $(LCFLAGS) -MD -Wp64 $<
 
 .cpp.OBJ:
 	$(CC) $(LCFLAGS) -D_AFXDLL -MD $<
 
-.dll.sig: 
-	cmd /c "$(CAPISDK)/cspSign s $< $@"
-	cmd /c "$(CAPISDK)/cspSign.exe v $< $@"
-
 .rc.res:
 	rc $(DEFINES) -D_AFXDLL $<
 
 all:	$(TARGETS)
 
 clean:
-	rm -f $(TARGETS) $(CSP_OBJ) $(CSP_RES_OBJ) $(REG_CERTS_OBJ) $(TRASH)
+	del  $(TARGETS) $(CSP_OBJ) $(CSP_RES_OBJ) $(REG_CERTS_OBJ) $(TRASH)
 
 cspres.dll: $(CSP_RES_OBJ)
 	link  /OUT:cspres.dll $(CSP_RES_OBJ) $(CSPRESFLAGS)
+	if EXIST cspres.dll.manifest mt -manifest cspres.dll.manifest -outputresource:cspres.dll;2
 
 clkcsp.dll: $(CSP_OBJ) 
 	link  /OUT:clkcsp.dll $(CSP_OBJ) $(CSPFLAGS)
+	if EXIST clkcsp.dll.manifest mt -manifest clkcsp.dll.manifest -outputresource:clkcsp.dll;2
+	"$(CAPISDK)/cspSign.exe" c clkcsp.dll
+	"$(CAPISDK)/cspSign.exe" d clkcsp.dll
 
 regcerts.exe: $(REG_CERTS_OBJ)
 	link  /OUT:regcerts.exe $(REG_CERTS_OBJ) $(REGCERTSFLAGS)
+	if EXIST regcerts.exe.manifest mt -manifest regcerts.exe.manifest -outputresource:regcerts.exe;2
 
--- ./src/windows/csp.single.dll/,stdafx.h	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp.single.dll/stdafx.h	Mon Jan 19 17:04:29 2009
@@ -28,20 +28,16 @@
 
 // Modify the following defines if you have to target a platform prior to the ones specified below.
 // Refer to MSDN for the latest info on corresponding values for different platforms.
-#ifndef WINVER				// Allow use of features specific to Windows 95 and Windows NT 4 or later.
-#define WINVER 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#ifndef WINVER				// Allow use of features specific to Windows
+#define WINVER 0x0502		// Default to target XP SP2 and W2003 SP1 
 #endif
 
-#ifndef _WIN32_WINNT		// Allow use of features specific to Windows NT 4 or later.
-#define _WIN32_WINNT 0x0400	// Change this to the appropriate value to target Windows 2000 or later.
+#ifndef _WIN32_WINNT		// Allow use of features specific to Windows
+#define _WIN32_WINNT 0x0502	// Default to target XP SP2 or W2003 SP1
 #endif						
 
-#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
-#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
-#endif
-
-#ifndef _WIN32_IE			// Allow use of features specific to IE 4.0 or later.
-#define _WIN32_IE 0x0400	// Change this to the appropriate value to target IE 5.0 or later.
+#ifndef _WIN32_IE			// Allow use of features specific to IE.
+#define _WIN32_IE 0x0700	// Default to target IE 7.0
 #endif
 
 #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit
--- ./src/windows/csp.single.dll/,csp.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp.single.dll/csp.cpp	Fri Jan 23 17:04:49 2009
@@ -33,7 +33,45 @@
 
 // Globals
 HINSTANCE g_hModule = NULL;
-MCSP::State MCSP::g_state;
+char * providerName = NULL;
+MCSP::State MCSP:: g_state;
+
+void
+setProviderName() 
+{
+    char * cp;
+    char *dp;
+    int len;
+    char moduleFileName[MAX_PATH+1];
+
+    len = GetModuleFileName(g_hModule, moduleFileName, MAX_PATH);
+    moduleFileName[len] = '\0';
+    cp = strrchr(moduleFileName, '\\');
+    if (cp) {
+        cp++;
+    } else {
+        cp = moduleFileName;
+    }
+    /* If module name matches the original CoolKey module name (clkcsp.dll) 
+     * then use the original PROVIDER_NAME, otherwise, make up one with the 
+     * filename of this DLL. This allows us to use multiple copies if this DLL
+     * with different names with other PKCS#11 implemetations and only require
+     * one module to be signed by Microsoft.
+     */ 
+    if (!stricmp("clkcsp.dll", cp)) {
+        providerName = strdup(PROVIDER_NAME_COOLKEY);
+    } else {  /* no, make up one as CoolKey <name> CSP */
+        dp = strrchr(cp, '.');
+        if (dp) {
+            len = dp - cp; 
+        }
+        providerName = (char *)malloc(9 + len + 4);
+        strcpy(providerName, "Coolkey ");
+        strncat(providerName, cp, len);
+        strcat(providerName," CSP");
+    }
+}
+
 
 BOOL WINAPI
 DllMain(
@@ -43,14 +81,24 @@
 {
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
+      g_hModule = hinstDLL;
+      setProviderName();
+      g_state.startup();
+      /* Order of above important
+       * State is created before DLLMain is called
+       * g_hModule names is needed to get name of dll
+       * used by providerName. 
+       * Provider name is used to in registry. 
+       * loging flags are in registry.
+       */ 
       LOG("Dllmain: DLL_PROCESS_ATTACH\n");
+      LOG("providerName: %s\n",providerName);
       DisableThreadLibraryCalls(hinstDLL);
-      g_hModule = hinstDLL;
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
       LOG("Dllmain: DLL_PROCESS_DETACH\n");
-      g_state.shutdown();
+      g_state.shutdown(0);
    }
 
    return TRUE;
@@ -82,10 +130,10 @@
     IN  DWORD dwFlags,
     IN  PVTableProvStruc pVTable)
 {
-   BEGIN_API_CALL;
-   LOG("Build: %s\n", "$Id: csp.cpp,v 1.3 2007/04/30 23:30:58 jmagne Exp $");
+   BEGIN_API_CALL_ACQUIRE;
+ //  LOG("Build: %s\n", "$Id: csp.cpp,v 1.3 2007/04/30 23:30:58 jmagne Exp $");
    LOG("Executable: \"%s\" (%s)\n", GetCurrentExecutable().c_str(), GetCurrentDLL().c_str());
-   LOG("Container: \"%s\" Flags: %s (0x%X)\n", 
+   LOG("Container: \"%s\" Flags: %s (0x%X)\n",
       szContainer, StringifyAquireFlags(dwFlags).c_str(), dwFlags);
 
    BOOL rv = TRUE;
@@ -212,10 +260,19 @@
          }
          else if (!context->newKeyset_)
          {
+           if (context->silent_)  
+           {
+			/* PKCS#11 private objects not visable in RO session */
+			/* will assume there is a private key matching  cert */
+			LOG("Assuming there is a default private key\n");
+           }
+           else 
+           {
             if (g_state.logging())
                DisplayError(context, "Could not find matching key-pair. This may just mean you are trying to use a certificate that does not have a matching key.\n\nIf you are attempting to install a certificate then it will not function properly. Your card may also be corrupt.");
 
             ThrowMsg(NTE_KEYSET_NOT_DEF, "Invalid container name and not CRYPT_NEWKEYSET");
+           }
          }
       }
 
@@ -364,7 +421,7 @@
 
          if (MessageBox(NULL, 
                         "An application is attempting to generate a keypair. Do you want to allow this?",
-                        PROVIDER_NAME, 
+                        providerName, 
                         MB_OKCANCEL | MB_ICONQUESTION | MB_TASKMODAL) == IDCANCEL)
          {
             Throw(NTE_FAIL);
@@ -643,6 +700,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey= 0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDestroyKey(hKey);
@@ -822,7 +880,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
-   LOG("dwParam:0x%X dwFlags:0x%X\n", dwParam, dwFlags);
+   LOG("hKey:0x%X dwParam:0x%X dwFlags:0x%X\n", hKey,dwParam, dwFlags);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptGetKeyParam(hKey, dwParam, pbData, pcbDataLen, dwFlags);
@@ -856,6 +914,11 @@
                ThrowMsg(NTE_FAIL, "C_GetAttributeValue failed");
          }
       }
+      else if (dwParam == KP_PERMISSIONS)
+      {
+		/* TODO For now say ENCRYPT and DECRYPT */
+        *(LPDWORD)pbData = CRYPT_ENCRYPT|CRYPT_DECRYPT;
+      }
       else
          ThrowMsg(NTE_BAD_TYPE, "Can't handle dwParam type");
    }
@@ -999,16 +1062,17 @@
 
             BinStr containerName = (char*)pbData;
             CRYPT_KEY_PROV_INFO provInfo;
-            provInfo.pwszContainerName = new unsigned short[containerName.size()];
-            provInfo.pwszProvName = new unsigned short[strlen(PROVIDER_NAME) + 1];;
+            provInfo.pwszContainerName = new WCHAR[containerName.size()];
+            provInfo.pwszProvName = new WCHAR[strlen(providerName) + 1];;
             provInfo.dwProvType = PROVIDER_TYPE;
             provInfo.dwFlags = 0;
             provInfo.cProvParam = 0;
             provInfo.rgProvParam = 0;
             provInfo.dwKeySpec = AT_SIGNATURE;
 
+/*DEE may need more info */
             mbstowcs(provInfo.pwszContainerName, (char*)&containerName[0], containerName.size());
-            mbstowcs(provInfo.pwszProvName, PROVIDER_NAME, strlen(PROVIDER_NAME) + 1);
+            mbstowcs(provInfo.pwszProvName, providerName, strlen(providerName) + 1);
 
             CertSetCertificateContextProperty(newCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfo);
 
@@ -1073,8 +1137,8 @@
    if (dwParam == PP_NAME)
    {
       if (pbData)
-         strcpy((char*)pbData, PROVIDER_NAME);
-      *pcbDataLen = (DWORD)strlen(PROVIDER_NAME) + 1;
+         strcpy((char*)pbData, providerName);
+      *pcbDataLen = (DWORD)strlen(providerName) + 1;
       rv = TRUE;
    }
    else if (dwParam == PP_KEYSET_SEC_DESCR)
@@ -1121,8 +1185,8 @@
          }
          break;
       case PP_NAME:
-         PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)PROVIDER_NAME, 
-            (unsigned long)strlen(PROVIDER_NAME) + 1);
+         PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)providerName, 
+            (unsigned long)strlen(providerName) + 1);
          break;
       case PP_VERSION:
          {
@@ -1792,6 +1856,7 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptEncrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen, cbBufLen);
@@ -1862,6 +1927,8 @@
 {
    BOOL rv = TRUE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
+
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDecrypt(hKey, hHash, fFinal, dwFlags, pbData, pcbDataLen);
@@ -1954,6 +2021,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);
@@ -2065,6 +2133,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptHashSessionKey(hHash, hKey, dwFlags);
@@ -2556,10 +2625,13 @@
 
       // Find the objects we want
       if (!FindObject(context, &hPrivKey, CKO_PRIVATE_KEY))
-         ThrowMsg(NTE_NO_KEY, "ERROR: Could not find the private key");
+      {
+	     hPrivKey = CK_INVALID_HANDLE;
+		 LOG("Defer obtaining private key till needed");
+      }
       if (!FindObject(context, &hPubKey, CKO_PUBLIC_KEY))
       {
-         hPubKey = -1;
+         hPubKey = CK_INVALID_HANDLE;
          LOG("WARNING: Could not find the public key (will attempt to get it from cert when needed)\n");
       }
 
@@ -2669,6 +2741,7 @@
 {
    BOOL rv = FALSE;
    BEGIN_API_CALL;
+   LOG("hKey:0x%X\n",hKey);
 
 #ifdef CSP_PASSTHROUGH
    rv = CryptDuplicateKey(hKey, pdwReserved, dwFlags, phKey);
--- ./src/windows/csp.single.dll/,RegDll.cpp	Fri Aug 10 19:57:06 2007
+++ ./src/windows/csp.single.dll/RegDll.cpp	Fri Jan 23 16:27:01 2009
@@ -30,6 +30,7 @@
 #include "io.h"
 
 extern HINSTANCE g_hModule;
+extern char * providerName;
 
 
 #define WINDOWS_CSP_PROVIDER \
@@ -37,7 +38,7 @@
 // Windows key values
 #define TYPE_KEY		"Type"
 #define IMAGE_KEY		"Image Path"
-#define SIG_KEY			"Signature"
+// Signature is in RC in XP 
 
 // CSP specific key values
 #define LOG_KEY			"Logging"
@@ -95,7 +96,7 @@
 {
     int libLen = strlen(libName);
     char *sigFile = (char *)malloc(libLen+sizeof(SIG_SUFFIX));
-    char *ext;
+    const char *ext;
 
     if (sigFile == NULL) {
 	return NULL;
@@ -186,12 +187,11 @@
     if (wrc != ERROR_SUCCESS) {
 	return HRESULT_FROM_WIN32(wrc);
     }
-    RegDeleteKey(provKey, PROVIDER_NAME);
+    RegDeleteKey(provKey, providerName);
     RegCloseKey(provKey);
     return S_OK;
 }
 
-
 STDAPI
 DllRegisterServer(void)
 {
@@ -210,7 +210,7 @@
     if (wrc != ERROR_SUCCESS) {
 	goto loser;
     }
-    wrc = RegCreateKeyEx(provKey, PROVIDER_NAME, 0, NULL,
+    wrc = RegCreateKeyEx(provKey, providerName, 0, NULL,
 			  REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, 
 			  &cspKey, &disp);
     if (wrc != ERROR_SUCCESS) {
@@ -253,26 +253,14 @@
     if (wrc != ERROR_SUCCESS) {
 	goto loser;
     }
-    wrc = getSignature(cspLibrary, &signature, &signatureLen);
-    if (wrc != ERROR_SUCCESS) {
-	goto loser;
-    }
-    wrc = RegSetValueEx(cspKey, SIG_KEY, 0, REG_BINARY, 
-			signature, signatureLen);
-    if (wrc != ERROR_SUCCESS) {
-	goto loser;
-    }
 loser:
-    if (signature) {
-	free(signature);
-    }
     if (cspLibrary) {
 	free(cspLibrary);
     }
     if (cspKey) {
 	RegCloseKey(cspKey);
 	if (wrc != ERROR_SUCCESS) {
-	    RegDeleteKey(provKey, PROVIDER_NAME);
+	    RegDeleteKey(provKey, providerName);
 	}
     }
     if (provKey) {
--- ./src/windows/csp.single.dll/,cspx.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp.single.dll/cspx.cpp	Thu Jan 22 08:52:11 2009
@@ -53,12 +53,14 @@
    struct tm* time_s = localtime(&t);
 
    char timestr[32];
-   sprintf(timestr, "%.2d/%.2d %.2d:%.2d:%.2d ", 
+   sprintf(timestr, "%.2d/%.2d %.2d:%.2d:%.2d [%.4X] ", 
                   time_s->tm_mon+1, 
                   time_s->tm_mday, 
                   time_s->tm_hour, 
                   time_s->tm_min, 
-                  time_s->tm_sec);
+                  time_s->tm_sec,
+                  GetProcessId(GetCurrentProcess()));
+
 
    out << timestr;
 
@@ -66,7 +68,7 @@
    for (size_t i = 0; msg[i] != 0x00; i++)
    {
       if (last == '\n')
-         out << "               ";
+         out << "                      ";
 
       if (msg[i] == '\n' && last != '\r')
          out << '\r';
@@ -93,18 +95,23 @@
 ///////////////////////////////////////////////////////////////////////////////
 void flogf(const char* msg0, ...)
 {
-   if (!g_state.logging())
-      return;
+ // DEE will log all the time for testing
+ //  if (!g_state.logging())
+ //    return;
 
    // Preserve error state
    DWORD lastErr = GetLastError();
 
-   FILE* fp = fopen("C:\\CSPDEBUG.log", "ab");
+   FILE* fp = fopen(g_state.logFilename().c_str(), "ab");
 
    if (!fp)
    {
       fp = stderr;
-      fprintf(fp, "ERROR: no log file");
+      if (!fp)  /* if running as login CSP, no stderr... */
+      {
+          SetLastError(lastErr);
+          return;
+      }
    }
 
    string msg1 = clean_flogf(msg0);
@@ -131,12 +138,16 @@
 //  hexMode - (optional) If hexMode is on then the return string will be hex
 //            characters.  Otherwise it returns a string of printable
 //            characters (unprintable characters are converted to '.').
+//            if hexMode is off dont convert trailing '\0' to . 
 //
 // Returns:
 //  string of hex data or printable characters
 ///////////////////////////////////////////////////////////////////////////////
 string StringifyBin(const BinStr& data, bool hexMode)
 {
+//   if (hexMode == FALSE && (LPBYTE)&data[data.size() - 1] == '\0')
+//    return StringifyBin((LPBYTE)&data[0], data.size() - 1 , hexMode);
+//   else
    return StringifyBin((LPBYTE)&data[0], data.size(), hexMode);
 }
 
@@ -503,6 +514,7 @@
                                     IN OUT LPDWORD pcbDataLen)
 {
    LOG("GetProvParam_PP_ENUMCONTAINERS called\n");
+   LOG("dwFlags=%d pbData=%p pcbDataLen=%d\n",dwFlags, pbData, *pcbDataLen);
 
    if (dwFlags & CRYPT_FIRST)
    {
@@ -553,9 +565,22 @@
 
    if (context->containerItr_ == context->containers_.end())
       Throw(ERROR_NO_MORE_ITEMS);
+
+   {
+     /* we need to return a container name. i.e. "\\.\reader\container" */
+     /* We should actually have card id in the container too... */
+	
+
+	std::string  fullcontainer = "\\\\.\\";
+
+    fullcontainer.append((const char *)&context->readerName_[0], context->readerName_.size() -1);
+    fullcontainer.append("\\");
+	fullcontainer.append((const char *)&(*context->containerItr_)[0], (*(context->containerItr_)).size() -1);  
+    LOG("DEE returning %s\n", fullcontainer.c_str());
    
-   PutDataIntoBuffer(pbData, pcbDataLen, &(*context->containerItr_)[0], 
-         context->containerItr_->size());
+     PutDataIntoBuffer(pbData, pcbDataLen, (LPBYTE)fullcontainer.data(), 
+         fullcontainer.size());
+   }
 
    if (pbData)
       context->containerItr_++;
@@ -732,6 +757,7 @@
 
    g_state.p11->C_FindObjectsFinal(context->p11_);
    
+   LOG("%s 0x%X %p\n", __FUNCTION__, GetLastError(), *phCert);
    if (*phCert)
       return true;
    else 
--- ./src/windows/csp.single.dll/,State.h	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp.single.dll/State.h	Fri Jan 23 14:47:51 2009
@@ -49,6 +49,7 @@
 
 public:
    CK_FUNCTION_LIST_PTR p11;
+   HMODULE p11lib; 
 
 public:
    State();
@@ -103,7 +104,9 @@
 
    void login(Session* session);
 
-   bool shutdown();
+   void startup();
+
+   bool shutdown(int why);
 
    void lock()
       { ::WaitForSingleObject(lock_, INFINITE); }
--- ./src/windows/csp.single.dll/,State.cpp	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp.single.dll/State.cpp	Fri Jan 23 16:08:18 2009
@@ -35,15 +35,25 @@
 namespace MCSP {
 
 State::State()
-   : init_(false), logging_(false), logFilename_("C:\\CSPDEBUG.log"), slot_(0), keyGenHack_(false), pkcs11dllname_("PKCS11.dll"),
+   : init_(false), logging_(false), logFilename_("C:\\CSPDEBUG.log.txt"), slot_(0), keyGenHack_(false), pkcs11dllname_("PKCS11.dll"),
+     p11lib(NULL),
      p11_(CK_INVALID_HANDLE)
 {
    lock_ = ::CreateMutex(NULL, FALSE, NULL); 
+}
 
+void State::startup()
+{
    HKEY hKey = NULL;
+    char regpath[MAX_PATH] = {""};
+
+	strcpy(regpath,"SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\");
+    strcat(regpath,providerName);
+
+LOG("DEE regpath=%s\n",regpath);
 
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                    TEXT("SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\"PROVIDER_NAME),
+                    TEXT(regpath),
                     0,
                     KEY_READ,
                     &hKey) == ERROR_SUCCESS)
@@ -60,7 +70,7 @@
       size = 0;
       if (RegQueryValueEx(hKey, TEXT("LogFilename"), 0, 0, 0, &size) == ERROR_SUCCESS)
       {
-         LOG("LogFilename size is: %u\n", size);
+         /* Can not log, until file name is set */ 
          std::string value;
          value.resize(size);
 
@@ -101,7 +111,7 @@
 
 State::~State()
 {
-   shutdown();
+   shutdown(0);
    ::CloseHandle(lock_);
 }
 
@@ -124,6 +134,7 @@
    sessions_.erase(session); 
    delete session; 
    unlock();
+   shutdown(1); /* if no more sessions unload p11lib */
 }
 
 Session* State::checkValidSession(HCRYPTPROV hProv)
@@ -196,13 +207,16 @@
 }
 
 
-bool State::shutdown()
+bool State::shutdown(int why)
 {
+
+   if (why == 0 || sessions_.empty()) /* if detach process or last session close */
+   {
    if (init())
    {
       lock();
 
-      LOG("Shutting down CSP\n");
+      LOG("Shutting down CSP why=%d\n",why);
       
       { 
          set<Session*>::iterator itr = sessions_.begin();
@@ -231,9 +245,18 @@
 
       g_state.p11->C_Finalize(0);
       init(false);
+      LOG("Called C_Finalize\n");
+
+      if (why == 1 && p11lib)
+      {
+         LOG("FreeLibrary p11lib\n");
+         FreeLibrary(p11lib);
+         p11lib = NULL;
+      }
 
       unlock();
    }
+   }
 
    return true;
 }
@@ -253,7 +276,7 @@
 
    try
    {
-      HMODULE p11lib = LoadLibrary(pkcs11dllname_.c_str());
+      p11lib = LoadLibrary(pkcs11dllname_.c_str());
       if (p11lib == NULL)
       {
          LOG("Failed to load PKCS11 library \"%s\"\n", pkcs11dllname_.c_str());
--- ./src/windows/csp.single.dll/,csp.h	Mon Apr 30 18:30:58 2007
+++ ./src/windows/csp.single.dll/csp.h	Fri Jan 23 14:44:45 2009
@@ -35,9 +35,9 @@
 #undef UNICODE
 
 #ifndef CSP_PASSTHROUGH
-#define PROVIDER_NAME "CoolKey PKCS #11 CSP"
+#define PROVIDER_NAME_COOLKEY "CoolKey PKCS #11 CSP"
 #else
-#define PROVIDER_NAME "CoolKey PKCS #11 CSP - Passthrough"
+#define PROVIDER_NAME_COOLKEY "CoolKey PKCS #11 CSP - Passthrough"
 #endif
 
 #define PROVIDER_TYPE PROV_RSA_FULL
@@ -48,8 +48,9 @@
 
 // Logging macros
 #define LOG flogf
-#define BEGIN_API_CALL LOG("+%s() - called\n", __FUNCTION__)
-#define END_API_CALL LOG(" -%s() - finished: %s (0x%X)\n", __FUNCTION__, rv ? "TRUE" : "FALSE", GetLastError());
+#define BEGIN_API_CALL LOG("++++%s() - called hProv: 0x%X\n", __FUNCTION__, hProv)
+#define BEGIN_API_CALL_ACQUIRE LOG("+%s() - called\n", __FUNCTION__)
+#define END_API_CALL LOG("----%s() - finished: %s (0x%X)\n\n", __FUNCTION__, rv ? "TRUE" : "FALSE", GetLastError());
 
 #include <windows.h>
 #include <wincrypt.h>
@@ -63,6 +64,7 @@
 #include "State.h"
 
 extern "C" HINSTANCE g_hModule;
+extern "C" char * providerName;
 
 namespace MCSP {
 
--- ./src/windows/csp.single.dll/,Session.cpp	Thu Jul 27 17:23:07 2006
+++ ./src/windows/csp.single.dll/Session.cpp	Fri Jan 23 14:20:53 2009
@@ -43,9 +43,9 @@
       BinStr uuid0;
       GenUUID(&uuid0);
 
-      size_t provNameLen = strlen(PROVIDER_NAME);
+      size_t provNameLen = strlen(providerName);
       cryptProvUUID_.resize(provNameLen);
-      memcpy(&cryptProvUUID_[0], PROVIDER_NAME, provNameLen);
+      memcpy(&cryptProvUUID_[0], providerName, provNameLen);
       cryptProvUUID_.push_back('_'); cryptProvUUID_.push_back('_');
       cryptProvUUID_.resize(cryptProvUUID_.size() + uuid0.size());
       memcpy(&cryptProvUUID_[provNameLen+2], &uuid0[0], uuid0.size());
@@ -81,7 +81,9 @@
 void Session::parseFQCN(const char* fqcn0, BinStr* container_name, BinStr* reader_name)
 {
    container_name->clear();
+   container_name->push_back(0); /* make sure we have a string */
    reader_name->clear();
+   reader_name->push_back(0);
 
    if (fqcn0 == 0 || fqcn0[0] == 0)
    {
--- ./src/windows/csp.single.dll/,csp.rc	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp.single.dll/csp.rc	Fri Jan 23 17:26:57 2009
@@ -90,8 +90,8 @@
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,1,0,10
- PRODUCTVERSION 1,1,0,10
+ FILEVERSION 1,1,0,1099
+ PRODUCTVERSION 1,1,0,1099
  FILEFLAGSMASK 0x17L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -108,10 +108,10 @@
         BEGIN
             VALUE "CompanyName", "Identity Alliance"
             VALUE "FileDescription", "Identity Alliance Cryptographic Service Provider"
-            VALUE "FileVersion", "1, 1, 0, 10"
+            VALUE "FileVersion", "1, 1, 0, 1099"
             VALUE "InternalName", "CLKCSP"
             VALUE "LegalCopyright", "Copyright © 2003-2005 Identity Alliance"
-            VALUE "ProductVersion", "1, 1, 0, 10"
+            VALUE "ProductVersion", "1, 1, 0, 1099"
         END
     END
     BLOCK "VarFileInfo"
--- ./src/windows/csp.single.dll/,gui.cpp	Wed Oct 11 13:12:58 2006
+++ ./src/windows/csp.single.dll/gui.cpp	Fri Jan 23 15:09:38 2009
@@ -187,7 +187,7 @@
 void DisplayError(const Session* context, const string& str)
 {
    if (!context->silent_)
-      MessageBox(NULL, str.c_str(), PROVIDER_NAME" Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+      MessageBox(NULL, str.c_str(), providerName, MB_OK | MB_ICONERROR | MB_TASKMODAL);
 
    LOG("ERROR: \"%s\"\n", str.c_str());
 }
@@ -209,7 +209,7 @@
    
    // Display the string
    if (!context->silent_)
-      MessageBox(NULL, (LPCSTR)lpMsgBuf, PROVIDER_NAME" Win32 Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);
+      MessageBox(NULL, (LPCSTR)lpMsgBuf, providerName, MB_OK | MB_ICONERROR | MB_TASKMODAL);
 
    LOG("WIN32 error: \"%s\"\n", lpMsgBuf);
    
_______________________________________________
Coolkey-devel mailing list
Coolkey-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/coolkey-devel

[Index of Archives]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Women]

  Powered by Linux