static DWORD VMCABackupFiles( PCSTR pszBaseFilePath ) { DWORD dwError = ERROR_SUCCESS; const DWORD MAX_NUMBER_OF_BAKUPS = 32; struct STAT st = { 0 }; DWORD dwCounter; PSTR pszDestFile = NULL; PSTR pszSourceFile = NULL; for (dwCounter = MAX_NUMBER_OF_BAKUPS; dwCounter > 0; --dwCounter) { dwError = VMCAAllocateStringPrintfA( &pszDestFile, "%s.%d", pszBaseFilePath, dwCounter); BAIL_ON_ERROR(dwError); if(STAT(pszDestFile, &st) == ERROR_SUCCESS ) { UNLINK(pszDestFile); } dwError = VMCAAllocateStringPrintfA( &pszSourceFile, "%s.%d", pszBaseFilePath, dwCounter - 1); BAIL_ON_ERROR(dwError); RENAME(pszSourceFile, pszDestFile); VMCA_SAFE_FREE_STRINGA(pszDestFile); VMCA_SAFE_FREE_STRINGA(pszSourceFile); pszDestFile = NULL; pszSourceFile = NULL; } VMCA_SAFE_FREE_STRINGA(pszDestFile); dwError = VMCAAllocateStringPrintfA( &pszDestFile, "%s.%d", pszBaseFilePath, 0); BAIL_ON_ERROR(dwError); RENAME(pszBaseFilePath, pszDestFile); error: VMCA_SAFE_FREE_STRINGA(pszDestFile); VMCA_SAFE_FREE_STRINGA(pszSourceFile); return dwError; }
uint32_t make_negotiate_token( gss_buffer_desc *pBuffer, char **ppszNegotiate ) { uint32_t dwError = 0; char *pszEncodedData = NULL; char *pszNegotiate = NULL; //int len = 0; if (pBuffer) { dwError = base64_encode( pBuffer->value, pBuffer->length, &pszEncodedData); BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCAAllocateStringPrintfA( &pszNegotiate, "Negotiate %s", pszEncodedData ? pszEncodedData : ""); BAIL_ON_VMCA_ERROR(dwError); *ppszNegotiate = pszNegotiate; cleanup: VMCA_SAFE_FREE_MEMORY(pszEncodedData); return dwError; error: VMCA_SAFE_FREE_MEMORY(pszNegotiate); goto cleanup; }
DWORD VMCACreatePrimaryLog(PSTR pszLogDir) { DWORD dwError = 0; PSTR pszDestFile = NULL; if(pszLogDir == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCAAllocateStringPrintfA( &pszDestFile, FORMATSTR, pszLogDir, VMCA_LOG_STRING, 0);// This is always the Current Log File BAIL_ON_VMCA_ERROR(dwError); if (fpCurrentLog != NULL) { fclose(fpCurrentLog); fpCurrentLog = NULL; } fpCurrentLog = fopen(pszDestFile, "a"); gVMCACurrentLogSizeBytes = 0; error : VMCA_SAFE_FREE_STRINGA(pszDestFile); return dwError; }
DWORD VMCARESTSetResponsePayload( PVMREST_HANDLE pRESTHandle, PREST_RESPONSE* ppResponse, PSTR pszRespPayload ) { DWORD dwError = 0; DWORD bytesWritten = 0; PSTR pszPyldLen = NULL; size_t pyldLen = 0; size_t sentLen = 0; pyldLen = VMCAStringLenA(VMCA_SAFE_STRING(pszRespPayload)); dwError = VMCAAllocateStringPrintfA(&pszPyldLen, "%ld", pyldLen); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetDataLength( ppResponse, pyldLen > VMCARESTMAXPAYLOADLENGTH ? NULL : pszPyldLen); BAIL_ON_VMREST_ERROR(dwError); do { size_t chunkLen = pyldLen > VMCARESTMAXPAYLOADLENGTH ? VMCARESTMAXPAYLOADLENGTH : pyldLen; dwError = VmRESTSetData( pRESTHandle, ppResponse, VMCA_SAFE_STRING(pszRespPayload) + sentLen, chunkLen, &bytesWritten); sentLen += bytesWritten; pyldLen -= bytesWritten; } while (dwError == REST_ENGINE_MORE_IO_REQUIRED); BAIL_ON_VMREST_ERROR(dwError); cleanup: VMCA_SAFE_FREE_MEMORY(pszPyldLen); return dwError; error: goto cleanup; }
DWORD VMCAGetTempCRLNamePath(PSTR *pszPrivPath) { PSTR pszDataPath = NULL; DWORD dwError = 0; dwError = VMCAGetDataDirectory(&pszDataPath); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA(pszPrivPath,"%s%s%s",pszDataPath,VMCA_PATH_SEPARATOR,VMCA_CRL_TMP_NAME); BAIL_ON_ERROR(dwError); error: if(pszDataPath != NULL){ VMCAFreeStringA(pszDataPath); } return dwError; }
DWORD VMCAGetCertsDBPath(PSTR *pszPrivPath) { PSTR pszDataPath = NULL; DWORD dwError = 0; dwError = VMCAGetDataDirectory(&pszDataPath); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA(pszPrivPath,"%s%s%s",pszDataPath,VMCA_PATH_SEPARATOR,CERTS_DB); BAIL_ON_ERROR(dwError); error: if(pszDataPath != NULL){ VMCAFreeStringA(pszDataPath); } return dwError; }
DWORD VMCAGetPrivateKeyPasswordPath(PSTR *pszPrivPath) { PSTR pszDataPath = NULL; DWORD dwError = 0; dwError = VMCAGetDataDirectory(&pszDataPath); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA(pszPrivPath,"%s%s%s",pszDataPath,VMCA_PATH_SEPARATOR,PRIVATE_PASSWORD); BAIL_ON_ERROR(dwError); error: if(pszDataPath != NULL){ VMCAFreeStringA(pszDataPath); } return dwError; }
DWORD VMCAGetRootCertificateFilePath(PSTR *pszRootPath) { PSTR pszDataPath = NULL; DWORD dwError = 0; dwError = VMCAGetDataDirectory(&pszDataPath); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA(pszRootPath,"%s%s%s",pszDataPath,VMCA_PATH_SEPARATOR,ROOT_CER); BAIL_ON_ERROR(dwError); error: if(pszDataPath != NULL){ VMCAFreeStringA(pszDataPath); } return dwError; }
/* * VMCAPolicySNMatchAuthOUWithCSR is the heart of SN policy validation. * * It verifies if the CSR organizationName entries in the subjectName field comprise the DN of the requestor. * * Examples: * * Pass: * * Parameters: * * Machine account DN: [email protected],ou=ex2,ou=ex1,ou=computers,dc=example,dc=com * * organizationName entries: {ex1, ex2} * * Config file match rule baseDN: ou=ex1,ou=computers,dc=example,dc=com * * Result: * * This will pass because the machine account lives under ou=ex2,ou=ex1 which is * under the baseDN from the config file, and the CSR organizationName entries contain * the OUs that the machine account lives under. * * Pass: * * Parameters: * * Machine account DN: [email protected],ou=ex2,ou=ex1,ou=computers,dc=example,dc=com * * organizationName entries: {ex2, ex1} * * Config file match rule baseDN: ou=ex1,ou=computers,dc=example,dc=com * * Result: * * This will pass because the machine account lives under ou=ex2,ou=ex1 which is * under the baseDN from the config file, and the CSR organizationName entries contain * the OUs that the machine account lives under (order does not matter). * * Fail: * * Parameters: * * Machine account DN: [email protected],ou=ex2,ou=ex1,ou=computers,dc=example,dc=com * * organizationName entries: {ex2} * * Config file match rule baseDN: ou=ex1,ou=computers,dc=example,dc=com * * Result: * * This will fail because the machine account lives under ou=ex2,ou=ex1 which is * under the baseDN from the config file, but the CSR organizationName entries do not * contain all of the OUs that the machine account lives under. * * Fail: * * Parameters: * * Machine account DN: [email protected],ou=ex2,ou=ex1,ou=computers,dc=example,dc=com * * organizationName entries: {ex2, ex2} * * Config file match rule baseDN: ou=ex1,ou=computers,dc=example,dc=com * * Result: * * This will fail because the machine account lives under ou=ex2,ou=ex1 which is * under the baseDN from the config file, but the CSR organizationName entries do not * contain all of the OUs that the machine account lives under, even though the amount * is the same. * * Fail: * * Parameters: * * Machine account DN: [email protected],ou=ex2,ou=ex1,ou=computers,dc=example,dc=com * * organizationName entries: {ex3, ex4} * * Config file match rule baseDN: ou=ex1,ou=computers,dc=example,dc=com * * Result: * * This will fail because the machine account lives under ou=ex2,ou=ex1 which is * under the baseDN from the config file, but the CSR organizationName entries do not * contain any of the OUs that the machine account lives under. * * @param pcszAuthDN: The DN of the CSR requestor * @param pcszAuthBaseDN: The baes DN under which the requestor must live * @param dwOrgNamesLen: The number of organizationName entries in the CSR subjectName field * @param ppcszOrgNames: An array of the organizationName entries * * @return A status code indicating valid (0) or invalid (not 0) request */ static DWORD VMCAPolicySNMatchAuthOUWithCSR( PCSTR pcszAuthDN, PCSTR pcszAuthBaseDN, DWORD dwOrgNamesLen, PSTR* const ppcszOrgNames ) { DWORD dwError = 0; DWORD dwIdx = 0; DWORD dwNumRDNsInAuthDN = 0; DWORD dwNumAuthRDNsToValidate = 0; DWORD dwNumRDNsInBaseDn = 0; PSTR pszFormattedOrgName = NULL; PSTR *ppszAuthRDNs = NULL; PSTR *ppszAuthBaseRDNs = NULL; PSTR *ppszAuthRDNsNoUserObj = NULL; PSTR *ppszOrgNamesLocal = NULL; if (IsNullOrEmptyString(pcszAuthDN) || IsNullOrEmptyString(pcszAuthBaseDN)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } if (dwOrgNamesLen < 1 || !ppcszOrgNames) { VMCA_LOG_INFO( "[%s,%d] SNPolicy violation: CSR subjectName did not contain organizationName entries. User (%s)", __FUNCTION__, __LINE__, pcszAuthDN); dwError = VMCA_POLICY_VALIDATION_ERROR; BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCADNToRDNArray( pcszAuthBaseDN, FALSE, &dwNumRDNsInBaseDn, &ppszAuthBaseRDNs); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCADNToRDNArray( pcszAuthDN, FALSE, &dwNumRDNsInAuthDN, &ppszAuthRDNs); BAIL_ON_VMCA_ERROR(dwError); dwNumAuthRDNsToValidate = dwNumRDNsInAuthDN - dwNumRDNsInBaseDn; if (dwOrgNamesLen != dwNumAuthRDNsToValidate) { VMCA_LOG_INFO( "[%s,%d] SNPolicy violation: CSR subjectName does not have same number of organizationName entries as auth principal RDNs. User (%s)", __FUNCTION__, __LINE__, pcszAuthDN); dwError = VMCA_POLICY_VALIDATION_ERROR; BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCACopyStringArrayA( &ppszOrgNamesLocal, dwOrgNamesLen, ppcszOrgNames, dwOrgNamesLen); BAIL_ON_VMCA_ERROR(dwError); // Increment AuthRDN ptr array by 1 as first RDN will be machine account obj ppszAuthRDNsNoUserObj = ppszAuthRDNs + 1; qsort(ppszAuthRDNsNoUserObj, dwNumAuthRDNsToValidate, sizeof(PSTR), &VMCAPolicySNStrCmpWrapper); qsort(ppszOrgNamesLocal, dwOrgNamesLen, sizeof(PSTR), &VMCAPolicySNStrCmpWrapper); for (; dwIdx < dwNumAuthRDNsToValidate; ++dwIdx) { dwError = VMCAAllocateStringPrintfA( &pszFormattedOrgName, "ou=%s", ppszOrgNamesLocal[dwIdx]); BAIL_ON_VMCA_ERROR(dwError); if (VMCAStringCompareA(ppszAuthRDNsNoUserObj[dwIdx], pszFormattedOrgName, TRUE)) { VMCA_LOG_INFO( "[%s,%d] SNPolicy violation: CSR subjectName organizationName does not match auth principal DN. User (%s)", __FUNCTION__, __LINE__, pcszAuthDN); dwError = VMCA_POLICY_VALIDATION_ERROR; BAIL_ON_VMCA_ERROR(dwError); } VMCA_SAFE_FREE_STRINGA(pszFormattedOrgName); } cleanup: VMCA_SAFE_FREE_STRINGA(pszFormattedOrgName); VMCAFreeStringArrayA(ppszAuthBaseRDNs, dwNumRDNsInBaseDn); VMCAFreeStringArrayA(ppszAuthRDNs, dwNumRDNsInAuthDN); VMCAFreeStringArrayA(ppszOrgNamesLocal, dwOrgNamesLen); return dwError; error: goto cleanup; }
// This function renames logs to rotate. // for example if max old log is 5, then // vmca.log.4 -> vmca.log.5 // vmca.log.3 -> vmca.log.4 // vmca.log.2 -> vmca.log.3 // vmca.log.1 -> vmca.log.2 // vmca.log.0 -> vmca.log.1 // where vmca.log.1 is the most current log. DWORD VMCARenameLogs() { int nCounter = 0; PSTR pszSourceFile = NULL; PSTR pszDestFile = NULL; PSTR pszLogDir = NULL; struct STAT st = { 0 }; DWORD dwError = 0; dwError = VMCAGetLogFileDirectory(&pszLogDir); BAIL_ON_VMCA_ERROR(dwError); if (fpCurrentLog) { fclose(fpCurrentLog); fpCurrentLog = NULL; } for ( nCounter = (int)gVMCAMaxOldLogs; nCounter > 0 ; nCounter --) { dwError = VMCAAllocateStringPrintfA( &pszDestFile, FORMATSTR, pszLogDir, VMCA_LOG_STRING, nCounter); BAIL_ON_VMCA_ERROR(dwError); if(STAT(pszDestFile, &st) == VMCA_OK ) { UNLINK(pszDestFile); } dwError = VMCAAllocateStringPrintfA( &pszSourceFile, FORMATSTR, pszLogDir, VMCA_LOG_STRING, nCounter - 1); BAIL_ON_VMCA_ERROR(dwError); if (RENAME(pszSourceFile, pszDestFile) != VMCA_OK ) { // Emit an Error Event once we have support for that } VMCA_SAFE_FREE_STRINGA(pszDestFile); pszDestFile = NULL; VMCA_SAFE_FREE_STRINGA(pszSourceFile); pszSourceFile = NULL; } cleanup : VMCA_SAFE_FREE_STRINGA(pszLogDir); return dwError; error : VMCA_SAFE_FREE_STRINGA(pszDestFile); VMCA_SAFE_FREE_STRINGA(pszSourceFile); goto cleanup; }
DWORD VMCAUpdatePkiCAAttribute( PVMCA_LDAP_CONTEXT pContext, PSTR pszConfigurationDN, X509* pCertificate ) { DWORD dwError = 0; PSTR pszCertificate = NULL; PSTR pszCAContainerDN = NULL; PSTR pszCADN = NULL; PSTR pszCACN = NULL; PSTR pszCAIssuerDN = NULL; PSTR pszFoundCADN = NULL; X509_NAME *pCertName = NULL; ATTR_SEARCH_RESULT attrSearchResult = ATTR_NOT_FOUND; if (!pCertificate || !pContext || IsNullOrEmptyString(pszConfigurationDN) ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_ERROR (dwError); } dwError = VMCACertToPEM( pCertificate, &pszCertificate ); BAIL_ON_ERROR (dwError); pCertName = X509_get_subject_name(pCertificate); if ( pCertName == NULL) // Don't free { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } dwError = VMCAGetX509Name(pCertName, XN_FLAG_COMPAT, &pszCAIssuerDN); BAIL_ON_ERROR(dwError); dwError = VMCAGenerateCACNForLdap(pCertificate, &pszCACN); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA( &pszCAContainerDN, "CN=%s,%s", CA_CONTAINER_NAME, pszConfigurationDN); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA( &pszCADN, "CN=%s,%s", pszCACN, pszCAContainerDN); BAIL_ON_ERROR(dwError); dwError = VMCACheckCAObject( pContext, NULL, pszCADN, NULL, &pszFoundCADN ); BAIL_ON_ERROR(dwError); if (IsNullOrEmptyString(pszFoundCADN)) { dwError = VMCACreateCAObject( pContext, pszCACN, pszCADN ); BAIL_ON_ERROR(dwError); } dwError = VMCACheckAttribute( pContext, pszCADN, ATTR_CA_CERTIFICATE, pszCertificate, &attrSearchResult); BAIL_ON_ERROR(dwError); if (attrSearchResult != ATTR_MATCH) { dwError = VMCAUpdateAttribute(pContext, pszCADN, ATTR_CA_CERTIFICATE, pszCertificate, (attrSearchResult == ATTR_NOT_FOUND)); BAIL_ON_ERROR(dwError); } dwError = VMCACheckAttribute( pContext, pszCADN, ATTR_CA_CERTIFICATE_DN, pszCAIssuerDN, &attrSearchResult); BAIL_ON_ERROR(dwError); if (attrSearchResult != ATTR_MATCH) { dwError = VMCAUpdateAttribute(pContext, pszCADN, ATTR_CA_CERTIFICATE_DN, pszCAIssuerDN, (attrSearchResult == ATTR_NOT_FOUND)); BAIL_ON_ERROR(dwError); } cleanup: VMCA_SAFE_FREE_STRINGA(pszCertificate); VMCA_SAFE_FREE_STRINGA(pszFoundCADN); VMCA_SAFE_FREE_STRINGA(pszCAContainerDN); VMCA_SAFE_FREE_STRINGA(pszCACN); VMCA_SAFE_FREE_STRINGA(pszCADN); VMCA_SAFE_FREE_STRINGA(pszCAIssuerDN); return dwError; error: goto cleanup; }
DWORD VMCAUpdateCrlCAAttribute( PVMCA_LDAP_CONTEXT pContext, PSTR pszConfigurationDN, PSTR pszCrl ) { DWORD dwError = 0; PSTR pszCADN = NULL; PSTR pszCrlAuthorityKeyId = NULL; PSTR pszCAContainerDN = NULL; X509_CRL* pCrl = NULL; ATTR_SEARCH_RESULT attrSearchResult = ATTR_NOT_FOUND; X509_NAME* pIssuer = NULL; PSTR pszCAIssuerDN = NULL; PSTR pszFoundCADN = NULL; dwError = VMCAPEMToX509Crl(pszCrl, &pCrl); BAIL_ON_ERROR(dwError); dwError = VMCAAllocateStringPrintfA( &pszCAContainerDN, "CN=%s,%s", CA_CONTAINER_NAME, pszConfigurationDN); BAIL_ON_ERROR(dwError); dwError = VMCAGetCrlAuthKeyIdHexString(pCrl, &pszCrlAuthorityKeyId); if (dwError == ERROR_SUCCESS) { if (!IsNullOrEmptyString(pszCrlAuthorityKeyId)) { dwError = VMCAAllocateStringPrintfA( &pszCADN, "CN=%s,%s", pszCrlAuthorityKeyId, pszCAContainerDN); BAIL_ON_ERROR(dwError); } } if (!pszCADN) { pIssuer = X509_CRL_get_issuer(pCrl); // Don't free dwError = VMCAGetX509Name(pIssuer, XN_FLAG_COMPAT, &pszCAIssuerDN); BAIL_ON_ERROR(dwError); if (pszCAIssuerDN == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } } dwError = VMCACheckCAObject( pContext, pszCAContainerDN, pszCADN, pszCAIssuerDN, &pszFoundCADN ); if (dwError == ERROR_INVALID_STATE && pszCAIssuerDN) { VMCA_LOG_ERROR("More than one CA found with given issuer DN: %s", pszCAIssuerDN); } BAIL_ON_ERROR(dwError); if (!pszFoundCADN) { dwError = ERROR_NOT_FOUND; BAIL_ON_ERROR(dwError); } dwError = VMCACheckAttribute( pContext, pszFoundCADN, ATTR_CRL, pszCrl, &attrSearchResult ); BAIL_ON_ERROR(dwError); if (attrSearchResult != ATTR_MATCH) { dwError = VMCAUpdateAttribute(pContext, pszFoundCADN, ATTR_CRL, pszCrl, (attrSearchResult == ATTR_NOT_FOUND)); BAIL_ON_ERROR(dwError); } cleanup: VMCA_SAFE_FREE_MEMORY(pszFoundCADN); VMCA_SAFE_FREE_MEMORY(pszCAIssuerDN); VMCA_SAFE_FREE_STRINGA(pszCADN); VMCA_SAFE_FREE_STRINGA(pszCrlAuthorityKeyId); VMCA_SAFE_FREE_STRINGA(pszCAContainerDN); if (pCrl) { X509_CRL_free(pCrl); } return dwError; error: goto cleanup; }
DWORD VMCALdapConnect( PSTR pszHostName, DWORD dwPort, PSTR pszUsername, PSTR pszPassword, PVMCA_LDAP_CONTEXT* ppLotus ) { DWORD dwError = 0; PVMCA_LDAP_CONTEXT pContext = NULL; PSTR pszUrl = NULL; BerValue ldapBindPwd = {0}; //LDAP_SUCCESS is defined as Zero in the Standard // Which plays well with our BAIL_ON_ERROR macro DWORD dwVersion = LDAP_VERSION3; DWORD dwReturns = 20; if(dwPort == 0) { // Let us use the default LDAP_PORT, 389 dwPort = LDAP_PORT; } dwError = VMCAAllocateMemory(sizeof(*pContext), (PVOID*)&pContext); BAIL_ON_ERROR(dwError); if (VMCAIsIPV6AddrFormat(pszHostName)) { dwError = VMCAAllocateStringPrintfA( &pszUrl, "ldap://[%s]:%d", pszHostName, dwPort); } else { dwError = VMCAAllocateStringPrintfA( &pszUrl, "ldap://%s:%d", pszHostName, dwPort); } BAIL_ON_ERROR(dwError); if(IsNullOrEmptyString(pszPassword)) { // no credentials, do anonymous bind. dwError = ldap_initialize(&pContext->pConnection, pszUrl); BAIL_ON_ERROR(dwError); if (pContext->pConnection == NULL) { ldap_get_option(pContext->pConnection, LDAP_OPT_ERROR_NUMBER, &dwError); //dwError = ld_errno; //LdapGetLastError(); BAIL_ON_ERROR(dwError); } dwError = ldap_set_option(pContext->pConnection, LDAP_OPT_PROTOCOL_VERSION, (void*)&dwVersion); BAIL_ON_ERROR(dwError); dwError = ldap_set_option(pContext->pConnection, LDAP_OPT_SIZELIMIT, (void*)& dwReturns); BAIL_ON_ERROR(dwError); dwError = ldap_sasl_bind_s( pContext->pConnection, pszUsername, LDAP_SASL_SIMPLE, &ldapBindPwd, // no credentials NULL, NULL, NULL); } else { dwError = VmCASASLSRPBind( &pContext->pConnection, pszUrl, pszUsername, pszPassword); } #ifdef LDAP_ERROR_MESSAGE if(dwError != 0) { printf("Error :%s\n",ldap_err2string(dwError)); } #endif BAIL_ON_ERROR(dwError); *ppLotus = pContext; cleanup: VMCA_SAFE_FREE_STRINGA(pszUrl); return dwError; error: if ((dwError != 0) && pContext) { VMCALdapClose(pContext); } goto cleanup; }
DWORD VMCALdapGetMemberships( PVMCA_LDAP_CONTEXT pConnection, PCSTR pszUPNName, PSTR **pppszMemberships, PDWORD pdwMemberships ) { DWORD dwError = 0; PSTR pszFilter = NULL; PSTR pszAttrMemberOf = ATTR_MEMBEROF; // memberOf PSTR ppszAttrs[] = { pszAttrMemberOf, NULL}; DWORD dwCount = 0; LDAPMessage *pResult = NULL; LDAPMessage *pEntry = NULL; struct berval** ppValues = NULL; PSTR *ppszMemberships = NULL; DWORD dwMemberships = 0; DWORD i = 0; LDAP *pLd = NULL; if (pConnection == NULL || pConnection->pConnection == NULL || IsNullOrEmptyString(pszUPNName) || pppszMemberships == NULL || pdwMemberships == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } pLd = pConnection->pConnection; dwError = VMCAAllocateStringPrintfA(&pszFilter, "(%s=%s)", ATTR_KRB_UPN, pszUPNName); // userPrincipalName BAIL_ON_VMCA_ERROR(dwError); dwError = ldap_search_ext_s( pLd, "", LDAP_SCOPE_SUBTREE, pszFilter, (PSTR*)ppszAttrs, 0, NULL, NULL, NULL, -1, &pResult); BAIL_ON_VMCA_ERROR(dwError); dwCount = ldap_count_entries(pLd, pResult); if (dwCount == 0) { dwError = LDAP_NO_SUCH_OBJECT; BAIL_ON_VMCA_ERROR(dwError); } else if (dwCount > 1) { dwError = LDAP_OPERATIONS_ERROR; BAIL_ON_VMCA_ERROR(dwError); } pEntry = ldap_first_entry(pLd, pResult); if (!pEntry) { dwError = LDAP_NO_SUCH_OBJECT; BAIL_ON_VMCA_ERROR(dwError); } ppValues = ldap_get_values_len(pLd, pEntry, pszAttrMemberOf); if (!ppValues) { dwMemberships = 0; } else { dwMemberships = ldap_count_values_len(ppValues); } if (dwMemberships) { dwError = VMCAAllocateMemory(dwMemberships * sizeof(PSTR), (PVOID*)&ppszMemberships); BAIL_ON_VMCA_ERROR(dwError); for (i = 0; ppValues[i] != NULL; i++) { PCSTR pszMemberOf = ppValues[i]->bv_val; dwError = VMCAAllocateStringA(pszMemberOf, &ppszMemberships[i]); BAIL_ON_VMCA_ERROR(dwError); } } *pppszMemberships = ppszMemberships; *pdwMemberships = dwMemberships; cleanup: if(ppValues) { ldap_value_free_len(ppValues); } if (pResult) { ldap_msgfree(pResult); } VMCA_SAFE_FREE_MEMORY(pszFilter); return dwError; error: if (ppszMemberships != NULL && dwMemberships > 0) { for (i = 0; i < dwMemberships; i++) { VMCA_SAFE_FREE_STRINGA(ppszMemberships[i]); } VMCA_SAFE_FREE_MEMORY(ppszMemberships); } goto cleanup; }
DWORD VMCAConvertUPNToDN( PVMCA_LDAP_CONTEXT pConnection, PCSTR pszUPN, PSTR* ppszOutDN ) { DWORD dwError = 0; LDAPMessage* pEntry = NULL; LDAPMessage* pResult = NULL; PSTR pszFilter = NULL; PSTR pszEntryDN = NULL; PSTR pszOutDN = NULL; int iCount = 0; LDAP *pLd = NULL; if (!pConnection || !pConnection->pConnection || IsNullOrEmptyString(pszUPN) || !ppszOutDN) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } pLd = pConnection->pConnection; dwError = VMCAAllocateStringPrintfA( &pszFilter, "%s=%s", ATTR_KRB_UPN, pszUPN); BAIL_ON_VMCA_ERROR(dwError); dwError = ldap_search_ext_s( pLd, "", LDAP_SCOPE_SUBTREE, pszFilter, NULL, FALSE, /* get values */ NULL, /* server controls */ NULL, /* client controls */ NULL, /* timeout */ 0, /* size limit */ &pResult); BAIL_ON_VMCA_ERROR(dwError); iCount = ldap_count_entries(pLd, pResult); // should have either 0 or 1 result if (iCount > 1) { dwError = VMCA_ERROR_INVALID_STATE; BAIL_ON_VMCA_ERROR(dwError); } else if (iCount == 0) { dwError = VMCA_ERROR_ENTRY_NOT_FOUND; BAIL_ON_VMCA_ERROR(dwError); } if ( (pEntry = ldap_first_entry(pLd, pResult)) != NULL ) { pszEntryDN = ldap_get_dn(pLd, pEntry); dwError = VMCAAllocateStringA( pszEntryDN, &pszOutDN ); BAIL_ON_VMCA_ERROR(dwError); *ppszOutDN = pszOutDN; } else { dwError = VMCA_ERROR_INVALID_ENTRY; BAIL_ON_VMCA_ERROR(dwError); } cleanup: if (pszEntryDN) { ldap_memfree( pszEntryDN ); } if (pResult) { ldap_msgfree( pResult ); } VMCA_SAFE_FREE_MEMORY(pszFilter); return dwError; error: VMCA_LOG_ERROR("[%s,%d] failed with error (%u)", __FUNCTION__, __LINE__, dwError); VMCA_SAFE_FREE_MEMORY(pszOutDN); if (ppszOutDN) { *ppszOutDN = NULL; } goto cleanup; }
static DWORD VMCALdapFindObject( PVMCA_LDAP_CONTEXT pContext, PCSTR pszBaseDN, ber_int_t scope, PCSTR pszAttribute, PCSTR pszValue, PSTR *ppszObjectDN ) { DWORD dwError = 0; DWORD dwNumEntries = 0; LDAPMessage* pResult = NULL; LDAPMessage* pEntry = NULL; PSTR pszFilter = NULL; PSTR pszObjectDN = NULL; if (pszAttribute && pszValue) { VMCAAllocateStringPrintfA(&pszFilter, "(%s=%s)", pszAttribute, pszValue); } dwError = ldap_search_ext_s( pContext->pConnection, (PSTR)pszBaseDN, scope, pszFilter, NULL, /* attributes */ TRUE, NULL, /* server controls */ NULL, /* client controls */ NULL, /* timeout */ 0, &pResult); BAIL_ON_ERROR(dwError); dwNumEntries = ldap_count_entries(pContext->pConnection, pResult); if (dwNumEntries > 1) { dwError = ERROR_INVALID_STATE; BAIL_ON_ERROR(dwError); } else if (dwNumEntries == 0) { dwError = ERROR_NOT_FOUND; BAIL_ON_ERROR(dwError); } else { pEntry = ldap_first_entry(pContext->pConnection, pResult); if (!pEntry) { dwError = ERROR_INVALID_STATE; BAIL_ON_ERROR(dwError); } pszObjectDN = ldap_get_dn(pContext->pConnection, pEntry); if (IsNullOrEmptyString(pszObjectDN)) { dwError = ERROR_INVALID_STATE; BAIL_ON_ERROR(dwError); } *ppszObjectDN = pszObjectDN; } cleanup: if (pResult) { ldap_msgfree(pResult); } VMCA_SAFE_FREE_STRINGA(pszFilter); return dwError; error : VMCA_SAFE_FREE_STRINGA(pszObjectDN); if (dwError == LDAP_NO_SUCH_OBJECT) { dwError = 0; } goto cleanup; }
static DWORD VMCASrvUpdateRootCerts( PVMCA_DIR_SYNC_PARAMS pDirSyncParams, PBOOLEAN pbSynced ) { DWORD dwError = 0; PVMCA_X509_CA pCA = NULL; PSTR pszAccount = NULL; PSTR pszPassword = NULL; PSTR pszDomainName = NULL; PSTR pszCAContainerDN = NULL; PSTR pszCertificate = NULL; PSTR pszCRL = NULL; X509_CRL* pCrl = NULL; DWORD dwCount = 0; DWORD dwIndex = 0; PVMCA_LDAP_CONTEXT pContext = NULL; PSTR pszUPN = NULL; dwError = VMCASrvValidateCA(); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCASrvGetCA(&pCA); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCASrvGetMachineAccountInfoA( &pszAccount, &pszDomainName, &pszPassword); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCAAllocateStringPrintfA( &pszUPN, "%s@%s", pszAccount, pszDomainName); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCALdapConnect( "localhost", 0, /* use default port */ pszUPN, pszPassword, &pContext); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCAGetDSERootAttribute( pContext, "configurationNamingContext", &pszCAContainerDN); BAIL_ON_VMCA_ERROR(dwError); dwError = VmcaSrvReGenCRL( &pCrl ); BAIL_ON_VMCA_ERROR (dwError); dwError = VMCACRLToPEM( pCrl, &pszCRL ); BAIL_ON_VMCA_ERROR (dwError); dwCount = sk_X509_num(pCA->skCAChain); for (; dwIndex <dwCount; dwIndex++) { X509 *pCert = sk_X509_value( pCA->skCAChain, dwIndex ); dwError = VMCAUpdatePkiCAAttribute( pContext, pszCAContainerDN, pCert ); BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCAUpdateCrlCAAttribute( pContext, pszCAContainerDN, pszCRL ); BAIL_ON_VMCA_ERROR (dwError); *pbSynced = TRUE; cleanup: VMCA_SAFE_FREE_STRINGA(pszUPN); VMCA_SAFE_FREE_STRINGA(pszDomainName); VMCA_SAFE_FREE_STRINGA(pszCertificate); VMCA_SAFE_FREE_STRINGA(pszAccount); VMCA_SAFE_FREE_STRINGA(pszPassword); VMCA_SAFE_FREE_STRINGA(pszCRL); if (pContext) { VMCALdapClose(pContext); } if (pCA) { VMCAReleaseCA(pCA); } return dwError; error: *pbSynced = FALSE; VMCA_LOG_ERROR("Failed to update root certs due to error [%u]", dwError); // TODO : Check specific errors dwError = 0; goto cleanup; }
DWORD VMCARESTVerifyKrbAuth( PVMCA_AUTHORIZATION_PARAM pAuthorization, PVMCA_ACCESS_TOKEN* ppAccessToken ) { DWORD dwError = 0; PSTR pszNegotiate = NULL; PSTR pszDecode = NULL; PSTR pszUser = NULL; char *pszToken = NULL; int nLength = 0; OM_uint32 major_status; OM_uint32 minor_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER; gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; gss_name_t client_name = GSS_C_NO_NAME; static gss_OID_desc gss_spnego_mech_oid_desc = {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; static gss_OID gss_spnego_mech_oid = &gss_spnego_mech_oid_desc; gss_cred_id_t server_creds; pszNegotiate = pAuthorization->pszAuthorizationToken; if ( IsNullOrEmptyString(pszNegotiate) ) { dwError = EACCES; BAIL_ON_VMREST_ERROR(dwError); } if (!strcmp(pszNegotiate,"testing")) // TODO: REMOVE // TODO: DO NOT CHECK IN {// Kerberos backdoor for testing dwError = VMCARESTMakeKrbAccessToken(ppAccessToken); BAIL_ON_VMREST_ERROR(dwError); goto cleanup; } dwError = base64_decode( pszNegotiate, &pszDecode, &nLength ); BAIL_ON_VMREST_ERROR(dwError); dwError = server_acquire_creds( "HTTP", &gss_spnego_mech_oid_desc, &server_creds ); BAIL_ON_VMREST_ERROR(dwError); input_token.length = nLength; input_token.value = pszDecode; major_status = gss_accept_sec_context( &minor_status, &gss_context, server_creds, &input_token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, &gss_spnego_mech_oid, &output_token, NULL, NULL, NULL ); if (GSS_ERROR(major_status) ) { //TODO: insert show error dwError = EACCES; BAIL_ON_VMREST_ERROR(dwError); } if (output_token.length) { dwError = make_negotiate_token(&output_token, &pszToken); BAIL_ON_VMREST_ERROR(dwError); } if (major_status == GSS_S_CONTINUE_NEEDED) { OM_uint32 min2; gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER; OM_uint32 msg_ctx = 0; PSTR pszError = NULL; gss_oid_to_str(&min2, gss_spnego_mech_oid, &mech_msg); gss_display_status(&min2, major_status, GSS_C_GSS_CODE, gss_spnego_mech_oid, &msg_ctx, &gss_msg); gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, gss_spnego_mech_oid, &msg_ctx, &minor_msg); VMCAAllocateStringPrintfA(&pszError, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]", major_status, (int)gss_msg.length, (const char *)(gss_msg.value?gss_msg.value:""), (int)mech_msg.length, (const char *)(mech_msg.value?mech_msg.value:""), minor_status, (int)minor_msg.length, (const char *)(minor_msg.value?minor_msg.value:"")); gss_release_buffer(&min2, &mech_msg); gss_release_buffer(&min2, &gss_msg); gss_release_buffer(&min2, &minor_msg); } if (major_status == GSS_S_COMPLETE) { gss_display_name(&minor_status, client_name, &display_name, NULL); dwError = VMCAAllocateStringA(display_name.value, &pszUser); BAIL_ON_VMREST_ERROR(dwError); } dwError = VMCARESTMakeKrbAccessToken(ppAccessToken); BAIL_ON_VMREST_ERROR(dwError); cleanup: if (pszUser) { VMCA_SAFE_FREE_MEMORY(pszUser); } return dwError; error: goto cleanup; }