1/* 2 * Copyright (c) 2013 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "krb5_locl.h" 37#include <CoreFoundation/CoreFoundation.h> 38#include <CFNetwork/CFNetwork.h> 39 40static krb5_error_code 41requestToURL(krb5_context context, 42 const char *stringurl, 43 const krb5_data *outdata, 44 krb5_data *retdata) 45{ 46 CFMutableDataRef responseBytes = NULL; 47 CFReadStreamRef requestStream = NULL; 48 CFHTTPMessageRef message = NULL; 49 CFDataRef bodyData = NULL; 50 KDC_PROXY_MESSAGE msg; 51 CFIndex numBytesRead; 52 krb5_error_code ret; 53 CFURLRef url = NULL; 54 size_t size; 55 56 bodyData = CFDataCreateWithBytesNoCopy(NULL, outdata->data, outdata->length, kCFAllocatorNull); 57 if (bodyData == NULL) { 58 ret = ENOMEM; 59 goto out; 60 } 61 62 url = CFURLCreateWithBytes(NULL, (const UInt8 *)stringurl, strlen(stringurl), kCFStringEncodingUTF8, NULL); 63 if (url == NULL) { 64 ret = ENOMEM; 65 goto out; 66 } 67 68 message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), url, kCFHTTPVersion1_1); 69 if (message == NULL) { 70 ret = ENOMEM; 71 goto out; 72 } 73 CFHTTPMessageSetBody(message, bodyData); 74 CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Content-Type"), CFSTR("application/octet-stream")); 75 76 requestStream = CFReadStreamCreateForHTTPRequest(NULL, message); 77 if (requestStream == NULL) { 78 ret = ENOMEM; 79 goto out; 80 } 81 82 if (!CFReadStreamOpen(requestStream)) { 83 CFErrorRef error = CFReadStreamCopyError(requestStream); 84 ret = HEIM_ERR_EOF; 85 _krb5_set_cf_error_message(context, ret, error, "Failed to open kkdcp stream"); 86 if (error) 87 CFRelease(error); 88 goto out; 89 } 90 91 responseBytes = CFDataCreateMutable(NULL, 0); 92 numBytesRead = 0 ; 93 do { 94 UInt8 buf[1024]; 95 numBytesRead = CFReadStreamRead(requestStream, buf, sizeof(buf)); 96 if(numBytesRead > 0) 97 CFDataAppendBytes(responseBytes, buf, numBytesRead); 98 99 } while(numBytesRead > 0); 100 if (numBytesRead < 0) { 101 CFErrorRef error = CFReadStreamCopyError(requestStream); 102 ret = HEIM_ERR_EOF; 103 _krb5_set_cf_error_message(context, ret, error, "Failed to reading kkdcp stream"); 104 goto out; 105 } 106 CFReadStreamClose(requestStream); 107 108 ret = decode_KDC_PROXY_MESSAGE(CFDataGetBytePtr(responseBytes), CFDataGetLength(responseBytes), &msg, &size); 109 if (ret) { 110 krb5_set_error_message(context, ret, "failed to decode KDC_PROXY_MESSAGE"); 111 goto out; 112 } 113 114 ret = krb5_data_copy(retdata, msg.kerb_message.data, msg.kerb_message.length); 115 free_KDC_PROXY_MESSAGE(&msg); 116 if (ret) 117 goto out; 118 119 ret = 0; 120 out: 121 if (ret) 122 _krb5_debug(context, 10, ret, "kkdcp to url (%s) failed", stringurl); 123 124 if (bodyData) 125 CFRelease(bodyData); 126 if (url) 127 CFRelease(url); 128 if (message) 129 CFRelease(message); 130 if (requestStream) 131 CFRelease(requestStream); 132 if (responseBytes) 133 CFRelease(responseBytes); 134 135 return ret; 136} 137 138krb5_error_code 139_krb5_kkdcp_request(krb5_context context, 140 const char *realm, 141 const char *url, 142 const krb5_data *data, 143 krb5_data *retdata) 144{ 145 KDC_PROXY_MESSAGE msg; 146 krb5_data msgdata; 147 krb5_error_code ret; 148 size_t size; 149 150 memset(&msg, 0, sizeof(msg)); 151 152 msg.kerb_message = *data; 153 msg.target_domain = (Realm *)&realm; 154 msg.dclocator_hint = NULL; 155 156 ASN1_MALLOC_ENCODE(KDC_PROXY_MESSAGE, msgdata.data, msgdata.length, &msg, &size, ret); 157 if (ret) 158 return ret; 159 heim_assert(msgdata.length == size, "internal asn1. encoder error"); 160 161 ret = requestToURL(context, url, &msgdata, retdata); 162 krb5_data_free(&msgdata); 163 164 return ret; 165} 166