static VOID _VMCAHttpsServiceShutdown( VOID ) { VMCA_LOG_INFO("%s: starting https rest server shutdown:", __FUNCTION__); _VMCARestFreeHandle(gpVMCAHTTPSHandle); gpVMCAHTTPSHandle = NULL; VMCA_LOG_INFO("%s: completed https rest server shutdown:", __FUNCTION__); }
static DWORD InitializeDatabase( VOID ) { DWORD dwError = 0 ; PSTR pszCertDBPath = NULL; dwError = VMCACreateDataDirectory(); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCAGetCertsDBPath(&pszCertDBPath); BAIL_ON_VMCA_ERROR(dwError); VMCA_LOG_INFO( "Initializing database: [%s]", VMCA_SAFE_STRING(pszCertDBPath)); dwError = VmcaDbInitialize(pszCertDBPath); BAIL_ON_VMCA_ERROR(dwError); error: VMCA_SAFE_FREE_STRINGA(pszCertDBPath); return dwError; }
DWORD VMCACheckAccess( handle_t IDL_handle, BOOL bNeedAdminPrivilage ) { DWORD dwError = 0; rpc_authz_cred_handle_t hPriv = { 0 }; DWORD dwProtectLevel = 0; ULONG rpc_status = rpc_s_ok; unsigned char *authPrinc = NULL; rpc_binding_inq_auth_caller( IDL_handle, &hPriv, &authPrinc, &dwProtectLevel, NULL, /* unsigned32 *authn_svc, */ NULL, /* unsigned32 *authz_svc, */ &rpc_status); /* Deny if connection is not encrypted */ if (dwProtectLevel < rpc_c_protect_level_pkt_privacy) { dwError = VMCA_KRB_ACCESS_DENIED; BAIL_ON_VMCA_ERROR(dwError); } /* Deny if no auth identity is provided. */ if (rpc_status == rpc_s_binding_has_no_auth || !authPrinc || !*authPrinc) { dwError = VMCA_KRB_ACCESS_DENIED; BAIL_ON_VMCA_ERROR(dwError); } VMCA_LOG_INFO("VMCACheckAccessKrb: Authenticated user %s", authPrinc); if (bNeedAdminPrivilage) { dwError = VMCALdapAccessCheck(authPrinc, VMCA_ADMINISTRATORS); BAIL_ON_VMCA_ERROR(dwError); } error: if (authPrinc) { rpc_string_free((unsigned_char_t **)&authPrinc, &rpc_status); } return dwError; }
DWORD VMCAGetVecsMachineCert( PSTR* ppszCert, PSTR* ppszKey ) { DWORD dwError = 0; VMCA_LIB_HANDLE plibHandle = NULL; PSTR pszCert = NULL; PSTR pszKey = NULL; if (ppszCert == NULL || ppszKey == NULL) { dwError = VMCA_ARGUMENT_ERROR; goto cleanup; } dwError = VMCAOpenVmAfdClientLib( &plibHandle ); BAIL_ON_VMCA_ERROR(dwError); dwError = _VMCAGetSSLCert( plibHandle, &pszCert, &pszKey ); BAIL_ON_VMCA_ERROR(dwError); *ppszCert = pszCert; *ppszKey = pszKey; VMCA_LOG_INFO("Acquired SSL Cert from VECS"); cleanup: VMCACloseLibrary( plibHandle ); return dwError; error: *ppszCert = NULL; *ppszKey = NULL; VMCA_SAFE_FREE_MEMORY(pszCert); VMCA_SAFE_FREE_MEMORY(pszKey); goto cleanup; }
static PVOID VMCASrvDirSyncThrFunc( PVOID pData ) { DWORD dwError = 0; PVMCA_THREAD_DATA pThrData = (PVMCA_THREAD_DATA)pData; PVMCA_DIR_SYNC_PARAMS pDirSyncParams = NULL; BOOLEAN bShutdown = FALSE; VMCA_LOG_INFO("Directory sync thread starting"); pDirSyncParams = VMCASrvAcquireDirSyncParams( (PVMCA_DIR_SYNC_PARAMS)pThrData->pData); if (!pDirSyncParams) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } while (!bShutdown) { BOOLEAN bSynced = FALSE; dwError = VMCACheckThreadShutdown(pThrData, &bShutdown); BAIL_ON_VMCA_ERROR(dwError); if (!bShutdown) { dwError = VMCASrvUpdateRootCerts(pDirSyncParams, &bSynced); BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCACheckThreadShutdown(pThrData, &bShutdown); BAIL_ON_VMCA_ERROR(dwError); if (!bShutdown) { DWORD dwIntervalSecs = 60; // wait a minute on sync failure if (bSynced) { dwError = VMCASrvGetDirSyncNotifyInterval( pDirSyncParams, &dwIntervalSecs); BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCAWaitNotifyThread(pThrData, dwIntervalSecs); if (dwError == ETIMEDOUT) { dwError = 0; } BAIL_ON_VMCA_ERROR(dwError); } } cleanup: if (pDirSyncParams) { VMCASrvReleaseDirSyncParams(pDirSyncParams); } VMCA_LOG_INFO("Directory sync thread exiting"); return NULL; error: VMCA_LOG_ERROR("Directory sync thread exiting due to error [%u]", dwError); goto cleanup; }
/* * 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; }
DWORD VMCAPolicySNValidate( PVMCA_POLICY pPolicy, PSTR pszPKCS10Request, PVMCA_REQ_CONTEXT pReqContext, PBOOLEAN pbBypass, PBOOLEAN pbIsValid ) { DWORD dwError = 0; DWORD dwOrgNamesLen = 0; DWORD dwIdx = 0; int nCount = 0; PSTR *ppszOrgNames = NULL; PSTR pszAuthBaseDN = NULL; PSTR pszAuthDN = NULL; PVMCA_LDAP_CONTEXT pLd = NULL; BOOLEAN bBypass = FALSE; BOOLEAN bIsValid = FALSE; if (!pPolicy || IsNullOrEmptyString(pszPKCS10Request) || !pReqContext || !pbIsValid) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMCA_ERROR(dwError); } dwError = VMCAOpenLocalLdapServer(&pLd); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCAConvertUPNToDN( pLd, pReqContext->pszAuthPrincipal, &pszAuthDN); BAIL_ON_VMCA_ERROR(dwError); if (VMCAStringCompareA(pPolicy->Rules.SN.pMatch->pszData, VMCA_POLICY_REQ_UPN_DN, TRUE) == 0 && VMCAStringCompareA(pPolicy->Rules.SN.pMatch->pszCondition, VMCA_POLICY_COND_BEGINS, TRUE) == 0) { dwError = VMCAStringCountSubstring( pszAuthDN, pPolicy->Rules.SN.pMatch->pszWith, &nCount); BAIL_ON_VMCA_ERROR(dwError); if (nCount == 0) { VMCA_LOG_INFO( "[%s,%d] CSR requestor (%s) is not a member of policy baseDN...bypassing enforcement", __FUNCTION__, __LINE__, pszAuthDN); bIsValid = TRUE; bBypass = TRUE; goto ret; } } else { VMCA_LOG_INFO( "[%s,%d] Unknown SN policy match rules", __FUNCTION__, __LINE__); dwError = VMCA_POLICY_CONFIG_ERROR; BAIL_ON_VMCA_ERROR(dwError); } for (dwIdx = 0; dwIdx < pPolicy->Rules.SN.dwValidateLen; ++dwIdx) { if (!VMCAStringCompareA( pPolicy->Rules.SN.ppValidate[dwIdx]->pszData, VMCA_POLICY_REQ_CSR_SUBJ_ORGS, TRUE)) { dwError = VMCAOpenSSLGetValuesFromSubjectName( pszPKCS10Request, VMCA_OPENSSL_NID_O, &dwOrgNamesLen, &ppszOrgNames); BAIL_ON_VMCA_ERROR(dwError); if (!VMCAStringCompareA( pPolicy->Rules.SN.ppValidate[dwIdx]->pszWith, VMCA_POLICY_REQ_UPN_RDN, TRUE)) { dwError = VMCAPolicySNMatchAuthOUWithCSR( pszAuthDN, pPolicy->Rules.SN.pMatch->pszWith, dwOrgNamesLen, ppszOrgNames); BAIL_ON_VMCA_ERROR(dwError); } else { VMCA_LOG_INFO( "[%s,%d] Unknown SN policy validate rules", __FUNCTION__, __LINE__); dwError = VMCA_POLICY_CONFIG_ERROR; BAIL_ON_VMCA_ERROR(dwError); } VMCAFreeStringArrayA(ppszOrgNames, dwOrgNamesLen); ppszOrgNames = NULL; dwOrgNamesLen = 0; } else { VMCA_LOG_INFO( "[%s,%d] Unknown SN policy validate rules", __FUNCTION__, __LINE__); dwError = VMCA_POLICY_CONFIG_ERROR; BAIL_ON_VMCA_ERROR(dwError); } } bIsValid = TRUE; ret: *pbBypass = bBypass; *pbIsValid = bIsValid; cleanup: VMCA_SAFE_FREE_STRINGA(pszAuthDN); VMCA_SAFE_FREE_STRINGA(pszAuthBaseDN); VMCAFreeStringArrayA(ppszOrgNames, dwOrgNamesLen); if (pLd) { VMCALdapClose(pLd); pLd = NULL; } return dwError; error: if (pbBypass) { *pbBypass = FALSE; } if (pbIsValid) { *pbIsValid = FALSE; } goto cleanup; }
int main( int argc, char* argv[] ) { DWORD dwError = 0; const char* pszSmNotify = NULL; int notifyFd = -1; int notifyCode = 0; int ret = -1; BOOL bEnableSysLog = FALSE; BOOL bConsoleLogging = FALSE; setlocale(LC_ALL, ""); VMCABlockSelectedSignals(); dwError = VMCAParseArgs(argc, argv, &bEnableSysLog, &bConsoleLogging); BAIL_ON_VMCA_ERROR(dwError); if (bEnableSysLog) { gVMCALogType = VMCA_LOG_TYPE_SYSLOG; } else if (bConsoleLogging) { gVMCALogType = VMCA_LOG_TYPE_CONSOLE; } else { gVMCALogType = VMCA_LOG_TYPE_FILE; } dwError = VMCAInitialize(0, 0); BAIL_ON_VMCA_ERROR(dwError); VMCA_LOG_INFO("VM Certificate Service started."); #ifdef REST_ENABLED #ifndef _WIN32 dwError = VMCARestServiceStartup(); BAIL_ON_VMCA_ERROR(dwError); VMCA_LOG_INFO("VM Certificate ReST Protocol started."); #endif #endif PrintCurrentState(); // interact with likewise service manager (start/stop control) if ((pszSmNotify = getenv("LIKEWISE_SM_NOTIFY")) != NULL) { notifyFd = atoi(pszSmNotify); do { ret = write(notifyFd, ¬ifyCode, sizeof(notifyCode)); } while (ret != sizeof(notifyCode) && errno == EINTR); if (ret < 0) { VMCA_LOG_ERROR("Could not notify service manager: %s (%i)", strerror(errno), errno); dwError = LwErrnoToWin32Error(errno); BAIL_ON_VMCA_ERROR(dwError); } close(notifyFd); } // main thread waits on signals dwError = VMCAHandleSignals(); BAIL_ON_VMCA_ERROR(dwError); VMCA_LOG_INFO("VM Certificate Service exiting..."); cleanup: VMCAShutdown(); #ifdef REST_ENABLED #ifndef _WIN32 VMCARestServiceShutdown(); #endif #endif return (dwError); error: VMCA_LOG_ERROR("VM Certificate exiting due to error [code:%d]", dwError); goto cleanup; }