DWORD VMCARESTHandleVMCARequest( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ* pVMCARequest, PSTR* ppszStatusCode, PSTR* ppszResponsePayload ) { DWORD dwError = 0; //HANDLE_NULL_PARAM(pVMCARequest, dwError); //BAIL_ON_VMCA_ERROR(dwError); if (!strcmp(pVMCARequest->pszMethod,"GET")) { dwError = VMCARESTGetServerVersion( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else { dwError = VMCA_ERROR_INVALID_METHOD; BAIL_ON_VMREST_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; }
DWORD VMCARESTCheckAccess( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ* pVMCARequest ) { DWORD dwError = 0; PVMCA_ACCESS_TOKEN pAccessToken = NULL; dwError = VMCARESTGetAccessToken(pRESTRequest, &pAccessToken); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTCheckGroupPermissions(pAccessToken); BAIL_ON_VMREST_ERROR(dwError); pVMCARequest->pAccessToken = pAccessToken; pAccessToken = NULL; cleanup: return dwError; error: if (pAccessToken) { VMCAFreeAccessToken(pAccessToken); } goto cleanup; }
DWORD VMCARESTCheckGroupPermissions( PVMCA_ACCESS_TOKEN pAccessToken ) { DWORD dwError = 0; int nCounter = 0; int bGroupFound = 0; if (!pAccessToken || !pAccessToken->tokenType) { dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMREST_ERROR(dwError); } switch(pAccessToken->tokenType) { case VMCA_AUTHORIZATION_TYPE_BEARER_TOKEN: if (!pAccessToken->pszGroups || pAccessToken->dwGroupSize == 0 ) { dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMREST_ERROR(dwError); } else { for (nCounter = 0; nCounter < pAccessToken->dwGroupSize; nCounter++) { if (strstr(pAccessToken->pszGroups[nCounter], VMCA_GROUP_PERMISSION_STRING)) { bGroupFound = 1; } } if (!bGroupFound) { dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMREST_ERROR(dwError); } } break; case VMCA_AUTHORIZATION_TOKEN_TYPE_KRB: if (!pAccessToken->bKrbTicketValid || *pAccessToken->bKrbTicketValid != 1 ) { dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMREST_ERROR(dwError); } break; default: dwError = ERROR_ACCESS_DENIED; BAIL_ON_VMREST_ERROR(dwError); break; } error: return dwError; }
DWORD VMCAHandleHttpRequest( PVMREST_HANDLE pRESTHandle, PREST_REQUEST pRequest, PREST_RESPONSE* ppResponse, uint32_t paramsCount ) { DWORD dwError = 0; PSTR pszStatusCode = NULL; PSTR pszResponsePayload = NULL; VMCA_HTTP_REQ_OBJ* pVMCARequest = NULL; dwError = VMCARESTParseHttpHeader(pRequest, &pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTGetPayload(pRESTHandle, pRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTExecuteHttpURI( pRequest, pVMCARequest, &pszStatusCode, &pszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTSetResponseHeaders(ppResponse, pszStatusCode); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTSetResponsePayload( pRESTHandle, ppResponse, pszResponsePayload); BAIL_ON_VMREST_ERROR(dwError); cleanup: VMCA_SAFE_FREE_MEMORY(pszResponsePayload); VMCA_SAFE_FREE_MEMORY(pszStatusCode); if (pVMCARequest) { VMCAFreeAccessToken(pVMCARequest->pAccessToken); VMCA_SAFE_FREE_MEMORY(pVMCARequest->pszPayload); VMCA_SAFE_FREE_MEMORY(pVMCARequest); } return dwError; error: if (dwError == EACCES) { dwError = VMCARESTRequestNegotiateAuth( pRESTHandle, pRequest, ppResponse, NULL); } goto cleanup; }
DWORD VMCARESTParseHttpHeader( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ** ppVMCARequest ) { DWORD dwError = 0; PSTR pszBuff = NULL; VMCA_HTTP_REQ_OBJ* pVMCARequest; HANDLE_NULL_PARAM(ppVMCARequest, dwError); BAIL_ON_VMCA_ERROR(dwError); dwError = VMCAAllocateMemory( sizeof(VMCA_HTTP_REQ_OBJ), (PVOID*) &pVMCARequest ); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTGetHttpMethod(pRESTRequest, &pszBuff); BAIL_ON_VMREST_ERROR(dwError); pVMCARequest->pszMethod = pszBuff; // TRUE - Request c-rest-engine to decode the URI dwError = VmRESTGetHttpURI(pRESTRequest, TRUE, &pszBuff); BAIL_ON_VMREST_ERROR(dwError); pVMCARequest->pszUri = pszBuff; dwError = VmRESTGetHttpVersion(pRESTRequest, &pszBuff); BAIL_ON_VMREST_ERROR(dwError); pVMCARequest->pszVer = pszBuff; dwError = VmRESTGetHttpHeader(pRESTRequest,"Content-Length", &pszBuff); BAIL_ON_VMREST_ERROR(dwError); pVMCARequest->pszContentLength = pszBuff; *ppVMCARequest = pVMCARequest; cleanup: return dwError; error: VMCA_SAFE_FREE_STRINGA(pVMCARequest->pszMethod); VMCA_SAFE_FREE_STRINGA(pVMCARequest->pszUri); VMCA_SAFE_FREE_STRINGA(pVMCARequest->pszVer); VMCA_SAFE_FREE_STRINGA(pszBuff); VMCA_SAFE_FREE_MEMORY(pVMCARequest); goto cleanup; }
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 VMCARestServiceStartup( VOID ) { DWORD dwError = 0; dwError = _VMCAHttpServiceStartup(); BAIL_ON_VMREST_ERROR(dwError); dwError = _VMCAHttpsServiceStartup(); //soft fail if (dwError != 0) { VMCA_LOG_ERROR("%s: failure while starting HTTPS service(expected before promote), error: %d", __FUNCTION__, dwError); dwError = 0; } cleanup: return dwError; error: VMCA_LOG_ERROR("%s: failure while starting REST service, error: %d", __FUNCTION__, dwError); goto cleanup; }
DWORD VMCARESTSetResponseHeaders( PREST_RESPONSE* ppResponse, PSTR pszStatusCode ) { DWORD dwError = 0; dwError = VmRESTSetHttpHeader(ppResponse, "VMware", "VMCA"); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpHeader(ppResponse, "Location", "United States"); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpStatusCode(ppResponse, pszStatusCode); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpStatusVersion(ppResponse,"HTTP/1.1"); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpReasonPhrase(ppResponse,"OK"); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpHeader(ppResponse, "Unix", "Linux"); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetHttpHeader(ppResponse, "Connection", "close"); BAIL_ON_VMREST_ERROR(dwError); cleanup: return dwError; error: goto cleanup; }
DWORD VMCARESTHandleRootRequest( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ* pVMCARequest, PSTR* ppszStatusCode, PSTR* ppszResponsePayload ) { DWORD dwError = 0; //HANDLE_NULL_PARAM(pVMCARequest, dwError); //BAIL_ON_VMCA_ERROR(dwError); if (!strcmp(pVMCARequest->pszMethod,"GET")) { dwError = VMCARESTGetRootCACertificate( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (!strcmp(pVMCARequest->pszMethod,"POST")) { dwError = VMCARESTCheckAccess(pRESTRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTAddRootCertificate( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (!strcmp(pVMCARequest->pszMethod,"PUT")) { dwError = VMCARESTCheckAccess(pRESTRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTAddRootCertificate( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else { dwError = VMCA_ERROR_INVALID_METHOD; BAIL_ON_VMREST_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; }
static DWORD server_acquire_creds( PSTR service_name, gss_OID_desc *mech, gss_cred_id_t *server_creds ) { DWORD dwError = 0; gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER; gss_name_t server_name = GSS_C_NO_NAME; OM_uint32 min = 0; OM_uint32 maj = 0; gss_OID_desc mech_oid_array[1]; gss_OID_set_desc desired_mech = {0}; if (mech) { desired_mech.count = 1; desired_mech.elements = mech_oid_array; desired_mech.elements[0] = *mech; } if (IsNullOrEmptyString(service_name)) { dwError = EACCES; BAIL_ON_VMREST_ERROR(dwError); } name_buf.value = service_name; name_buf.length = strlen(name_buf.value) + 1; maj = gss_import_name(&min, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, &server_name); //TODO: insert show error maj = gss_acquire_cred( &min, server_name, 0, &desired_mech, GSS_C_ACCEPT, server_creds, NULL, NULL ); //TODO: insert show error (void) gss_release_name(&min, &server_name); cleanup: return (DWORD) maj; error: if (maj) { maj = min ? min : maj; } if (server_name) { gss_release_name(&min, &server_name); } 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; }
static DWORD _VMCAHttpsServiceStartup( VOID ) { DWORD dwError = 0; DWORD iter = 0; DWORD endPointCnt = 0; REST_CONF config = {0}; PSTR pszCert = NULL; PSTR pszKey = NULL; DWORD dwPort = 0; PREST_PROCESSOR pHandlers = &sVmcaRestHandlers; PVMREST_HANDLE pHTTPSHandle = NULL; (VOID)VMCAGetRegKeyValueDword( VMCA_KEY_PARAMETERS,//VMCA_CONFIG_PARAMETER_KEY_PATH, VMCA_HTTPS_PORT_REG_KEY, &dwPort, VMCA_HTTPS_PORT_NUM ); // port value '0' indicates don't start HTTPS service if (dwPort == 0) { goto cleanup; } config.serverPort = dwPort; config.connTimeoutSec = VMCA_REST_CONN_TIMEOUT_SEC; config.maxDataPerConnMB = VMCA_MAX_DATA_PER_CONN_MB; config.pSSLContext = NULL; config.nWorkerThr = VMCA_REST_WORKER_TH_CNT; config.nClientCnt = VMCA_REST_CLIENT_CNT; config.SSLCtxOptionsFlag = 0; config.pszSSLCertificate = NULL; config.pszSSLKey = NULL; config.pszSSLCipherList = NULL; config.pszDebugLogFile = NULL; config.pszDaemonName = VMCA_DAEMON_NAME; config.isSecure = TRUE; config.useSysLog = TRUE; config.debugLogLevel = VMREST_LOG_LEVEL_ERROR; //Get Certificate and Key from VECS and Set it to Rest Engine dwError = VMCAGetVecsMachineCert(&pszCert, &pszKey); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTInit(&config, &pHTTPSHandle); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetSSLInfo(pHTTPSHandle, pszCert, VMCAStringLenA(pszCert)+1, SSL_DATA_TYPE_CERT); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTSetSSLInfo(pHTTPSHandle, pszKey, VMCAStringLenA(pszKey)+1, SSL_DATA_TYPE_KEY); BAIL_ON_VMREST_ERROR(dwError); endPointCnt = ARRAY_SIZE(restEndPoints); for (iter = 0; iter < endPointCnt; iter++) { dwError = VmRESTRegisterHandler( pHTTPSHandle, restEndPoints[iter], pHandlers, NULL); BAIL_ON_VMREST_ERROR(dwError); } dwError = VmRESTStart(pHTTPSHandle); BAIL_ON_VMREST_ERROR(dwError); gpVMCAHTTPSHandle = pHTTPSHandle; cleanup: VMCA_SAFE_FREE_MEMORY(pszCert); VMCA_SAFE_FREE_MEMORY(pszKey); return dwError; error: _VMCARestFreeHandle(pHTTPSHandle); VMCA_LOG_ERROR("%s: failure while starting REST HTTPS service, error: %d", __FUNCTION__, dwError); goto cleanup; }
DWORD VMCARESTExecuteHttpURI( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ* pVMCARequest, PSTR* ppszStatusCode, PSTR* ppszResponsePayload ) { DWORD dwError = 0; PSTR pszStatusCode = NULL; PSTR pszResponsePayload = NULL; HANDLE_NULL_PARAM(pVMCARequest, dwError); BAIL_ON_VMCA_ERROR(dwError); if (!pVMCARequest) { dwError = VMCA_ERROR_INVALID_URI; BAIL_ON_VMREST_ERROR(dwError); } if (strcasestr(pVMCARequest->pszUri,VMCA_CRL_URI) != NULL) { dwError = VMCARESTHandleCRLRequest( pRESTRequest, pVMCARequest, &pszStatusCode, &pszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (strcasestr(pVMCARequest->pszUri,VMCA_ROOT_URI) != NULL) { dwError = VMCARESTHandleRootRequest( pRESTRequest, pVMCARequest, &pszStatusCode, &pszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (strcasestr(pVMCARequest->pszUri,VMCA_CERTS_URI) != NULL) { dwError = VMCARESTHandleCertRequest( pRESTRequest, pVMCARequest, &pszStatusCode, &pszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (strcasestr(pVMCARequest->pszUri,VMCA_URI) != NULL) { dwError = VMCARESTHandleVMCARequest( pRESTRequest, pVMCARequest, &pszStatusCode, &pszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else { dwError = VMCA_ERROR_INVALID_URI; BAIL_ON_VMREST_ERROR(dwError); } *ppszStatusCode = pszStatusCode; *ppszResponsePayload = pszResponsePayload; cleanup: return dwError; error: goto cleanup; }
DWORD VMCARESTHandleCertRequest( PREST_REQUEST pRESTRequest, VMCA_HTTP_REQ_OBJ* pVMCARequest, PSTR* ppszStatusCode, PSTR* ppszResponsePayload ) { DWORD dwError = 0; PSTR pszKey1 = NULL; PSTR pszVal1 = NULL; PSTR pszKey2 = NULL; PSTR pszVal2 = NULL; PSTR pszFlag = NULL; PSTR pszNum = NULL; //HANDLE_NULL_PARAM(pVMCARequest, dwError); //BAIL_ON_VMCA_ERROR(dwError); if (!strcmp(pVMCARequest->pszMethod,"GET")) { dwError = VMCARESTCheckAccess(pRESTRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTGetParamsByIndex(pRESTRequest, 2, 1, &pszKey2, &pszVal2); BAIL_ON_VMREST_ERROR(dwError); dwError = VmRESTGetParamsByIndex(pRESTRequest, 2, 2, &pszKey1, &pszVal1); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCAHandleEnumCertsParam( pszKey1, pszVal1, pszKey2, pszVal2, &pszFlag, &pszNum); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTEnumCertificates( *pVMCARequest, pszFlag, pszNum, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (!strcmp(pVMCARequest->pszMethod,"PUT")) { dwError = VMCARESTCheckAccess(pRESTRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTGetSignedCertificate( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else if (!strcmp(pVMCARequest->pszMethod,"DELETE")) { dwError = VMCARESTCheckAccess(pRESTRequest, pVMCARequest); BAIL_ON_VMREST_ERROR(dwError); dwError = VMCARESTRevokeCertificate( *pVMCARequest, ppszStatusCode, ppszResponsePayload ); BAIL_ON_VMREST_ERROR(dwError); } else { dwError = VMCA_ERROR_INVALID_METHOD; BAIL_ON_VMREST_ERROR(dwError); } cleanup: //VMCA_SAFE_FREE_MEMORY(pszKey1); //VMCA_SAFE_FREE_MEMORY(pszKey2); //VMCA_SAFE_FREE_MEMORY(pszVal1); //VMCA_SAFE_FREE_MEMORY(pszVal2); return dwError; error: goto cleanup; }