/*-------------------------------------------------------------- * * FILE: SK_DLL.C * * PURPOSE: The file contains the Functions responsible for * managing information passed between SerialKeys * and the SerialKeys DLL * * CREATION: June 1994 * * COPYRIGHT: Black Diamond Software (C) 1994 * * AUTHOR: Ronald Moak * * NOTES: * * This file, and all others associated with it contains trade secrets * and information that is proprietary to Black Diamond Software. * It may not be copied copied or distributed to any person or firm * without the express written permission of Black Diamond Software. * This permission is available only in the form of a Software Source * License Agreement. * * $Header: %Z% %F% %H% %T% %I% * *--- Includes ---------------------------------------------------------*/ #include #include "windows.h" #include "w95trace.h" #include "sk_defs.h" #include "sk_reg.h" #include "sk_dll.h" #include "sk_dllif.h" #include #ifdef DEBUG void dbg_Output(LPSTR Header) { DBPRINTF(Header); DBPRINTF(TEXT("-- dwFlags (%d) iBaudRate (%d) Save (%d) iPortState (%d)\r\n"), SKeyDLL.dwFlags,SKeyDLL.iBaudRate,SKeyDLL.iSave,SKeyDLL.iPortState); DBPRINTF(TEXT("-- ActivePort (%s) Port (%s)\r\n"),SKeyDLL.szActivePort,SKeyDLL.szPort); } #define DBG_DUMP(Header) dbg_Output(Header) #else #define DBG_DUMP(Header) #endif // Defines -------------------------------------------------- // Local Function Prototypes --------------------------------- static void CleanUpDLL(); static void GetCurrentValues(); static void GetNewValues(); static void ProcessDLL(); static BOOL ReadDLL(); static void __cdecl ServiceDLL(VOID *notUsed); static BOOL WriteDLL(); // Local Variables -------------------------------------------------- static OVERLAPPED OverLapRd; // Overlapped structure for reading. static SKEYDLL SKeyDLL; // Input buffer for pipe. static BOOL fExitDLL; // Set Exit Flag static BOOL fDoneDLL = TRUE; static HANDLE hPipeDLL; static HANDLE hThreadDLL; /*--------------------------------------------------------------- * * Global Functions * /*--------------------------------------------------------------- * * FUNCTION BOOL DoneDLL() * * TYPE Global * * PURPOSE Returns the state of the DLL Thread * * INPUTS None * * RETURNS TRUE - DLL Thread not running * FALSE - DLL Thread Is running * *---------------------------------------------------------------*/ BOOL DoneDLL() { return(fDoneDLL); } //----------------------------------------------------------------------------- // CreateSd // // Creates a SECURITY_DESCRIPTOR with an authenticated user DACL and the // rights specified by ulRights. // // Caller must call free() on the returned buffer if not NULL. // PSECURITY_DESCRIPTOR CreateSd(unsigned long ulRights) { PSECURITY_DESCRIPTOR pSd = NULL; PSID psidAuthentUser; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; // Make a SID for a local administrator if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAuthentUser)) { // Calculate the size of and allocate a buffer for the DACL, we need // this value independently of the total alloc size for ACL init. ULONG cbAclSize = sizeof (ACL) + (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG)) + GetLengthSid(psidAuthentUser); pSd = malloc(SECURITY_DESCRIPTOR_MIN_LENGTH + cbAclSize); if (pSd) { ACL *pAcl = (ACL *)((BYTE *)pSd + SECURITY_DESCRIPTOR_MIN_LENGTH); if ( !InitializeAcl(pAcl, cbAclSize, ACL_REVISION) || !AddAccessAllowedAce(pAcl, ACL_REVISION, ulRights, psidAuthentUser) || !InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION) || !SetSecurityDescriptorDacl(pSd, TRUE, pAcl, FALSE)) { free(pSd); // error! pSd = NULL; } } FreeSid(psidAuthentUser); } return pSd; } /*--------------------------------------------------------------- * * FUNCTION BOOL InitDLL() * * TYPE Global * * PURPOSE This function creates a thread that monitors when an * application uses the DLL to Get or Set the state * of Serial Keys. * * INPUTS None * * RETURNS TRUE - Init ok & Thread installed * FALSE- Thread failed * *---------------------------------------------------------------*/ BOOL InitDLL() { DWORD Id; PSECURITY_DESCRIPTOR pSD; SECURITY_ATTRIBUTES sa; DBPRINTF(TEXT("InitDLL()\r\n")); hPipeDLL = INVALID_HANDLE_VALUE; hThreadDLL = NULL; fExitDLL = FALSE; pSD = CreateSd(FILE_CREATE_PIPE_INSTANCE|GENERIC_READ|GENERIC_WRITE); if (!pSD) return(FALSE); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = pSD; hPipeDLL = CreateNamedPipe( SKEY_NAME, // Pipe name PIPE_ACCESS_DUPLEX, // 2 way pipe. PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, // Maximum instance limit. 0, // Buffer sizes. 0, 1000 * 30, // Specify time out. &sa); // Default securities specified. free(pSD); if (INVALID_HANDLE_VALUE == hPipeDLL) { hPipeDLL = NULL; DBPRINTF(TEXT("Unable to Create DLL Named Pipe\r\n")); return FALSE; } fDoneDLL = FALSE; // Clear Thread Done Flag // Generate thread to handle DLL processing; hThreadDLL = (HANDLE)CreateThread( // Start Service Thread 0, 0, (LPTHREAD_START_ROUTINE) ServiceDLL, 0,0,&Id); // argument to thread if (NULL == hThreadDLL) { DBPRINTF(TEXT("Unable to Create DLL Thread\r\n")); CleanUpDLL(); return FALSE; } return(TRUE); } /*--------------------------------------------------------------- * * FUNCTION void SuspendDLL() * * TYPE Global * * PURPOSE The function is called to Pause the thread * reading and processing data coming from the comm port. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void SuspendDLL() { if (NULL != hThreadDLL) { SuspendThread(hThreadDLL); } } /*--------------------------------------------------------------- * * FUNCTION void ResumeDLL() * * TYPE Global * * PURPOSE The function is called to resume the Paused thread. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void ResumeDLL() { if (NULL != hThreadDLL) { ResumeThread(hThreadDLL); } } /*--------------------------------------------------------------- * * FUNCTION void TerminateDLL() * * TYPE Global * * PURPOSE This function is called to Terminate the DLL Process * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void TerminateDLL() { DWORD bytesRead; DBPRINTF(TEXT("TerminateDLL()\r\n")); if (fDoneDLL) return; fExitDLL = TRUE; // Set Exit Flag CallNamedPipe // Trigger the DLL to Shutdown ( SKEY_NAME, // Pipe name &SKeyDLL, sizeof(SKeyDLL), &SKeyDLL, sizeof(SKeyDLL), &bytesRead, NMPWAIT_NOWAIT ); } /*--------------------------------------------------------------- * * Local Functions * /*--------------------------------------------------------------- * * FUNCTION static void CleanUpDLL() * * TYPE Local * * PURPOSE This function cleans up file handles and misc stuff * when the thread is terminated. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void CleanUpDLL() { BOOL Stat; DBPRINTF(TEXT("CleanUpDLL()\r\n")); // Close Pipe Handle if (NULL != hPipeDLL) { Stat = CloseHandle(hPipeDLL); DBPRINTF_IF(Stat,TEXT("Unable to Close DLL Pipe\r\n")); } // Close Thread Handle if (NULL != hThreadDLL) { Stat = CloseHandle(hThreadDLL); DBPRINTF_IF(Stat,TEXT("Unable to Close DLL Thread\r\n")); } hPipeDLL = NULL; hThreadDLL = NULL; fDoneDLL = TRUE; // Set Thread Done Flag DBPRINTF(TEXT("DLL Service Processing Done\r\n")); } /*--------------------------------------------------------------- * * FUNCTION void _CRTAPI1 ServiceDLL() * * TYPE Local * * PURPOSE This function is a thread that monitors when an * application uses the DLL to Get or Set the state * of Serial Keys. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void __cdecl ServiceDLL(VOID *notUsed) { DWORD retCode; DWORD bytesRead; DWORD bytesWritten; DBPRINTF(TEXT("SericeDLL()\r\n")); while (TRUE) { if (!ConnectNamedPipe(hPipeDLL,NULL)) { ExitThread(0); return; } if (fExitDLL) // Is the Service Done? { // Yes - Close Down Service CleanUpDLL(); // Close Handles Etc. ExitThread(0); // Exit The Thread return; } retCode = ReadFile( // Read Message hPipeDLL, &SKeyDLL, sizeof(SKeyDLL), &bytesRead, NULL); if (!retCode) // Pipe is Broken Try & reconnect continue; ProcessDLL(); // Yes - Process incoming buffer retCode = WriteFile( // Write Message hPipeDLL, &SKeyDLL, sizeof(SKeyDLL), &bytesWritten, NULL); if (!retCode) // Pipe is Broken Try & reconnect continue; DisconnectNamedPipe(hPipeDLL); } } /*--------------------------------------------------------------- * * FUNCTION void ProcessDLL() * * TYPE Local * * PURPOSE This function process the input buffer received from * the DLL. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void ProcessDLL() { DWORD dwService; DBPRINTF(TEXT("ProcessDLL()\r\n")); dwService = SC_CHANGE_COMM; switch (SKeyDLL.Message) // Validate Message { case SPI_GETSERIALKEYS: if (skCurKey.dwFlags & SERKF_ACTIVE) // Are We Disabled? GetCurrentValues(); // No - Send the actual Values else GetNewValues(); // Yes - Send the Proposed values DBG_DUMP("---Info Sent"); return; case SPI_SETSERIALKEYS: DBG_DUMP("---Info Received"); if ((SKeyDLL.dwFlags & SERKF_SERIALKEYSON) && // Are We Truning on & (SKeyDLL.dwFlags & SERKF_AVAILABLE)) // Is SerialKeys Available { if (!(skCurKey.dwFlags & SERKF_ACTIVE)) // Are We Disabled? { dwService = SC_ENABLE_SKEY; // Yes - Turn SKeys On DBPRINTF(TEXT("Turn Serial Key On\r\n")); } } if (!(SKeyDLL.dwFlags & SERKF_SERIALKEYSON) && // Are We Truning off & (SKeyDLL.dwFlags & SERKF_AVAILABLE)) // Is SerialKeys Available { if (skCurKey.dwFlags & SERKF_ACTIVE) // Are We Active? { dwService = SC_DISABLE_SKEY; // Yes - Turn SKeys Off DBPRINTF(TEXT("Turn Serial Key Off\r\n")); } } skNewKey.iBaudRate = SKeyDLL.iBaudRate; skNewKey.dwFlags = SKeyDLL.dwFlags; // Ensure that the strings we've just read off the named pipe // are NUL-terminated before we use them. // (All port strings are MAX_PATH long - see sk_dllif.h, sk_defs.h) SKeyDLL.szActivePort[ MAX_PATH - 1 ] = '\0'; SKeyDLL.szPort[ MAX_PATH - 1 ] = '\0'; #ifdef UNICODE MultiByteToWideChar( CP_ACP, 0, SKeyDLL.szActivePort, -1, skNewKey.lpszActivePort, MAX_PATH); MultiByteToWideChar( CP_ACP, 0, SKeyDLL.szPort, -1, skNewKey.lpszPort, MAX_PATH); // Just in case either of the above fail (due to insufficient // buffer or other reason), forcibly NUL-terminate. skNewKey.lpszActivePort[ MAX_PATH - 1 ] = '\0'; skNewKey.lpszPort[ MAX_PATH - 1 ] = '\0'; #else lstrcpy(skNewKey.lpszActivePort,SKeyDLL.szActivePort); lstrcpy(skNewKey.lpszPort,SKeyDLL.szPort); #endif if (*skNewKey.lpszPort == 0) { lstrcpy(skNewKey.lpszPort, skNewKey.lpszActivePort); } // the calling dll is now responsible for saving the // settings because it's running in the user context // and can access HKEY_CURRENT_USER. Here we're // running as a service (as the system) and have // no HKEY_CURRENT_USER DoServiceCommand(dwService); Sleep(1000); // Sleep 1 Sec to set values if (SKeyDLL.dwFlags & SERKF_SERIALKEYSON) // Are We Truning on GetCurrentValues(); // Yes - Send the actual Values else GetNewValues(); // No - Send the Proposed values DBG_DUMP("---Info Sent"); break; default: return; } } /*--------------------------------------------------------------- * * FUNCTION void GetCurrentValues() * * TYPE Local * * PURPOSE * * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void GetCurrentValues() { DBPRINTF(TEXT("GetCurrentValues()\r\n")); #ifdef UNICODE WideCharToMultiByte( CP_ACP, 0, skCurKey.lpszActivePort, -1, SKeyDLL.szActivePort, sizeof(SKeyDLL.szActivePort), NULL, NULL); WideCharToMultiByte( CP_ACP, 0, skCurKey.lpszPort, -1, SKeyDLL.szPort, sizeof(SKeyDLL.szPort), NULL, NULL); #else lstrcpy(SKeyDLL.szActivePort,skCurKey.lpszActivePort); lstrcpy(SKeyDLL.szPort,skCurKey.lpszPort); #endif SKeyDLL.dwFlags = skCurKey.dwFlags; SKeyDLL.iBaudRate = skCurKey.iBaudRate; SKeyDLL.iPortState = skCurKey.iPortState; } /*--------------------------------------------------------------- * * FUNCTION void GetNewValues() * * TYPE Local * * PURPOSE * * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void GetNewValues() { DBPRINTF(TEXT("GetNewValues()\r\n")); // FEATURE a-jimhar 04-03-96 this next line is suspect. May need to // change 'skCurKey.dwFlags' to 'skNewKey.dwFlags. This is either // a mistake or was done to always return the current flags. SKeyDLL.dwFlags = skCurKey.dwFlags; SKeyDLL.iBaudRate = skNewKey.iBaudRate; SKeyDLL.iPortState = skNewKey.iPortState; #ifdef UNICODE WideCharToMultiByte( CP_ACP, 0, skNewKey.lpszActivePort, -1, SKeyDLL.szActivePort, sizeof(SKeyDLL.szActivePort), NULL, NULL); WideCharToMultiByte( CP_ACP, 0, skNewKey.lpszPort, -1, SKeyDLL.szPort, sizeof(SKeyDLL.szPort), NULL, NULL); #else lstrcpy(SKeyDLL.szActivePort,skNewKey.lpszActivePort); lstrcpy(SKeyDLL.szPort,skNewKey.lpszPort); #endif }