bool ZStreamRWCon_SSL_Win::pConnect() { SecBuffer outSB[1]; outSB[0].cbBuffer = 0; outSB[0].pvBuffer = nullptr; outSB[0].BufferType = SECBUFFER_TOKEN; SecBufferDesc outSBD; outSBD.cBuffers = 1; outSBD.pBuffers = outSB; outSBD.ulVersion = SECBUFFER_VERSION; DWORD attributes; if (SEC_I_CONTINUE_NEEDED != spPSFT->InitializeSecurityContextA( &fCredHandle, nullptr, nullptr, // other party, needed if we're verifying spRequirements, 0, // Reserved1 SECURITY_NATIVE_DREP, nullptr, 0, // Reserved2 &fCtxtHandle, &outSBD, &attributes, nullptr)) { return false; } spWriteFreeFlush(outSB[0], fStreamW); return this->pHandshake(); }
/* * Wrapper arround initializeSecurityContext. Supplies several * default parameters as well as logging in case of errors. */ static SECURITY_STATUS initializeSecurityContext(CredHandle * credentials, CtxtHandle * context, char *spn, ULONG contextReq, SecBufferDesc * inBuffer, CtxtHandle * newContext, SecBufferDesc * outBuffer) { ULONG contextAttributes; SECURITY_STATUS status; status = pSFT->InitializeSecurityContextA(credentials, context, spn, contextReq, 0, SECURITY_NETWORK_DREP, inBuffer, 0, newContext, outBuffer, &contextAttributes, NULL); if (!SEC_SUCCESS(status)) { if (status == SEC_E_INVALID_TOKEN) { NE_DEBUG(NE_DBG_HTTPAUTH, "InitializeSecurityContext [fail] SEC_E_INVALID_TOKEN.\n"); } else if (status == SEC_E_UNSUPPORTED_FUNCTION) { NE_DEBUG(NE_DBG_HTTPAUTH, "InitializeSecurityContext [fail] SEC_E_UNSUPPORTED_FUNCTION.\n"); } else { NE_DEBUG(NE_DBG_HTTPAUTH, "InitializeSecurityContext [fail] [%x].\n", status); } } return status; }
static int tds_sspi_handle_next(TDSSOCKET * tds, struct tds_authentication * tds_auth, size_t len) { SecBuffer in_buf, out_buf; SecBufferDesc in_desc, out_desc; SECURITY_STATUS status; ULONG attrs; TimeStamp ts; TDS_UCHAR *auth_buf; TDSSSPIAUTH *auth = (TDSSSPIAUTH *) tds_auth; if (len < 32 || len > NTLMBUF_LEN) return TDS_FAIL; auth_buf = (TDS_UCHAR *) malloc(len); if (!auth_buf) return TDS_FAIL; tds_get_n(tds, auth_buf, (int)len); in_desc.ulVersion = out_desc.ulVersion = SECBUFFER_VERSION; in_desc.cBuffers = out_desc.cBuffers = 1; in_desc.pBuffers = &in_buf; out_desc.pBuffers = &out_buf; in_buf.BufferType = SECBUFFER_TOKEN; in_buf.pvBuffer = auth_buf; in_buf.cbBuffer = (ULONG)len; out_buf.BufferType = SECBUFFER_TOKEN; out_buf.pvBuffer = auth->tds_auth.packet; out_buf.cbBuffer = NTLMBUF_LEN; status = sec_fn->InitializeSecurityContextA(&auth->cred, &auth->cred_ctx, auth->sname, ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION, 0, SECURITY_NETWORK_DREP, &in_desc, 0, &auth->cred_ctx, &out_desc, &attrs, &ts); free(auth_buf); if (status != SEC_E_OK) return TDS_FAIL; if (out_buf.cbBuffer == 0) return TDS_SUCCEED; tds_put_n(tds, auth->tds_auth.packet, out_buf.cbBuffer); return tds_flush_packet(tds); }
void ZStreamRWCon_SSL_Win::Imp_SendDisconnect() { ZAcqMtx acq(fMtx_W); if (not fSendOpen) return; fSendOpen = false; SecBuffer outSB[1]; outSB[0].cbBuffer = 0; outSB[0].pvBuffer = nullptr; outSB[0].BufferType= SECBUFFER_TOKEN; SecBufferDesc outSBD; outSBD.cBuffers = 1; outSBD.pBuffers = outSB; outSBD.ulVersion = SECBUFFER_VERSION; DWORD attributes; SECURITY_STATUS scRet = spPSFT->InitializeSecurityContextA( &fCredHandle, &fCtxtHandle, nullptr, spRequirements, 0, // Reserved1 SECURITY_NATIVE_DREP, nullptr, 0, // Reserved2 nullptr, &outSBD, &attributes, nullptr); if (FAILED(scRet)) return; spWriteFreeFlush(outSB[0], fStreamW); }
/** * Build a SSPI packet to send to server * @param tds A pointer to the TDSSOCKET structure managing a client/server operation. */ TDSAUTHENTICATION * tds_sspi_get_auth(TDSSOCKET * tds) { SecBuffer buf; SecBufferDesc desc; SECURITY_STATUS status; ULONG attrs; TimeStamp ts; SEC_WINNT_AUTH_IDENTITY identity; const char *p, *user_name, *server_name; TDSSSPIAUTH *auth; TDSCONNECTION *connection = tds->connection; /* check connection */ if (!connection) return NULL; if (!tds_init_secdll()) return NULL; /* parse username/password informations */ memset(&identity, 0, sizeof(identity)); user_name = tds_dstr_cstr(&connection->user_name); if ((p = strchr(user_name, '\\')) != NULL) { identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; identity.Password = (void *) tds_dstr_cstr(&connection->password); identity.PasswordLength = tds_dstr_len(&connection->password); identity.Domain = (void *) user_name; identity.DomainLength = p - user_name; user_name = p + 1; identity.User = (void *) user_name; identity.UserLength = strlen(user_name); } auth = (TDSSSPIAUTH *) calloc(1, sizeof(TDSSSPIAUTH)); if (!auth || !tds->connection) return NULL; auth->tds_auth.free = tds_sspi_free; auth->tds_auth.handle_next = tds_sspi_handle_next; /* using Negotiate system will use proper protocol (either NTLM or Kerberos) */ if (sec_fn->AcquireCredentialsHandleA(NULL, (char *)"Negotiate", SECPKG_CRED_OUTBOUND, NULL, identity.Domain ? &identity : NULL, NULL, NULL, &auth->cred, &ts) != SEC_E_OK) { free(auth); return NULL; } /* allocate buffer */ auth->tds_auth.packet = (TDS_UCHAR *) malloc(NTLMBUF_LEN); if (!auth->tds_auth.packet) { sec_fn->FreeCredentialsHandle(&auth->cred); free(auth); return NULL; } desc.ulVersion = SECBUFFER_VERSION; desc.cBuffers = 1; desc.pBuffers = &buf; buf.cbBuffer = NTLMBUF_LEN; buf.BufferType = SECBUFFER_TOKEN; buf.pvBuffer = auth->tds_auth.packet; /* build SPN */ server_name = tds_dstr_cstr(&connection->server_host_name); if (strchr(server_name, '.') == NULL) { struct hostent *host = gethostbyname(server_name); if (host && strchr(host->h_name, '.') != NULL) server_name = host->h_name; } if (strchr(server_name, '.') != NULL) { if (asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, connection->port) < 0) { free(auth->tds_auth.packet); sec_fn->FreeCredentialsHandle(&auth->cred); free(auth); return NULL; } tdsdump_log(TDS_DBG_NETWORK, "kerberos name %s\n", auth->sname); } status = sec_fn->InitializeSecurityContextA(&auth->cred, NULL, auth->sname, ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION, 0, SECURITY_NETWORK_DREP, NULL, 0, &auth->cred_ctx, &desc, &attrs, &ts); if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) { sec_fn->CompleteAuthToken(&auth->cred_ctx, &desc); } else if(status != SEC_E_OK) { free(auth->sname); free(auth->tds_auth.packet); sec_fn->FreeCredentialsHandle(&auth->cred); free(auth); return NULL; } auth->tds_auth.packet_len = buf.cbBuffer; return &auth->tds_auth; }
bool ZStreamRWCon_SSL_Win::pHandshake() { for (;;) { SecBuffer inSB[2]; // Data from peer is in fBufferEnc, and passed to schannel via inSB[0]. inSB[0].cbBuffer = fBufferEnc.size(); inSB[0].pvBuffer = ZUtil_STL::sFirstOrNil(fBufferEnc); inSB[0].BufferType = SECBUFFER_TOKEN; // After calling schannel, any unused data in fBufferEnc is described by inSB[1]. inSB[1].cbBuffer = 0; inSB[1].pvBuffer = nullptr; inSB[1].BufferType = SECBUFFER_EMPTY; SecBufferDesc inSBD; inSBD.cBuffers = 2; inSBD.pBuffers = inSB; inSBD.ulVersion = SECBUFFER_VERSION; // Will hold data to be sent to peer SecBuffer outSB[1]; outSB[0].cbBuffer = 0; outSB[0].pvBuffer = nullptr; outSB[0].BufferType= SECBUFFER_TOKEN; SecBufferDesc outSBD; outSBD.cBuffers = 1; outSBD.pBuffers = outSB; outSBD.ulVersion = SECBUFFER_VERSION; DWORD attributes; const SECURITY_STATUS result = spPSFT->InitializeSecurityContextA( &fCredHandle, &fCtxtHandle, nullptr, spRequirements, 0, // Reserved1 SECURITY_NATIVE_DREP, &inSBD, 0, // Reserved2 nullptr, &outSBD, &attributes, nullptr); if (result == SEC_E_INCOMPLETE_MESSAGE) { if (not spReadMore(fBufferEnc, fStreamR)) return false; } else { // Send anything that was generated. spWriteFreeFlush(outSB[0], fStreamW); if (FAILED(result)) return false; // Remove consumed data. if (inSB[1].BufferType == SECBUFFER_EXTRA) fBufferEnc.erase(fBufferEnc.begin(), fBufferEnc.end() - inSB[1].cbBuffer); else fBufferEnc.clear(); if (result == SEC_E_OK) { // Handshake completed successfully. return true; } } } }