//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-1998 // // File: db.cpp // // Contents: // all routine deal with cross table query // // History: // Feb 4, 98 HueiWang Created //--------------------------------------------------------------------------- #include "pch.cpp" #include "globals.h" #include "db.h" #include "clilic.h" #include "keypack.h" #include "kp.h" #include "lkpdesc.h" /**************************************************************************** Function: LSDBValidateLicense() Description: Routine to validate license agaist database, must call LSDecodeLicense() to convert hydra license to LICENSEREQUEST structure. Arguments: IN CSQLStmt* - SQL Statement handle to use IN PLICENSEREQUEST - License in the form of LICENSEREQUEST structure IN dwKeyPackId - KeyPack table's ID that is license is issued from IN dwLicenseId - License tables's License ID OUT LPKEYPACK - KeyPack record this license is issued from, NULL if not interested in this value. OUT LPLICENSE - Corresponding license record for this license, NULL if not interest in this value. Returns: ERROR_SUCCESS TLS_E_INVALID_LICENSE TLS_E_INTERNAL ODBC error. ****************************************************************************/ DWORD TLSDBValidateLicense( PTLSDbWorkSpace pDbWkSpace, //IN PBYTE pbLicense, //IN DWORD cbLicense, IN PHWID phWid, IN PLICENSEREQUEST pLicensedProduct, IN DWORD dwKeyPackId, IN DWORD dwLicenseId, OUT PTLSLICENSEPACK lpKeyPack, OUT LPLICENSEDCLIENT lpLicense ) /* */ { DWORD dwStatus=ERROR_SUCCESS; DWORD dwMatchCount=0; if(pDbWkSpace == NULL) { SetLastError(dwStatus = ERROR_INVALID_PARAMETER); TLSASSERT(FALSE); return dwStatus; } TLSLICENSEPACK keypack_search; TLSLICENSEPACK keypack_found; LICENSEDCLIENT license_search; LICENSEDCLIENT license_found; int count=0; BOOL bValid=TRUE; memset(&license_search, 0, sizeof(LICENSEDCLIENT)); keypack_found.pbDomainSid = NULL; license_search.dwLicenseId = dwLicenseId; dwStatus = TLSDBLicenseEnumBegin( pDbWkSpace, TRUE, LSLICENSE_SEARCH_LICENSEID, &license_search ); if(dwStatus != ERROR_SUCCESS) { if(IS_JB_ERROR(dwStatus) != TRUE) { SetLastError(dwStatus = TLS_E_INVALID_LICENSE); } goto cleanup; } do { dwStatus=TLSDBLicenseEnumNext( pDbWkSpace, &license_found ); if(dwStatus != ERROR_SUCCESS) break; count++; } while(count < 1); TLSDBLicenseEnumEnd(pDbWkSpace); if(count != 1) { // can't find the license SetLastError(dwStatus = TLS_E_INVALID_LICENSE); goto cleanup; } if(count > 1) { // more than one entry in database has identical // license id SetLastError(dwStatus = TLS_E_INTERNAL); goto cleanup; } // // Not issue by this license server??? // if(license_found.dwKeyPackId != dwKeyPackId) { SetLastError(dwStatus = TLS_E_INVALID_LICENSE); goto cleanup; } // // new license request might pass different HWID // dwMatchCount += (int)(license_found.dwSystemBiosChkSum == phWid->dwPlatformID); dwMatchCount += (int)(license_found.dwVideoBiosChkSum == phWid->Data1); dwMatchCount += (int)(license_found.dwFloppyBiosChkSum == phWid->Data2); dwMatchCount += (int)(license_found.dwHardDiskSize == phWid->Data3); dwMatchCount += (int)(license_found.dwRamSize == phWid->Data4); if(dwMatchCount < LICENSE_MIN_MATCH) { SetLastError(dwStatus = TLS_E_INVALID_LICENSE); } // // Verify against KeyPack Table // memset(&keypack_search, 0, sizeof(keypack_search)); keypack_search.dwKeyPackId = dwKeyPackId; dwStatus = TLSDBKeyPackFind( pDbWkSpace, TRUE, LSKEYPACK_EXSEARCH_DWINTERNAL, &keypack_search, &keypack_found ); if(dwStatus != ERROR_SUCCESS) { if(IS_JB_ERROR(dwStatus) != TRUE) { SetLastError(dwStatus = TLS_E_INVALID_LICENSE); } goto cleanup; } // match KeyPack's Product ID, Version, Language ID, PlatformID // structure change, no more product version. if(pLicensedProduct->dwPlatformID != keypack_found.dwPlatformType || _tcsicmp((LPTSTR)pLicensedProduct->pProductInfo->pbCompanyName, keypack_found.szCompanyName) || _tcsicmp((LPTSTR)pLicensedProduct->pProductInfo->pbProductID, keypack_found.szProductId) ) { SetLastError(dwStatus = TLS_E_INVALID_LICENSE); } cleanup: //FreeTlsLicensePack(&keypack_found); if(dwStatus == ERROR_SUCCESS) { if(lpKeyPack) { *lpKeyPack = keypack_found; } if(lpLicense) { *lpLicense = license_found; } } return dwStatus; } /************************************************************************* Function: LSDBDeleteLicense() *************************************************************************/ DWORD TLSDBDeleteLicense( PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId, DWORD dwLicenseId ) /* */ { // TODO - license entry base on license id // 1) Return license back to key pack // 2) 'Physically' delete the license. return ERROR_SUCCESS; } /************************************************************************* Function: LSDBRevokeLicense() *************************************************************************/ DWORD TLSDBRevokeLicense( PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPacKId, IN DWORD dwLicenseId ) { // Set License Status to revoked // Return License to KeyPack // call LSDBDeleteKeyPack() and if not successful, insert into RevokeLicenseTable return ERROR_SUCCESS; } /************************************************************************* Function: LSDBReturnLicense() *************************************************************************/ DWORD TLSDBReturnLicense( PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId, IN DWORD dwLicenseId, IN DWORD dwNewLicenseStatus ) /* */ { DWORD dwStatus=ERROR_SUCCESS; DWORD dwQuantity = 1; TLSDBLockKeyPackTable(); TLSDBLockLicenseTable(); // // no verification on record got updated. // LICENSEDCLIENT license; license.dwLicenseId = dwLicenseId; license.ucLicenseStatus = dwNewLicenseStatus; // // use undocumented feature to delete license // DBGPrintf( DBG_INFORMATION, DBG_FACILITY_RETURN, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("Deleting license ID %d issued by keypack %d\n"), license.dwLicenseId, dwKeyPackId ); if (dwNewLicenseStatus == LSLICENSESTATUS_DELETE) { // get number of CALs in this license LICENSEDCLIENT licenseFound; dwStatus = TLSDBLicenseFind( pDbWkSpace, TRUE, LSLICENSE_SEARCH_LICENSEID, &license, &licenseFound ); if(dwStatus == ERROR_SUCCESS) { dwQuantity = licenseFound.dwNumLicenses; } } dwStatus = TLSDBLicenseSetValue( pDbWkSpace, LSLICENSE_EXSEARCH_LICENSESTATUS, &license, FALSE ); if(dwStatus == ERROR_SUCCESS && dwNewLicenseStatus == LSLICENSESTATUS_DELETE) { dwStatus = TLSDBReturnLicenseToKeyPack( pDbWkSpace, dwKeyPackId, dwQuantity ); } TLSDBUnlockLicenseTable(); TLSDBUnlockKeyPackTable(); return dwStatus; } /************************************************************************* Function: LSDBReturnLicenseToKeyPack() *************************************************************************/ DWORD TLSDBReturnLicenseToKeyPack( IN PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId, IN int dwNumLicense ) { DWORD dwStatus = ERROR_SUCCESS; TLSDBLockKeyPackTable(); #ifdef DBG DWORD dwPrevNumLicense=0; #endif TLSLICENSEPACK found; TLSLICENSEPACK search; found.pbDomainSid = NULL; do { // retrieve number of licenses search.dwKeyPackId = dwKeyPackId; dwStatus = TLSDBKeyPackFind( pDbWkSpace, TRUE, LSKEYPACK_EXSEARCH_DWINTERNAL, &search, &found ); if(dwStatus != ERROR_SUCCESS) { if(IS_JB_ERROR(dwStatus) == FALSE) { SetLastError(dwStatus = TLS_E_RECORD_NOTFOUND); } break; } if(search.dwKeyPackId != found.dwKeyPackId) { TLSASSERT(FALSE); } #ifdef DBG dwPrevNumLicense = found.dwNumberOfLicenses; #endif // set the number of licenses issued by 1 switch( (found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE) ) { case LSKEYPACKTYPE_RETAIL: case LSKEYPACKTYPE_CONCURRENT: case LSKEYPACKTYPE_OPEN: case LSKEYPACKTYPE_SELECT: // number of licenses available found.dwNumberOfLicenses += dwNumLicense; break; case LSKEYPACKTYPE_FREE: case LSKEYPACKTYPE_TEMPORARY: // number of license issued if(found.dwNumberOfLicenses > 0) { found.dwNumberOfLicenses -= dwNumLicense; } break; default: SetLastError(dwStatus = TLS_E_CORRUPT_DATABASE); } #ifdef DBG DBGPrintf( DBG_INFORMATION, DBG_FACILITY_RETURN, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("Returning license to keypack %d - from %d to %d\n"), found.dwKeyPackId, dwPrevNumLicense, found.dwNumberOfLicenses ); #endif // // use undocumented feature to delete temp. keypack if( (found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE) == LSKEYPACKTYPE_TEMPORARY && found.dwNumberOfLicenses == 0) { found.ucKeyPackStatus = LSKEYPACKSTATUS_DELETE; // delete keypack desc table LICPACKDESC keyPackDesc; memset(&keyPackDesc, 0, sizeof(LICPACKDESC)); keyPackDesc.dwKeyPackId = found.dwKeyPackId; TLSDBKeyPackDescSetValue( pDbWkSpace, KEYPACKDESC_SET_DELETE_ENTRY, &keyPackDesc ); } dwStatus=TLSDBKeyPackSetValues( pDbWkSpace, TRUE, LSKEYPACK_EXSEARCH_AVAILABLE, &found ); } while(FALSE); //FreeTlsLicensePack(&found); TLSDBUnlockKeyPackTable(); return dwStatus; } /************************************************************************* Function: LSDBRevokeKeyPack() *************************************************************************/ DWORD TLSDBRevokeKeyPack( IN PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId ) { // Set Key Pack Status to Revoke // Insert this key pack into RevokeKeyPackTable ??? return ERROR_SUCCESS; } /************************************************************************* Function: LSDBReturnKeyPack() *************************************************************************/ DWORD TLSDBReturnKeyPack( IN PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId ) { // Same as RevokeKeyPack except status is return // Delete Key pack only when all license has been returned. return ERROR_SUCCESS; } /************************************************************************* Function: LSDBDeleteKeyPack() *************************************************************************/ DWORD TLSDBDeleteKeyPack( PTLSDbWorkSpace pDbWkSpace, IN DWORD dwKeyPackId ) { // Delete Only when all license has been returned. return ERROR_SUCCESS; } //+------------------------------------------------------------------------ // Function: // AllocateLicenses() // // Description: // Allocate license from key Pack // // Arguments: // IN lpSqlStmt - sql statement handle // IN ucKeyPackType - key pack type to allocate license from // IN szCompanyName - Product Company // IN szProductId - Product Name // IN dwVersion - Product Version // IN dwPlatformId - Product PlatformId // IN dwLangId - Product Lanugage Id // IN OUT lpdwNumLicense - number of license to be allocated and on // return, number of licenses actually allocated // IN bufSize - number of interested keypack that has requested license // IN OUT lpAllocationVector - number of license allocated from list of // key pack that has requested licenses. // IN OUT LPKEYPACK - key Pack that license was allocated from // // Returns: // TLS_E_INVALID_DATA Invalid parameter // TLS_I_NO_MORE_DATA No key pack has the requested license // // Notes: // To keep code clean/simple, call ReturnLicenses() for returning // licenses //------------------------------------------------------------------------- DWORD VerifyTLSDBAllocateRequest( IN PTLSDBAllocateRequest pRequest ) /* */ { DWORD dwStatus = ERROR_SUCCESS; UCHAR ucAgreementType; if(pRequest == NULL) { SetLastError(dwStatus = ERROR_INVALID_PARAMETER); goto cleanup; } ucAgreementType = (pRequest->ucAgreementType & ~pRequest->ucAgreementType); if(ucAgreementType < LSKEYPACKTYPE_FIRST || ucAgreementType > LSKEYPACKTYPE_LAST) { DBGPrintf( DBG_ERROR, DBGLEVEL_FUNCTION_DETAILSIMPLE, DBG_ALL_LEVEL, _TEXT("AllocateLicenses() invalid keypack type - %d\n"), pRequest->ucAgreementType ); SetLastError(dwStatus = TLS_E_INVALID_DATA); goto cleanup; } if(pRequest->szCompanyName == NULL || _tcslen(pRequest->szCompanyName) == 0) { DBGPrintf( DBG_ERROR, DBGLEVEL_FUNCTION_DETAILSIMPLE, DBG_ALL_LEVEL, _TEXT("AllocateLicenses() invalid company name\n") ); SetLastError(dwStatus = TLS_E_INVALID_DATA); goto cleanup; } if(pRequest->szProductId == NULL || _tcslen(pRequest->szProductId) == 0) { DBGPrintf( DBG_ERROR, DBGLEVEL_FUNCTION_DETAILSIMPLE, DBG_ALL_LEVEL, _TEXT("AllocateLicenses() invalid product id\n") ); SetLastError(dwStatus = TLS_E_INVALID_DATA); } cleanup: return dwStatus; } //---------------------------------------------------------------------- DWORD AllocateLicensesFromDB( IN PTLSDbWorkSpace pDbWkSpace, IN PTLSDBAllocateRequest pRequest, IN BOOL fCheckAgreementType, IN OUT PTLSDBLicenseAllocation pAllocated ) /* */ { DWORD status=ERROR_SUCCESS; if(pDbWkSpace == NULL || pRequest == NULL || pAllocated == NULL) { DBGPrintf( DBG_ERROR, DBGLEVEL_FUNCTION_DETAILSIMPLE, DBG_ALL_LEVEL, _TEXT("pDbWkSpace is NULL...\n") ); SetLastError(status = ERROR_INVALID_PARAMETER); TLSASSERT(FALSE); return status; } status = VerifyTLSDBAllocateRequest(pRequest); if(status != ERROR_SUCCESS) return status; if(pAllocated->dwBufSize <= 0) { DBGPrintf( DBG_ERROR, DBG_FACILITY_ALLOCATELICENSE, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("AllocateLicenses() invalid return buffer size\n") ); SetLastError(status = TLS_E_INVALID_DATA); return status; } #ifdef DBG DWORD dwPrevNumLicense; #endif BOOL bProductInstalled=FALSE; DWORD bufIndex=0; TLSLICENSEPACK keypack_search; TLSLICENSEPACK keypack_found; DWORD dwNumLicenses = pRequest->dwNumLicenses; // number of license wanted/returned DWORD dwTotalAllocated=0; memset(&keypack_search, 0, sizeof(keypack_search)); memset(&keypack_found, 0, sizeof(keypack_found)); keypack_search.ucAgreementType = pRequest->ucAgreementType; _tcscpy(keypack_search.szCompanyName, pRequest->szCompanyName); _tcscpy(keypack_search.szProductId, pRequest->szProductId); keypack_search.wMajorVersion = HIWORD(pRequest->dwVersion); keypack_search.wMinorVersion = LOWORD(pRequest->dwVersion); keypack_search.dwPlatformType = pRequest->dwPlatformId; LicPackTable& licpack_table=pDbWkSpace->m_LicPackTable; time_t current_time=time(NULL); // // Lock Key Pack table // Only update requires locking, read might get in-correct value. // // // Only allow one thread to enter - Jet not fast enough in updating entry // TLSDBLockKeyPackTable(); status = TLSDBKeyPackEnumBegin( pDbWkSpace, TRUE, LSKEYPACK_SEARCH_PRODUCTID | (fCheckAgreementType ? LICENSEDPACK_FIND_LICENSEPACK : 0), &keypack_search ); if(status != ERROR_SUCCESS) goto cleanup; try { while(status == ERROR_SUCCESS && dwNumLicenses != 0 && bufIndex < pAllocated->dwBufSize) { status = TLSDBKeyPackEnumNext( pDbWkSpace, &keypack_found ); if(status != ERROR_SUCCESS) break; // // Skip remote keypack // if(keypack_found.ucAgreementType & LSKEYPACK_REMOTE_TYPE) { continue; } if(keypack_found.ucKeyPackStatus & LSKEYPACKSTATUS_REMOTE) { continue; } if(fCheckAgreementType && (keypack_found.ucAgreementType != pRequest->ucAgreementType)) { continue; } UCHAR ucKeyPackStatus = keypack_found.ucKeyPackStatus & ~LSKEYPACKSTATUS_RESERVED; // Allocating licenses // // Throw away any key pack that has bad status // one of the reason why can't returning license in this routine // for returning license, we should not care about key pack // status. if(ucKeyPackStatus == LSKEYPACKSTATUS_UNKNOWN || ucKeyPackStatus == LSKEYPACKSTATUS_RETURNED || ucKeyPackStatus == LSKEYPACKSTATUS_REVOKED || ucKeyPackStatus == LSKEYPACKSTATUS_OTHERS) { continue; } // // we find the product, make sure the version is what we want. // bProductInstalled=TRUE; // Expired keypack // TODO - update table here. if((DWORD)keypack_found.dwExpirationDate < current_time) continue; // // never allocate from older version // if( keypack_found.wMajorVersion < HIWORD(pRequest->dwVersion) ) { continue; } // // Same major version but older minor // if( keypack_found.wMajorVersion == HIWORD(pRequest->dwVersion) && keypack_found.wMinorVersion < LOWORD(pRequest->dwVersion) ) { continue; } if(pRequest->dwScheme == ALLOCATE_EXACT_VERSION) { if(keypack_found.wMajorVersion != HIWORD(pRequest->dwVersion) || keypack_found.wMinorVersion < LOWORD(pRequest->dwVersion) ) { continue; } } UCHAR ucAgreementType = (keypack_found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE); // // Verify number of licenses left // if((ucAgreementType == LSKEYPACKTYPE_SELECT || ucAgreementType == LSKEYPACKTYPE_RETAIL || ucAgreementType == LSKEYPACKTYPE_CONCURRENT || ucAgreementType == LSKEYPACKTYPE_OPEN) && keypack_found.dwNumberOfLicenses == 0) { continue; } pAllocated->lpAllocateKeyPack[bufIndex] = keypack_found; #ifdef DBG dwPrevNumLicense = pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses; #endif if( ucAgreementType != LSKEYPACKTYPE_RETAIL && ucAgreementType != LSKEYPACKTYPE_CONCURRENT && ucAgreementType != LSKEYPACKTYPE_OPEN && ucAgreementType != LSKEYPACKTYPE_SELECT ) { // For Free/temporary license, number of available license is // how many license has been issued pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses += dwNumLicenses; pAllocated->pdwAllocationVector[bufIndex] = dwNumLicenses; dwTotalAllocated += dwNumLicenses; pAllocated->lpAllocateKeyPack[bufIndex].dwNextSerialNumber += dwNumLicenses; dwNumLicenses=0; } else { int allocated=min(dwNumLicenses, keypack_found.dwNumberOfLicenses); pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses -= allocated; dwNumLicenses -= allocated; pAllocated->pdwAllocationVector[bufIndex] = allocated; dwTotalAllocated += allocated; pAllocated->lpAllocateKeyPack[bufIndex].dwNextSerialNumber += allocated; } #if DBG DBGPrintf( DBG_INFORMATION, DBG_FACILITY_ALLOCATELICENSE, DBGLEVEL_FUNCTION_DETAILSIMPLE, _TEXT("Updating keypack %d number of license from %d to %d\n"), pAllocated->lpAllocateKeyPack[bufIndex].dwKeyPackId, dwPrevNumLicense, pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses ); #endif // // Update number of licenses available for this keypack and license id in keypack // GetSystemTimeAsFileTime(&(pAllocated->lpAllocateKeyPack[bufIndex].ftLastModifyTime)); if(licpack_table.UpdateRecord( pAllocated->lpAllocateKeyPack[bufIndex], LICENSEDPACK_ALLOCATE_LICENSE_UPDATE_FIELD ) == FALSE) { SetLastError(status = SET_JB_ERROR(licpack_table.GetLastJetError())); TLSASSERT(FALSE); break; } #ifdef DBG TLSLICENSEPACK test; if(licpack_table.FetchRecord(test) == FALSE) { SetLastError(status = SET_JB_ERROR(licpack_table.GetLastJetError())); TLSASSERT(FALSE); } if(test.dwKeyPackId != pAllocated->lpAllocateKeyPack[bufIndex].dwKeyPackId || test.dwNumberOfLicenses != pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses) { TLSASSERT(FALSE); } //FreeTlsLicensePack(&test); #endif bufIndex++; } } catch(...) { SetLastError(status = TLS_E_INTERNAL); } // // terminate enumeration. // TLSDBKeyPackEnumEnd(pDbWkSpace); if(status == TLS_I_NO_MORE_DATA) { if(bufIndex != 0) { status = ERROR_SUCCESS; } else if(!bProductInstalled) { SetLastError(status = TLS_E_PRODUCT_NOTINSTALL); } } pAllocated->dwBufSize = bufIndex; pAllocated->dwTotalAllocated = dwTotalAllocated; pAllocated->dwBufSize = bufIndex; cleanup: TLSDBUnlockKeyPackTable(); return status; }