#include "krb5_locl.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CFNetwork/CFNetwork.h>
static krb5_error_code
requestToURL(krb5_context context,
const char *stringurl,
const krb5_data *outdata,
krb5_data *retdata)
{
CFMutableDataRef responseBytes = NULL;
CFReadStreamRef requestStream = NULL;
CFHTTPMessageRef message = NULL;
CFDataRef bodyData = NULL;
KDC_PROXY_MESSAGE msg;
CFIndex numBytesRead;
krb5_error_code ret;
CFURLRef url = NULL;
size_t size;
bodyData = CFDataCreateWithBytesNoCopy(NULL, outdata->data, outdata->length, kCFAllocatorNull);
if (bodyData == NULL) {
ret = ENOMEM;
goto out;
}
url = CFURLCreateWithBytes(NULL, (const UInt8 *)stringurl, strlen(stringurl), kCFStringEncodingUTF8, NULL);
if (url == NULL) {
ret = ENOMEM;
goto out;
}
message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), url, kCFHTTPVersion1_1);
if (message == NULL) {
ret = ENOMEM;
goto out;
}
CFHTTPMessageSetBody(message, bodyData);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Content-Type"), CFSTR("application/octet-stream"));
requestStream = CFReadStreamCreateForHTTPRequest(NULL, message);
if (requestStream == NULL) {
ret = ENOMEM;
goto out;
}
if (!CFReadStreamOpen(requestStream)) {
CFErrorRef error = CFReadStreamCopyError(requestStream);
ret = HEIM_ERR_EOF;
_krb5_set_cf_error_message(context, ret, error, "Failed to open kkdcp stream");
if (error)
CFRelease(error);
goto out;
}
responseBytes = CFDataCreateMutable(NULL, 0);
numBytesRead = 0 ;
do {
UInt8 buf[1024];
numBytesRead = CFReadStreamRead(requestStream, buf, sizeof(buf));
if(numBytesRead > 0)
CFDataAppendBytes(responseBytes, buf, numBytesRead);
} while(numBytesRead > 0);
if (numBytesRead < 0) {
CFErrorRef error = CFReadStreamCopyError(requestStream);
ret = HEIM_ERR_EOF;
_krb5_set_cf_error_message(context, ret, error, "Failed to reading kkdcp stream");
goto out;
}
CFReadStreamClose(requestStream);
ret = decode_KDC_PROXY_MESSAGE(CFDataGetBytePtr(responseBytes), CFDataGetLength(responseBytes), &msg, &size);
if (ret) {
krb5_set_error_message(context, ret, "failed to decode KDC_PROXY_MESSAGE");
goto out;
}
ret = krb5_data_copy(retdata, msg.kerb_message.data, msg.kerb_message.length);
free_KDC_PROXY_MESSAGE(&msg);
if (ret)
goto out;
ret = 0;
out:
if (ret)
_krb5_debug(context, 10, ret, "kkdcp to url (%s) failed", stringurl);
if (bodyData)
CFRelease(bodyData);
if (url)
CFRelease(url);
if (message)
CFRelease(message);
if (requestStream)
CFRelease(requestStream);
if (responseBytes)
CFRelease(responseBytes);
return ret;
}
krb5_error_code
_krb5_kkdcp_request(krb5_context context,
const char *realm,
const char *url,
const krb5_data *data,
krb5_data *retdata)
{
KDC_PROXY_MESSAGE msg;
krb5_data msgdata;
krb5_error_code ret;
size_t size;
memset(&msg, 0, sizeof(msg));
msg.kerb_message = *data;
msg.target_domain = (Realm *)&realm;
msg.dclocator_hint = NULL;
ASN1_MALLOC_ENCODE(KDC_PROXY_MESSAGE, msgdata.data, msgdata.length, &msg, &size, ret);
if (ret)
return ret;
heim_assert(msgdata.length == size, "internal asn1. encoder error");
ret = requestToURL(context, url, &msgdata, retdata);
krb5_data_free(&msgdata);
return ret;
}