SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData) { SecBufferDesc OutBuffer, InBuffer; SecBuffer InBuffers[2], OutBuffers; DWORD dwSSPIFlags, dwSSPIOutFlags, cbData, cbIoBuffer; TimeStamp tsExpiry; SECURITY_STATUS rc; PUCHAR IoBuffer; BOOL fDoRead; MARIADB_TLS *ctls= pvio->ctls; SC_CTX *sctx= (SC_CTX *)ctls->ssl; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* Allocate data buffer */ if (!(IoBuffer = LocalAlloc(LMEM_FIXED, SC_IO_BUFFER_SIZE))) return SEC_E_INSUFFICIENT_MEMORY; cbIoBuffer = 0; fDoRead = InitialRead; /* handshake loop: We will leave a handshake is finished or an error occurs */ rc = SEC_I_CONTINUE_NEEDED; while (rc == SEC_I_CONTINUE_NEEDED || rc == SEC_E_INCOMPLETE_MESSAGE || rc == SEC_I_INCOMPLETE_CREDENTIALS ) { /* Read data */ if (rc == SEC_E_INCOMPLETE_MESSAGE || !cbIoBuffer) { if(fDoRead) { cbData = (DWORD)pvio->methods->read(pvio, IoBuffer + cbIoBuffer, (size_t)(SC_IO_BUFFER_SIZE - cbIoBuffer)); if (cbData == SOCKET_ERROR || cbData == 0) { rc = SEC_E_INTERNAL_ERROR; break; } cbIoBuffer += cbData; } else fDoRead = TRUE; } /* input buffers First buffer stores data received from server. leftover data will be stored in second buffer with BufferType SECBUFFER_EXTRA */ InBuffers[0].pvBuffer = IoBuffer; InBuffers[0].cbBuffer = cbIoBuffer; InBuffers[0].BufferType = SECBUFFER_TOKEN; InBuffers[1].pvBuffer = NULL; InBuffers[1].cbBuffer = 0; InBuffers[1].BufferType = SECBUFFER_EMPTY; InBuffer.cBuffers = 2; InBuffer.pBuffers = InBuffers; InBuffer.ulVersion = SECBUFFER_VERSION; /* output buffer */ OutBuffers.pvBuffer = NULL; OutBuffers.BufferType= SECBUFFER_TOKEN; OutBuffers.cbBuffer = 0; OutBuffer.cBuffers = 1; OutBuffer.pBuffers = &OutBuffers; OutBuffer.ulVersion = SECBUFFER_VERSION; rc = InitializeSecurityContextA(&sctx->CredHdl, &sctx->ctxt, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &InBuffer, 0, NULL, &OutBuffer, &dwSSPIOutFlags, &tsExpiry ); if (rc == SEC_E_OK || rc == SEC_I_CONTINUE_NEEDED || FAILED(rc) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if(OutBuffers.cbBuffer && OutBuffers.pvBuffer) { cbData= (DWORD)pvio->methods->write(pvio, (uchar *)OutBuffers.pvBuffer, (size_t)OutBuffers.cbBuffer); if(cbData == SOCKET_ERROR || cbData == 0) { FreeContextBuffer(OutBuffers.pvBuffer); DeleteSecurityContext(&sctx->ctxt); return SEC_E_INTERNAL_ERROR; } /* Free output context buffer */ FreeContextBuffer(OutBuffers.pvBuffer); OutBuffers.pvBuffer = NULL; } } /* check if we need to read more data */ switch (rc) { case SEC_E_INCOMPLETE_MESSAGE: /* we didn't receive all data, so just continue loop */ continue; break; case SEC_E_OK: /* handshake completed, but we need to check if extra data was sent (which contains encrypted application data) */ if (InBuffers[1].BufferType == SECBUFFER_EXTRA) { if (!(pExtraData->pvBuffer= LocalAlloc(0, InBuffers[1].cbBuffer))) return SEC_E_INSUFFICIENT_MEMORY; MoveMemory(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer ); pExtraData->BufferType = SECBUFFER_TOKEN; pExtraData->cbBuffer = InBuffers[1].cbBuffer; } else { pExtraData->BufferType= SECBUFFER_EMPTY; pExtraData->pvBuffer= NULL; pExtraData->cbBuffer= 0; } break; case SEC_I_INCOMPLETE_CREDENTIALS: /* Provided credentials didn't contain a valid client certificate. We will try to connect anonymously, using current credentials */ fDoRead= FALSE; rc= SEC_I_CONTINUE_NEEDED; continue; break; default: if (FAILED(rc)) { ma_schannel_set_sec_error(pvio, rc); goto loopend; } break; } if ( InBuffers[1].BufferType == SECBUFFER_EXTRA ) { MoveMemory( IoBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer ); cbIoBuffer = InBuffers[1].cbBuffer; } cbIoBuffer = 0; } loopend: if (FAILED(rc)) DeleteSecurityContext(&sctx->ctxt); LocalFree(IoBuffer); return rc; }
INT auth_sspi_client_step(sspi_client_state* state, SEC_CHAR* challenge) { SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; ULONG ignored; SECURITY_STATUS status = AUTH_GSS_CONTINUE; SIZE_T len; if (state->response != NULL) { free(state->response); state->response = NULL; } inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = NULL; inBufs[0].cbBuffer = 0; inBufs[0].BufferType = SECBUFFER_TOKEN; if (state->haveCtx) { inBufs[0].pvBuffer = base64_decode(challenge, &len); inBufs[0].cbBuffer = (ULONG)len; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; Py_BEGIN_ALLOW_THREADS status = InitializeSecurityContextA(/* CredHandle */ &state->cred, /* CtxtHandle (NULL on first call) */ state->haveCtx ? &state->ctx : NULL, /* Service Principal Name */ state->spn, /* Flags */ ISC_REQ_ALLOCATE_MEMORY | state->flags, /* Always 0 */ 0, /* Target data representation */ SECURITY_NETWORK_DREP, /* Challenge (NULL on first call) */ state->haveCtx ? &inbuf : NULL, /* Always 0 */ 0, /* CtxtHandle (Set on first call) */ &state->ctx, /* Output */ &outbuf, /* Context attributes */ &ignored, /* Expiry (We don't use this) */ NULL); Py_END_ALLOW_THREADS if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { set_krberror(status, "InitializeSecurityContext"); status = AUTH_GSS_ERROR; goto done; } state->haveCtx = 1; if (outBufs[0].cbBuffer) { state->response = base64_encode(outBufs[0].pvBuffer, outBufs[0].cbBuffer); } if (status == SEC_E_OK) { /* Get authenticated username. */ SecPkgContext_Names names; status = QueryContextAttributes( &state->ctx, SECPKG_ATTR_NAMES, &names); if (status != SEC_E_OK) { set_krberror(status, "QueryContextAttributes"); status = AUTH_GSS_ERROR; goto done; } state->username = _strdup(names.sUserName); if (state->username == NULL) { PyErr_SetNone(PyExc_MemoryError); FreeContextBuffer(names.sUserName); status = AUTH_GSS_ERROR; goto done; } FreeContextBuffer(names.sUserName); status = AUTH_GSS_COMPLETE; } else { status = AUTH_GSS_CONTINUE; } done: if (inBufs[0].pvBuffer) { free(inBufs[0].pvBuffer); } if (outBufs[0].pvBuffer) { FreeContextBuffer(outBufs[0].pvBuffer); } return status; }
OM_uint32 gss_init_sec_context ( OM_uint32 *minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, gss_name_t target_name, gss_OID mech_type, int req_flags, int time_req, gss_channel_bindings_t input_channel_bindings, gss_buffer_t input_token, gss_OID *actual_mech_types, gss_buffer_t output_token, int *ret_flags, OM_int32 *time_rec) { SecPkgInfoA *secPackInfo = NULL; gss_cred_id_t credhandle={0}; gss_ctx_id_t *pctx; // SECBUFFER_TOKEN // This buffer type is used to indicate the security token portion of the message. // This is read-only for input parameters or read/write for output parameters. SecBuffer InputBuf[1] = {input_token?input_token->length:0,SECBUFFER_TOKEN,input_token?input_token->value:0}; SecBuffer OutputBuf[1] = {0,SECBUFFER_TOKEN,NULL}; SecBufferDesc InBuffer[1] = {SECBUFFER_VERSION, 1, InputBuf}; SecBufferDesc OutBuffer[1] = {SECBUFFER_VERSION, 1, OutputBuf}; OM_uint32 ret; TimeStamp tr; unsigned long rf; SECURITY_STATUS retq; // // Previously gserver passed ISC_REQ_ALLOCATE_MEMORY to InitializeSecurityContext // but it returns SEC_E_BUFFER_TOO_SMALL - I think this is because // only Digest and Schannel will allocate output buffers for you, even though the documentation // doesn't make that clear for InitializeSecurityContext (see AcquireCredentialsHandle doco). // if((retq=QuerySecurityPackageInfoA( "Kerberos", &secPackInfo )) != SEC_E_OK) return 0; OutputBuf->BufferType = SECBUFFER_TOKEN; // preping a token here OutputBuf->cbBuffer = secPackInfo->cbMaxToken; OutputBuf->pvBuffer = malloc(secPackInfo->cbMaxToken); if(claimant_cred_handle.dwLower==0 && claimant_cred_handle.dwUpper==0) { static gss_cred_id_t global_client_cred={0}; if(global_client_cred.dwLower==0 || global_client_cred.dwUpper==0) { ret = AcquireCredentialsHandleA(NULL,"Kerberos",SECPKG_CRED_OUTBOUND,NULL,NULL,NULL,NULL,&global_client_cred,NULL); if(ret) return ret; } credhandle = global_client_cred; } else credhandle = claimant_cred_handle; if(context_handle->dwLower==0 && context_handle->dwUpper==0) pctx = NULL; else pctx = context_handle; // note - only Digest and Schannel will allocate output buffers for you. // so kerberos and other security contexts should not use ISC_REQ_ALLOCATE_MEMORY // and also should not free them by calling the FreeContextBuffer function. ret = InitializeSecurityContextA( &credhandle, pctx, target_name, req_flags, 0, SECURITY_NETWORK_DREP, input_token?InBuffer:NULL,0, pctx?NULL:context_handle, OutBuffer, &rf, &tr); // really need to return if that didn't work... if (ret != SEC_E_OK /*GSS_S_COMPLETE*/ && ret != SEC_I_CONTINUE_NEEDED /*GSS_S_CONTINUE_NEEDED*/ ) { free(OutputBuf->pvBuffer); OutputBuf->pvBuffer = NULL; return ret; } output_token->length = OutputBuf[0].cbBuffer; output_token->value = malloc((OutputBuf[0].cbBuffer)+100); if (output_token->value!=NULL) memcpy(output_token->value,OutputBuf[0].pvBuffer,output_token->length); // only call this if InitializeSecurityContext successfully created the buffers for us // FreeContextBuffer(OutBuffer); // manually made the memory, so manually release it... free(OutputBuf->pvBuffer); OutputBuf->pvBuffer = NULL; *minor_status = 0; if(time_rec) *time_rec=tr.LowPart; if(ret_flags) *ret_flags=rf; return ret; }
bool CSSPIHandler::ClientStep(bool& more, const char *inputBuffer, size_t inputSize) { SECURITY_STATUS rcISC; DWORD ctxAttr; // input and output buffers TimeStamp useBefore; SecBufferDesc obd,ibd; SecBuffer ob[1], ib[2]; m_outputBuffer.resize(m_secPackInfo->cbMaxToken); obd.ulVersion = SECBUFFER_VERSION; obd.cBuffers = 1; obd.pBuffers = ob; // just one buffer ob[0].cbBuffer = m_secPackInfo->cbMaxToken; ob[0].pvBuffer = (void*)m_outputBuffer.data(); ob[0].BufferType = SECBUFFER_TOKEN; // preping a token here if(inputBuffer) { // prepare to get the server's response ibd.ulVersion = SECBUFFER_VERSION; ibd.cBuffers = 1; ibd.pBuffers = ib; // just one buffer ib[0].cbBuffer=(DWORD)inputSize; ib[0].pvBuffer =(void*)inputBuffer; ib[0].BufferType = SECBUFFER_TOKEN; // preping a token here } rcISC = InitializeSecurityContextA( &m_credHandle, m_haveContext? &m_contextHandle:NULL, (char*)m_tokenSource, m_ctxReq, 0, SECURITY_NATIVE_DREP, m_haveContext?&ibd:NULL, 0, &m_contextHandle, &obd, &ctxAttr, &useBefore ); if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE || rcISC == SEC_I_COMPLETE_NEEDED ) { CompleteAuthToken( &m_contextHandle, &obd ); if ( rcISC == SEC_I_COMPLETE_NEEDED ) rcISC = SEC_E_OK; else if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE ) rcISC = SEC_I_CONTINUE_NEEDED; } if(rcISC<0) { m_rc = rcISC; more=false; return false; } m_outputBuffer.resize(ob[0].cbBuffer); if ( rcISC != SEC_I_CONTINUE_NEEDED ) { m_rc = rcISC; if ( rcISC != SEC_E_OK ) m_haveContext = false; else { QueryContextAttributes(&m_contextHandle,SECPKG_ATTR_SIZES,&m_secSizes); m_haveContext = true; } more=false; return m_haveContext; } m_haveContext = true; more=true; return true; }
BOOL GenClientContext (BYTE *pIn, DWORD cbIn, BYTE *pOut, DWORD *pcbOut, BOOL *pfDone, SEC_CHAR *pszTarget, CredHandle *hCred, struct _SecHandle *hCtxt) { SECURITY_STATUS ss; TimeStamp Lifetime; SecBufferDesc OutBuffDesc; SecBuffer OutSecBuff; SecBufferDesc InBuffDesc; SecBuffer InSecBuff; ULONG ContextAttributes; SEC_CHAR lpPackageName[1024]; _SEC_WINNT_AUTH_IDENTITY auth_data; PCHAR pUserName = NULL; DWORD cbUserName = 0; DWORD dw; if( NULL == pIn ) { GetUserNameExA(NameSamCompatible, pUserName, &cbUserName); pUserName = (PCHAR) malloc (cbUserName); GetUserNameExA(NameSamCompatible, pUserName, &cbUserName); cbUserName = (DWORD)((int)strchr(pUserName,'\\')); *(char *)cbUserName = 0; auth_data.Domain = (unsigned char *)pUserName; auth_data.User = (unsigned char *)((int)cbUserName+1); printf("%s@%s\n",(char *)auth_data.User,(char *)auth_data.Domain); auth_data.UserLength = strlen((char *)auth_data.User); auth_data.DomainLength = strlen((char *)auth_data.Domain); auth_data.Password = NULL; auth_data.PasswordLength = 0; auth_data.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; lstrcpynA (lpPackageName, "NTLM", 5); ss = AcquireCredentialsHandleA (NULL, lpPackageName, SECPKG_CRED_OUTBOUND, NULL, &auth_data, NULL, NULL, hCred, &Lifetime); if (!(SEC_SUCCESS (ss))) MyHandleError("AcquireCreds failed "); } OutBuffDesc.ulVersion = 0; OutBuffDesc.cBuffers = 1; OutBuffDesc.pBuffers = &OutSecBuff; OutSecBuff.cbBuffer = *pcbOut; OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.pvBuffer = pOut; if (pIn) { InBuffDesc.ulVersion = 0; InBuffDesc.cBuffers = 1; InBuffDesc.pBuffers = &InSecBuff; InSecBuff.cbBuffer = cbIn; InSecBuff.BufferType = SECBUFFER_TOKEN; InSecBuff.pvBuffer = pIn; ss = InitializeSecurityContextA (hCred, hCtxt, pszTarget, ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, hCtxt, &OutBuffDesc, &ContextAttributes, &Lifetime); } else { ss = InitializeSecurityContextA (hCred, NULL, pszTarget, ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, NULL, 0, hCtxt, &OutBuffDesc, &ContextAttributes, &Lifetime); } if (!SEC_SUCCESS (ss)) MyHandleError ("InitializeSecurityContext failed " ); *pcbOut = OutSecBuff.cbBuffer; *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) ||(SEC_I_COMPLETE_AND_CONTINUE == ss)); return TRUE; }