int sspiValidateServerSecurityLayerOffering(SspiConnContext* pcctx, sasl_client_params_t* cparams, const char *serverin, unsigned serverinlen) { SecPkgContext_Sizes sizes; SECURITY_STATUS status = QueryContextAttributesW(&pcctx->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "QueryContextAttributes(sizes)"); return SASL_FAIL; } unsigned bufferLength = sizes.cbMaxToken + sizes.cbMaxSignature + sizes.cbSecurityTrailer; boost::scoped_array<char> message(new char[bufferLength]); if (serverinlen > bufferLength) { cparams->utils->seterror(cparams->utils->conn, 0, "SSPI: server message is too long"); return SASL_FAIL; } memcpy(message.get(), serverin, serverinlen); SecBuffer wrapBufs[4]; SecBufferDesc wrapBufDesc; wrapBufDesc.cBuffers = 2; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = 0; wrapBufs[0].BufferType = SECBUFFER_DATA; wrapBufs[0].pvBuffer = message.get(); wrapBufs[1].cbBuffer = serverinlen; wrapBufs[1].BufferType = SECBUFFER_STREAM; wrapBufs[1].pvBuffer = message.get(); status = DecryptMessage(&pcctx->ctx, &wrapBufDesc, 0, NULL); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "DecryptMessage"); return SASL_FAIL; } // Validate the server's plaintext message. // Length (as per RFC 4752) if (wrapBufs[0].cbBuffer < 4) { cparams->utils->seterror(cparams->utils->conn, 0, "SSPI: server message is too short"); return SASL_FAIL; } // First bit of first byte set, indicating that the client may elect to use no // security layer. As a client we are uninterested in any of the other features the // server offers and thus we ignore the other bits. if (!(static_cast<char*>(wrapBufs[0].pvBuffer)[0] & 1)) { cparams->utils->seterror(cparams->utils->conn, 0, "SSPI: server does not support the required security layer"); return SASL_BADAUTH; } return SASL_OK; }
BOOL Write(void *buf, size_t len) { BOOL write_ret = WriteFile(hCom, buf, len, 0, (OVERLAPPED*)&write_over); if(!write_ret && GetLastError() != ERROR_IO_PENDING) { HandleLastError("WriteFile"); return FALSE; } return TRUE; }
void iocp_thread() { DWORD bytes_transferred; OVER *over; ULONG key; while(true) { bytes_transferred = 0; BOOL completed = GetQueuedCompletionStatus(hIOCP,&bytes_transferred,&key,(OVERLAPPED**)&over,timeout); if(key == KEY_STOP) { if(log_level) std::cerr << "KEY_STOP" << std::endl; break; } DWORD last_error = completed ? 0 : HandleLastError("GetQueuedCompletionStatus"); if(log_level) fprintf(stderr,"completed[%i] bytes_transferred[%i] over.operation[%i]\n",completed,bytes_transferred,over ? over->operation : 0); if((!completed && last_error == WAIT_TIMEOUT)) { fprintf(stderr,"WAIT_TIMEOUT\n"); } if(timeout.check()) { int i = CancelIo(hCom); fprintf(stderr,"CancelIo = %i\n",i); continue; } if(!completed || !over) { continue; } if(over->operation == OP_READ) { if(completed) { long packet_found = data_received(read_buf,bytes_transferred); if(!packet_found) { Read(read_buf,1); } } } if(over->operation == OP_WRITE) { if(data_sent(bytes_transferred,system::error_code(last_error,system::system_category())) == 0) { Read(read_buf,1); } } } if(log_level) std::cerr << "iocp_thread stopped" << std::endl; }
static HANDLE ComOpen(const char *path, uint32_t baud, uint8_t parity, uint32_t flags) { COMMTIMEOUTS CommTimeouts; DCB dcb; wchar_t baud_s[50]; wsprintf(baud_s, L"baud=%d parity=%s data=8 stop=1",baud, parity == PARITY::EVEN ? "E" : (parity == PARITY::ODD ? "O" : "N" ) ); // get a handle to the port HANDLE hCom = CreateFileA(path, // communication port path GENERIC_READ | GENERIC_WRITE, // read/write types 0, // comm devices must be opened with exclusive access NULL, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING flags, // flags 0); // template must be 0 for comm devices if (hCom == INVALID_HANDLE_VALUE) { HandleLastError("CreateFile"); return hCom; } // set the timeout values CommTimeouts.ReadIntervalTimeout = 1; CommTimeouts.ReadTotalTimeoutMultiplier = 0; CommTimeouts.ReadTotalTimeoutConstant = 0; CommTimeouts.WriteTotalTimeoutMultiplier = 0; CommTimeouts.WriteTotalTimeoutConstant = 0; // configure if (SetCommTimeouts(hCom, &CommTimeouts)) { //if (GetCommState(hCom, &dcb)) //{ //dcb.fOutxCtsFlow = FALSE; //dcb.fRtsControl = RTS_CONTROL_ENABLE; if (BuildCommDCB(baud_s, &dcb)) { SetCommState(hCom, &dcb); // normal operation... continue } //} } return hCom; }
BlockwiseImpl(const char* path,uint32_t baud, uint8_t parity) :read_over(OP_READ),write_over(OP_WRITE),read_size(1) { uint32_t flags = FILE_FLAG_OVERLAPPED; hCom = ComOpen(path, baud, parity, flags); if(INVALID_HANDLE_VALUE == hCom) throw -1; hIOCP = CreateIoCompletionPort(hCom,0,0,0); if(!hIOCP) { HandleLastError("CreateIoCompletionPort"); throw -2; }; io_thread = thread(boost::bind(&BlockwiseImpl::iocp_thread,this)); }
bool Read(void *buf, size_t len) { //ReadFile //If the function succeeds, the return value is nonzero (TRUE). //If the function fails, or is completing asynchronously, the return value is zero (FALSE). To get extended error information, call the GetLastError function. //Note The GetLastError code ERROR_IO_PENDING is not a failure; it designates the read operation is pending completion asynchronously. For more information, see Remarks. //Comments: //On Windows XP (at least) we have ReadFile returning TRUE and still initiating async iocp operation. if(log_level) std::cerr << "BlockwiseImpl::Read " << timeout.time_left()<< std::endl; BOOL read_ret = ReadFile(hCom, buf, len, 0, (OVERLAPPED*)&read_over); if(!read_ret && GetLastError() != ERROR_IO_PENDING) { HandleLastError("ReadFile"); return true; } return false;; }
int sspiClientMechStep(void *conn_context, sasl_client_params_t *cparams, const char *serverin, unsigned serverinlen, sasl_interact_t **prompt_need, const char **clientout, unsigned *clientoutlen, sasl_out_params_t *oparams) { SspiConnContext* pcctx = static_cast<SspiConnContext*>(conn_context); *clientout = NULL; *clientoutlen = 0; if (pcctx->authComplete) { return sspiSendClientAuthzId(pcctx, cparams, serverin, serverinlen, clientout, clientoutlen, oparams); } SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; if (pcctx->haveCtxt) { // If we already have a context, we now have data to send. // Put this data in an inbuf. inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = const_cast<char*>(serverin); inBufs[0].cbBuffer = serverinlen; inBufs[0].BufferType = SECBUFFER_TOKEN; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; ULONG contextAttr = 0; SECURITY_STATUS status = InitializeSecurityContextW(&pcctx->cred, pcctx->haveCtxt ? &pcctx->ctx : NULL, const_cast<wchar_t*>( pcctx->nameToken.c_str()), ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH, 0, SECURITY_NETWORK_DREP, (pcctx->haveCtxt ? &inbuf : NULL), 0, &pcctx->ctx, &outbuf, &contextAttr, NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { HandleLastError(cparams->utils, status, "InitializeSecurityContext"); return SASL_FAIL; } ON_BLOCK_EXIT(FreeContextBuffer, outbuf.pBuffers[0].pvBuffer); pcctx->haveCtxt = true; if (status == SEC_E_OK) { // Send back nothing and wait for the server to reply with the security capabilities *clientout = NULL; *clientoutlen = 0; pcctx->authComplete = true; return SASL_CONTINUE; } char *newoutbuf = static_cast<char*>(cparams->utils->malloc(outBufs[0].cbBuffer)); *clientoutlen = outBufs[0].cbBuffer; memcpy(newoutbuf, outBufs[0].pvBuffer, *clientoutlen); *clientout = newoutbuf; return SASL_CONTINUE; }
int sspiSendClientAuthzId(SspiConnContext* pcctx, sasl_client_params_t* cparams, const char *serverin, unsigned serverinlen, const char **clientout, unsigned *clientoutlen, sasl_out_params_t* oparams) { // Ensure server response is decryptable. int decryptStatus = sspiValidateServerSecurityLayerOffering(pcctx, cparams, serverin, serverinlen); if (decryptStatus != SASL_OK) { return decryptStatus; } // Fill in AUTHID and AUTHZID fields in oparams. int ret = cparams->canon_user(cparams->utils->conn, pcctx->userPlusRealm.c_str(), 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); // Reply to server with security capability and authz name. SecPkgContext_Sizes sizes; SECURITY_STATUS status = QueryContextAttributes(&pcctx->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "QueryContextAttributes(sizes)"); return SASL_FAIL; } // See RFC4752. int plaintextMessageSize = 4 + pcctx->userPlusRealm.size(); boost::scoped_array<char> message(new char[sizes.cbSecurityTrailer + plaintextMessageSize + sizes.cbBlockSize]); char* plaintextMessage = message.get() + sizes.cbSecurityTrailer; plaintextMessage[0] = 1; // LAYER_NONE plaintextMessage[1] = 0; plaintextMessage[2] = 0; plaintextMessage[3] = 0; memcpy(&plaintextMessage[4], pcctx->userPlusRealm.c_str(), pcctx->userPlusRealm.size()); SecBuffer wrapBufs[3]; SecBufferDesc wrapBufDesc; wrapBufDesc.cBuffers = 3; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; wrapBufs[0].BufferType = SECBUFFER_TOKEN; wrapBufs[0].pvBuffer = message.get(); wrapBufs[1].cbBuffer = plaintextMessageSize; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = message.get() + sizes.cbSecurityTrailer; wrapBufs[2].cbBuffer = sizes.cbBlockSize; wrapBufs[2].BufferType = SECBUFFER_PADDING; wrapBufs[2].pvBuffer = message.get() + sizes.cbSecurityTrailer + plaintextMessageSize; status = EncryptMessage(&pcctx->ctx, SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "EncryptMessage"); return SASL_FAIL; } // Create the message to send to server. *clientoutlen = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; char *newoutbuf = static_cast<char*>(cparams->utils->malloc(*clientoutlen)); memcpy(newoutbuf, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); *clientout = newoutbuf; return SASL_OK; }