//+-------------------------------------------------------------------------- // // Copyright (c) 1997-1999 Microsoft Corporation // // File: pid.cpp // // Contents: Generate/save/retrieve license server ID to LSA // // History: // //--------------------------------------------------------------------------- #include "pch.cpp" #include "pid.h" #include "gencert.h" #include "certutil.h" ////////////////////////////////////////////////////////////////// DWORD ServerIdsToLsaServerId( IN PBYTE pbServerUniqueId, IN DWORD cbServerUniqueId, IN PBYTE pbServerPid, IN DWORD cbServerPid, IN PBYTE pbServerSPK, IN DWORD cbServerSPK, IN PCERT_EXTENSION pCertExtensions, IN DWORD dwNumCertExtensions, OUT PTLSLSASERVERID* ppLsaServerId, OUT DWORD* pdwLsaServerId ) /*++ Abstract: Combine list of License Server ID to TLSLSASERVERID structure suitable to be saved with LSA. Parameters: pbServerUniqueId : License Server Unique ID. cbServerUniqueId : size of License Server Unique Id in bytes. pbServerPid : License Server's PID cbServerPid : size of License Server's PID in bytes pbServerSPK : License Server's SPK. cbServerSPK : size of License Server's SPK in bytes. pdwLsaServerId : Pointer to DWORD to receive size of TLSLSASERVERID. pLsaServerId : PPointer to TLSLSASERVERID Returns: Note: Internal Routine. --*/ { DWORD dwStatus = ERROR_SUCCESS; DWORD dwOffset = offsetof(TLSLSASERVERID, pbVariableStart); PBYTE pbEncodedExt = NULL; DWORD cbEncodedExt = 0; CERT_EXTENSIONS cert_extensions; if( pbServerSPK != NULL && cbServerSPK != 0 && pCertExtensions != NULL && dwNumCertExtensions != 0 ) { cert_extensions.cExtension = dwNumCertExtensions; cert_extensions.rgExtension = pCertExtensions; // // encode cert. extension // dwStatus = TLSCryptEncodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_CERT_EXTENSIONS, &cert_extensions, &pbEncodedExt, &cbEncodedExt ); if(dwStatus != ERROR_SUCCESS) { return dwStatus; } } *pdwLsaServerId = sizeof(TLSLSASERVERID) + cbServerUniqueId + cbServerPid + cbServerSPK + cbEncodedExt; *ppLsaServerId = (PTLSLSASERVERID)AllocateMemory(*pdwLsaServerId); if(*ppLsaServerId != NULL) { (*ppLsaServerId)->dwVersion = TLSERVER_SERVER_ID_VERSION; (*ppLsaServerId)->dwUniqueId = 0; (*ppLsaServerId)->dwServerPid = 0; (*ppLsaServerId)->dwServerSPK = 0; (*ppLsaServerId)->dwExtensions = 0; if(pbServerUniqueId && cbServerUniqueId) { (*ppLsaServerId)->dwUniqueId = cbServerUniqueId; memcpy( (PBYTE)(*ppLsaServerId) + dwOffset, pbServerUniqueId, cbServerUniqueId ); } if(pbServerPid && cbServerPid) { (*ppLsaServerId)->dwServerPid = cbServerPid; memcpy( (PBYTE)(*ppLsaServerId) + dwOffset + cbServerUniqueId, pbServerPid, cbServerPid ); } if(pbServerSPK && cbServerSPK) { (*ppLsaServerId)->dwServerSPK = cbServerSPK; memcpy( (PBYTE)(*ppLsaServerId) + dwOffset + cbServerUniqueId + cbServerPid, pbServerSPK, cbServerSPK ); } if(pbEncodedExt && cbEncodedExt) { (*ppLsaServerId)->dwExtensions = cbEncodedExt; memcpy( (PBYTE)(*ppLsaServerId) + dwOffset + cbServerUniqueId + cbServerPid + cbServerSPK, pbEncodedExt, cbEncodedExt ); } } else { dwStatus = GetLastError(); } FreeMemory(pbEncodedExt); return dwStatus; } ////////////////////////////////////////////////////////////////// DWORD LsaServerIdToServerIds( IN PTLSLSASERVERID pLsaServerId, IN DWORD dwLsaServerId, OUT PBYTE* ppbServerUniqueId, OUT PDWORD pcbServerUniqueId, OUT PBYTE* ppbServerPid, OUT PDWORD pcbServerPid, OUT PBYTE* ppbServerSPK, OUT PDWORD pcbServerSPK, OUT PCERT_EXTENSIONS* pCertExtensions, OUT PDWORD pcbCertExtensions ) /*++ Abstract: Reverse of ServerIdsToLsaServerId() --*/ { DWORD dwStatus = ERROR_SUCCESS; DWORD dwSize = 0; PBYTE pbUniqueId = NULL; PBYTE pbPid = NULL; PBYTE pbSPK = NULL; DWORD dwOffset = offsetof(TLSLSASERVERID, pbVariableStart); DWORD cbCertExt = 0; PCERT_EXTENSIONS pCertExt = NULL; // // verify input. // if(dwLsaServerId == 0 || pLsaServerId == NULL) { dwStatus = ERROR_INVALID_PARAMETER; goto cleanup; } if(pLsaServerId->dwVersion != TLSERVER_SERVER_ID_VERSION) { TLSLogErrorEvent(TLS_E_INCOMPATIBLELSAVERSION); goto cleanup; } dwSize = sizeof(TLSLSASERVERID) + pLsaServerId->dwUniqueId + pLsaServerId->dwServerPid + pLsaServerId->dwServerSPK + pLsaServerId->dwExtensions; if(dwSize != dwLsaServerId) { dwStatus = ERROR_INVALID_PARAMETER; goto cleanup; } if(pLsaServerId->dwVersion != TLSERVER_SERVER_ID_VERSION) { dwStatus = ERROR_INVALID_PARAMETER; goto cleanup; } *pcbServerUniqueId = pLsaServerId->dwUniqueId; *pcbServerPid = pLsaServerId->dwServerPid; *pcbServerSPK = pLsaServerId->dwServerSPK; if(pLsaServerId->dwUniqueId != 0) { pbUniqueId = (PBYTE)AllocateMemory(pLsaServerId->dwUniqueId); if(pbUniqueId == NULL) { dwStatus = GetLastError(); goto cleanup; } } if(pLsaServerId->dwServerPid != 0) { pbPid = (PBYTE)AllocateMemory(pLsaServerId->dwServerPid); if(pbPid == NULL) { dwStatus = GetLastError(); goto cleanup; } } if(pLsaServerId->dwServerSPK != 0) { pbSPK = (PBYTE)AllocateMemory(pLsaServerId->dwServerSPK); if(pbSPK == NULL) { dwStatus = GetLastError(); goto cleanup; } } if(pLsaServerId->dwUniqueId) { memcpy( pbUniqueId, (PBYTE)pLsaServerId + dwOffset, pLsaServerId->dwUniqueId ); } if(pLsaServerId->dwServerPid) { memcpy( pbPid, (PBYTE)pLsaServerId + dwOffset + pLsaServerId->dwUniqueId, pLsaServerId->dwServerPid ); } if(pLsaServerId->dwServerSPK) { memcpy( pbSPK, (PBYTE)pLsaServerId + dwOffset + pLsaServerId->dwUniqueId + pLsaServerId->dwServerPid, pLsaServerId->dwServerSPK ); } if(pLsaServerId->dwExtensions) { PBYTE pbEncodedCert; DWORD cbEncodedCert; pbEncodedCert = (PBYTE)pLsaServerId + dwOffset + pLsaServerId->dwUniqueId + pLsaServerId->dwServerPid + pLsaServerId->dwServerSPK; cbEncodedCert = pLsaServerId->dwExtensions; dwStatus = LSCryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_CERT_EXTENSIONS, pbEncodedCert, cbEncodedCert, 0, (VOID **)&pCertExt, &cbCertExt ); } cleanup: if(dwStatus != ERROR_SUCCESS) { FreeMemory(pCertExt); FreeMemory(pbUniqueId); FreeMemory(pbPid); FreeMemory(pbSPK); } else { *pCertExtensions = pCertExt; *pcbCertExtensions = cbCertExt; *ppbServerUniqueId = pbUniqueId; *ppbServerPid = pbPid; *ppbServerSPK = pbSPK; } return dwStatus; } ////////////////////////////////////////////////////////////////// DWORD LoadNtPidFromRegistry( OUT LPTSTR* ppszNtPid ) /*++ Abstract: Load the NT Product ID from registry key. Parameters: pdwNtPidSize : Pointer to DWORD to receive size of data return. ppbNtPid : Pointer to PBYTE to receive return data pointer. Return: Note: use AllocateMemory() macro to allocate memory. --*/ { DWORD dwPidSize=0; HKEY hKey = NULL; DWORD dwStatus = ERROR_SUCCESS; if(ppszNtPid == NULL) { SetLastError(dwStatus = ERROR_INVALID_PARAMETER); goto cleanup; } *ppszNtPid = NULL; dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, NTPID_REGISTRY, 0, KEY_READ, // read only &hKey ); if(dwStatus != ERROR_SUCCESS) { // // If this registry key does not exist, // invalid NT installation, if we can't access it, // we are in big trouble. // goto cleanup; } dwStatus = RegQueryValueEx( hKey, NTPID_VALUE, NULL, NULL, NULL, &dwPidSize ); if(dwStatus != ERROR_MORE_DATA && dwStatus != ERROR_SUCCESS) { // Big trouble. goto cleanup; } *ppszNtPid = (LPTSTR)AllocateMemory(dwPidSize + sizeof(TCHAR)); if(*ppszNtPid == NULL) { dwStatus = GetLastError(); goto cleanup; } dwStatus = RegQueryValueEx( hKey, NTPID_VALUE, NULL, NULL, (PBYTE)*ppszNtPid, &dwPidSize ); cleanup: if(hKey != NULL) { RegCloseKey(hKey); } if(dwStatus != NULL) { FreeMemory(*ppszNtPid); } return dwStatus; } ////////////////////////////////////////////////////////////////// DWORD GenerateRandomNumber( IN DWORD Seed ) /*++ Routine Description: Generate a random number. Arguments: Seed - Seed for random-number generator. Return Value: Returns a random number. --*/ { ULONG ulSeed = Seed; // Randomize the seed some more ulSeed = RtlRandomEx(&ulSeed); return RtlRandomEx(&ulSeed); } ////////////////////////////////////////////////////////////////// DWORD TLSGeneratePid( OUT LPTSTR* pszTlsPid, OUT PDWORD pcbTlsPid, OUT LPTSTR* pszTlsUniqueId, OUT PDWORD pcbTlsUniqueId ) /*++ Abstract: Generate a PID for License Server, License Server PID is composed of NT PID (from registry) with last 5 digit being randomly generated number. Parameter: ppbTlsPid : Pointer to PBYTE that receive the License Server PID. pcbTlsPid : Pointer to DWORD to receive size of License Server PID. ppbTlsUniqueId : Pointer to PBYTE to receive the License Server Unique Id. pcbTlsUniqueId : Pointer to DWORD to receive size of License Server's unique ID. Returns: Error code if can't access NT system PID. Note: refer to PID20 format for detail, License Server treat PID as binary data. --*/ { DWORD dwStatus; DWORD dwRandomNumber; DWORD dwNtPid; LPTSTR pszNtPid = NULL; LPTSTR pszPid20Random = NULL; int index; DWORD dwMod = 1; if( pszTlsPid == NULL || pcbTlsPid == NULL || pszTlsUniqueId == NULL || pcbTlsUniqueId == NULL ) { dwStatus = ERROR_INVALID_PARAMETER; goto cleanup; } // // Load NT system PID // dwStatus = LoadNtPidFromRegistry( &pszNtPid ); if(dwStatus != ERROR_SUCCESS) { goto cleanup; } pszPid20Random = (LPTSTR)AllocateMemory( (TLSUNIQUEID_SIZE + 1) * sizeof(TCHAR) ); if(pszPid20Random == NULL) { dwStatus = GetLastError(); goto cleanup; } for(index = 0; index < TLSUNIQUEID_SIZE; index++) { dwMod *= 10; } dwRandomNumber = GenerateRandomNumber( GetCurrentThreadId() + GetTickCount() ); swprintf( pszPid20Random, _TEXT("%0*u"), TLSUNIQUEID_SIZE, dwRandomNumber % dwMod ); // // overwrite last 5 digit // lstrcpy( pszNtPid + (lstrlen(pszNtPid) - TLSUNIQUEID_SIZE), pszPid20Random ); *pszTlsPid = pszNtPid; *pcbTlsPid = (lstrlen(pszNtPid) + 1) * sizeof(TCHAR); *pszTlsUniqueId = pszPid20Random; *pcbTlsUniqueId = (lstrlen(pszPid20Random) + 1) * sizeof(TCHAR); cleanup: if(dwStatus != ERROR_SUCCESS) { FreeMemory(pszNtPid); FreeMemory(pszPid20Random); } return dwStatus; }