1b528cefcSMark Murray /* 28373020dSJacques Vidrine * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "krb5_locl.h" 35b528cefcSMark Murray 36c19800e8SDoug Rabson RCSID("$Id: send_to_kdc.c 21934 2007-08-27 14:21:04Z lha $"); 37c19800e8SDoug Rabson 38c19800e8SDoug Rabson struct send_to_kdc { 39c19800e8SDoug Rabson krb5_send_to_kdc_func func; 40c19800e8SDoug Rabson void *data; 41c19800e8SDoug Rabson }; 42b528cefcSMark Murray 43b528cefcSMark Murray /* 44b528cefcSMark Murray * send the data in `req' on the socket `fd' (which is datagram iff udp) 45b528cefcSMark Murray * waiting `tmout' for a reply and returning the reply in `rep'. 46b528cefcSMark Murray * iff limit read up to this many bytes 47b528cefcSMark Murray * returns 0 and data in `rep' if succesful, otherwise -1 48b528cefcSMark Murray */ 49b528cefcSMark Murray 50b528cefcSMark Murray static int 51b528cefcSMark Murray recv_loop (int fd, 52b528cefcSMark Murray time_t tmout, 53b528cefcSMark Murray int udp, 54b528cefcSMark Murray size_t limit, 55b528cefcSMark Murray krb5_data *rep) 56b528cefcSMark Murray { 57b528cefcSMark Murray fd_set fdset; 58b528cefcSMark Murray struct timeval timeout; 59b528cefcSMark Murray int ret; 60b528cefcSMark Murray int nbytes; 61b528cefcSMark Murray 625e9cd1aeSAssar Westerlund if (fd >= FD_SETSIZE) { 635e9cd1aeSAssar Westerlund return -1; 645e9cd1aeSAssar Westerlund } 655e9cd1aeSAssar Westerlund 66b528cefcSMark Murray krb5_data_zero(rep); 67b528cefcSMark Murray do { 68b528cefcSMark Murray FD_ZERO(&fdset); 69b528cefcSMark Murray FD_SET(fd, &fdset); 70b528cefcSMark Murray timeout.tv_sec = tmout; 71b528cefcSMark Murray timeout.tv_usec = 0; 72b528cefcSMark Murray ret = select (fd + 1, &fdset, NULL, NULL, &timeout); 73b528cefcSMark Murray if (ret < 0) { 74b528cefcSMark Murray if (errno == EINTR) 75b528cefcSMark Murray continue; 76b528cefcSMark Murray return -1; 77b528cefcSMark Murray } else if (ret == 0) { 78b528cefcSMark Murray return 0; 79b528cefcSMark Murray } else { 80b528cefcSMark Murray void *tmp; 81b528cefcSMark Murray 82b528cefcSMark Murray if (ioctl (fd, FIONREAD, &nbytes) < 0) { 83b528cefcSMark Murray krb5_data_free (rep); 84b528cefcSMark Murray return -1; 85b528cefcSMark Murray } 86c19800e8SDoug Rabson if(nbytes <= 0) 87b528cefcSMark Murray return 0; 88b528cefcSMark Murray 89b528cefcSMark Murray if (limit) 90b528cefcSMark Murray nbytes = min(nbytes, limit - rep->length); 91b528cefcSMark Murray 92b528cefcSMark Murray tmp = realloc (rep->data, rep->length + nbytes); 93b528cefcSMark Murray if (tmp == NULL) { 94b528cefcSMark Murray krb5_data_free (rep); 95b528cefcSMark Murray return -1; 96b528cefcSMark Murray } 97b528cefcSMark Murray rep->data = tmp; 98b528cefcSMark Murray ret = recv (fd, (char*)tmp + rep->length, nbytes, 0); 99b528cefcSMark Murray if (ret < 0) { 100b528cefcSMark Murray krb5_data_free (rep); 101b528cefcSMark Murray return -1; 102b528cefcSMark Murray } 103b528cefcSMark Murray rep->length += ret; 104b528cefcSMark Murray } 105b528cefcSMark Murray } while(!udp && (limit == 0 || rep->length < limit)); 106b528cefcSMark Murray return 0; 107b528cefcSMark Murray } 108b528cefcSMark Murray 109b528cefcSMark Murray /* 110b528cefcSMark Murray * Send kerberos requests and receive a reply on a udp or any other kind 111b528cefcSMark Murray * of a datagram socket. See `recv_loop'. 112b528cefcSMark Murray */ 113b528cefcSMark Murray 114b528cefcSMark Murray static int 115b528cefcSMark Murray send_and_recv_udp(int fd, 116b528cefcSMark Murray time_t tmout, 117b528cefcSMark Murray const krb5_data *req, 118b528cefcSMark Murray krb5_data *rep) 119b528cefcSMark Murray { 120b528cefcSMark Murray if (send (fd, req->data, req->length, 0) < 0) 121b528cefcSMark Murray return -1; 122b528cefcSMark Murray 123b528cefcSMark Murray return recv_loop(fd, tmout, 1, 0, rep); 124b528cefcSMark Murray } 125b528cefcSMark Murray 126b528cefcSMark Murray /* 127b528cefcSMark Murray * `send_and_recv' for a TCP (or any other stream) socket. 128b528cefcSMark Murray * Since there are no record limits on a stream socket the protocol here 129b528cefcSMark Murray * is to prepend the request with 4 bytes of its length and the reply 130b528cefcSMark Murray * is similarly encoded. 131b528cefcSMark Murray */ 132b528cefcSMark Murray 133b528cefcSMark Murray static int 134b528cefcSMark Murray send_and_recv_tcp(int fd, 135b528cefcSMark Murray time_t tmout, 136b528cefcSMark Murray const krb5_data *req, 137b528cefcSMark Murray krb5_data *rep) 138b528cefcSMark Murray { 139b528cefcSMark Murray unsigned char len[4]; 140b528cefcSMark Murray unsigned long rep_len; 141b528cefcSMark Murray krb5_data len_data; 142b528cefcSMark Murray 143b528cefcSMark Murray _krb5_put_int(len, req->length, 4); 144b528cefcSMark Murray if(net_write(fd, len, sizeof(len)) < 0) 145b528cefcSMark Murray return -1; 146b528cefcSMark Murray if(net_write(fd, req->data, req->length) < 0) 147b528cefcSMark Murray return -1; 148b528cefcSMark Murray if (recv_loop (fd, tmout, 0, 4, &len_data) < 0) 149b528cefcSMark Murray return -1; 150b528cefcSMark Murray if (len_data.length != 4) { 151b528cefcSMark Murray krb5_data_free (&len_data); 152b528cefcSMark Murray return -1; 153b528cefcSMark Murray } 154b528cefcSMark Murray _krb5_get_int(len_data.data, &rep_len, 4); 155b528cefcSMark Murray krb5_data_free (&len_data); 156b528cefcSMark Murray if (recv_loop (fd, tmout, 0, rep_len, rep) < 0) 157b528cefcSMark Murray return -1; 158b528cefcSMark Murray if(rep->length != rep_len) { 159b528cefcSMark Murray krb5_data_free (rep); 160b528cefcSMark Murray return -1; 161b528cefcSMark Murray } 162b528cefcSMark Murray return 0; 163b528cefcSMark Murray } 164b528cefcSMark Murray 165c19800e8SDoug Rabson int 166c19800e8SDoug Rabson _krb5_send_and_recv_tcp(int fd, 167c19800e8SDoug Rabson time_t tmout, 168c19800e8SDoug Rabson const krb5_data *req, 169c19800e8SDoug Rabson krb5_data *rep) 170c19800e8SDoug Rabson { 171c19800e8SDoug Rabson return send_and_recv_tcp(fd, tmout, req, rep); 172c19800e8SDoug Rabson } 173c19800e8SDoug Rabson 174b528cefcSMark Murray /* 175b528cefcSMark Murray * `send_and_recv' tailored for the HTTP protocol. 176b528cefcSMark Murray */ 177b528cefcSMark Murray 178b528cefcSMark Murray static int 179b528cefcSMark Murray send_and_recv_http(int fd, 180b528cefcSMark Murray time_t tmout, 181b528cefcSMark Murray const char *prefix, 182b528cefcSMark Murray const krb5_data *req, 183b528cefcSMark Murray krb5_data *rep) 184b528cefcSMark Murray { 185b528cefcSMark Murray char *request; 186b528cefcSMark Murray char *str; 187b528cefcSMark Murray int ret; 188b528cefcSMark Murray int len = base64_encode(req->data, req->length, &str); 189b528cefcSMark Murray 190b528cefcSMark Murray if(len < 0) 191b528cefcSMark Murray return -1; 192b528cefcSMark Murray asprintf(&request, "GET %s%s HTTP/1.0\r\n\r\n", prefix, str); 193b528cefcSMark Murray free(str); 194b528cefcSMark Murray if (request == NULL) 195b528cefcSMark Murray return -1; 196b528cefcSMark Murray ret = net_write (fd, request, strlen(request)); 197b528cefcSMark Murray free (request); 198b528cefcSMark Murray if (ret < 0) 199b528cefcSMark Murray return ret; 200b528cefcSMark Murray ret = recv_loop(fd, tmout, 0, 0, rep); 201b528cefcSMark Murray if(ret) 202b528cefcSMark Murray return ret; 203b528cefcSMark Murray { 204b528cefcSMark Murray unsigned long rep_len; 205b528cefcSMark Murray char *s, *p; 206b528cefcSMark Murray 207b528cefcSMark Murray s = realloc(rep->data, rep->length + 1); 208b528cefcSMark Murray if (s == NULL) { 209b528cefcSMark Murray krb5_data_free (rep); 210b528cefcSMark Murray return -1; 211b528cefcSMark Murray } 212b528cefcSMark Murray s[rep->length] = 0; 213b528cefcSMark Murray p = strstr(s, "\r\n\r\n"); 214b528cefcSMark Murray if(p == NULL) { 215c19800e8SDoug Rabson krb5_data_zero(rep); 216b528cefcSMark Murray free(s); 217b528cefcSMark Murray return -1; 218b528cefcSMark Murray } 219b528cefcSMark Murray p += 4; 220b528cefcSMark Murray rep->data = s; 221b528cefcSMark Murray rep->length -= p - s; 222b528cefcSMark Murray if(rep->length < 4) { /* remove length */ 223c19800e8SDoug Rabson krb5_data_zero(rep); 224b528cefcSMark Murray free(s); 225b528cefcSMark Murray return -1; 226b528cefcSMark Murray } 227b528cefcSMark Murray rep->length -= 4; 228b528cefcSMark Murray _krb5_get_int(p, &rep_len, 4); 229b528cefcSMark Murray if (rep_len != rep->length) { 230c19800e8SDoug Rabson krb5_data_zero(rep); 231b528cefcSMark Murray free(s); 232b528cefcSMark Murray return -1; 233b528cefcSMark Murray } 234b528cefcSMark Murray memmove(rep->data, p + 4, rep->length); 235b528cefcSMark Murray } 236b528cefcSMark Murray return 0; 237b528cefcSMark Murray } 238b528cefcSMark Murray 239b528cefcSMark Murray static int 240b528cefcSMark Murray init_port(const char *s, int fallback) 241b528cefcSMark Murray { 242b528cefcSMark Murray if (s) { 243b528cefcSMark Murray int tmp; 244b528cefcSMark Murray 245b528cefcSMark Murray sscanf (s, "%d", &tmp); 246b528cefcSMark Murray return htons(tmp); 247b528cefcSMark Murray } else 248b528cefcSMark Murray return fallback; 249b528cefcSMark Murray } 250b528cefcSMark Murray 251b528cefcSMark Murray /* 252b528cefcSMark Murray * Return 0 if succesful, otherwise 1 253b528cefcSMark Murray */ 254b528cefcSMark Murray 255b528cefcSMark Murray static int 256b528cefcSMark Murray send_via_proxy (krb5_context context, 2574137ff4cSJacques Vidrine const krb5_krbhst_info *hi, 2588373020dSJacques Vidrine const krb5_data *send_data, 259b528cefcSMark Murray krb5_data *receive) 260b528cefcSMark Murray { 2615e9cd1aeSAssar Westerlund char *proxy2 = strdup(context->http_proxy); 2625e9cd1aeSAssar Westerlund char *proxy = proxy2; 263b528cefcSMark Murray char *prefix; 264b528cefcSMark Murray char *colon; 265b528cefcSMark Murray struct addrinfo hints; 266b528cefcSMark Murray struct addrinfo *ai, *a; 267b528cefcSMark Murray int ret; 2684137ff4cSJacques Vidrine int s = -1; 269b528cefcSMark Murray char portstr[NI_MAXSERV]; 270b528cefcSMark Murray 2715e9cd1aeSAssar Westerlund if (proxy == NULL) 2725e9cd1aeSAssar Westerlund return ENOMEM; 2735e9cd1aeSAssar Westerlund if (strncmp (proxy, "http://", 7) == 0) 2745e9cd1aeSAssar Westerlund proxy += 7; 2755e9cd1aeSAssar Westerlund 276b528cefcSMark Murray colon = strchr(proxy, ':'); 277b528cefcSMark Murray if(colon != NULL) 278b528cefcSMark Murray *colon++ = '\0'; 279b528cefcSMark Murray memset (&hints, 0, sizeof(hints)); 280b528cefcSMark Murray hints.ai_family = PF_UNSPEC; 281b528cefcSMark Murray hints.ai_socktype = SOCK_STREAM; 282b528cefcSMark Murray snprintf (portstr, sizeof(portstr), "%d", 283b528cefcSMark Murray ntohs(init_port (colon, htons(80)))); 2845e9cd1aeSAssar Westerlund ret = getaddrinfo (proxy, portstr, &hints, &ai); 2855e9cd1aeSAssar Westerlund free (proxy2); 286b528cefcSMark Murray if (ret) 287adb0ddaeSAssar Westerlund return krb5_eai_to_heim_errno(ret, errno); 288b528cefcSMark Murray 289b528cefcSMark Murray for (a = ai; a != NULL; a = a->ai_next) { 290b528cefcSMark Murray s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 291b528cefcSMark Murray if (s < 0) 292b528cefcSMark Murray continue; 293b528cefcSMark Murray if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 294b528cefcSMark Murray close (s); 295b528cefcSMark Murray continue; 296b528cefcSMark Murray } 297b528cefcSMark Murray break; 298b528cefcSMark Murray } 299b528cefcSMark Murray if (a == NULL) { 300b528cefcSMark Murray freeaddrinfo (ai); 301b528cefcSMark Murray return 1; 302b528cefcSMark Murray } 303b528cefcSMark Murray freeaddrinfo (ai); 304b528cefcSMark Murray 3054137ff4cSJacques Vidrine asprintf(&prefix, "http://%s/", hi->hostname); 306b528cefcSMark Murray if(prefix == NULL) { 307b528cefcSMark Murray close(s); 308b528cefcSMark Murray return 1; 309b528cefcSMark Murray } 310b528cefcSMark Murray ret = send_and_recv_http(s, context->kdc_timeout, 3118373020dSJacques Vidrine prefix, send_data, receive); 312b528cefcSMark Murray close (s); 313b528cefcSMark Murray free(prefix); 314b528cefcSMark Murray if(ret == 0 && receive->length != 0) 315b528cefcSMark Murray return 0; 316b528cefcSMark Murray return 1; 317b528cefcSMark Murray } 318b528cefcSMark Murray 319b528cefcSMark Murray /* 3204137ff4cSJacques Vidrine * Send the data `send' to one host from `handle` and get back the reply 321b528cefcSMark Murray * in `receive'. 322b528cefcSMark Murray */ 323b528cefcSMark Murray 324c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 3255e9cd1aeSAssar Westerlund krb5_sendto (krb5_context context, 3268373020dSJacques Vidrine const krb5_data *send_data, 3274137ff4cSJacques Vidrine krb5_krbhst_handle handle, 328b528cefcSMark Murray krb5_data *receive) 329b528cefcSMark Murray { 330c19800e8SDoug Rabson krb5_error_code ret; 331b528cefcSMark Murray int fd; 332b528cefcSMark Murray int i; 333b528cefcSMark Murray 334c19800e8SDoug Rabson krb5_data_zero(receive); 335c19800e8SDoug Rabson 336adb0ddaeSAssar Westerlund for (i = 0; i < context->max_retries; ++i) { 3374137ff4cSJacques Vidrine krb5_krbhst_info *hi; 338b528cefcSMark Murray 3394137ff4cSJacques Vidrine while (krb5_krbhst_next(context, handle, &hi) == 0) { 3404137ff4cSJacques Vidrine struct addrinfo *ai, *a; 3414137ff4cSJacques Vidrine 342c19800e8SDoug Rabson if (context->send_to_kdc) { 343c19800e8SDoug Rabson struct send_to_kdc *s = context->send_to_kdc; 344c19800e8SDoug Rabson 345c19800e8SDoug Rabson ret = (*s->func)(context, s->data, 346c19800e8SDoug Rabson hi, send_data, receive); 347c19800e8SDoug Rabson if (ret == 0 && receive->length != 0) 348b528cefcSMark Murray goto out; 349c19800e8SDoug Rabson continue; 350c19800e8SDoug Rabson } 351c19800e8SDoug Rabson 352c19800e8SDoug Rabson if(hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) { 353c19800e8SDoug Rabson if (send_via_proxy (context, hi, send_data, receive) == 0) { 354c19800e8SDoug Rabson ret = 0; 355c19800e8SDoug Rabson goto out; 356c19800e8SDoug Rabson } 357c19800e8SDoug Rabson continue; 358b528cefcSMark Murray } 359b528cefcSMark Murray 3604137ff4cSJacques Vidrine ret = krb5_krbhst_get_addrinfo(context, hi, &ai); 361b528cefcSMark Murray if (ret) 362b528cefcSMark Murray continue; 3634137ff4cSJacques Vidrine 364b528cefcSMark Murray for (a = ai; a != NULL; a = a->ai_next) { 365b528cefcSMark Murray fd = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 366b528cefcSMark Murray if (fd < 0) 367b528cefcSMark Murray continue; 368b528cefcSMark Murray if (connect (fd, a->ai_addr, a->ai_addrlen) < 0) { 369b528cefcSMark Murray close (fd); 370b528cefcSMark Murray continue; 371b528cefcSMark Murray } 3724137ff4cSJacques Vidrine switch (hi->proto) { 3734137ff4cSJacques Vidrine case KRB5_KRBHST_HTTP : 374b528cefcSMark Murray ret = send_and_recv_http(fd, context->kdc_timeout, 3758373020dSJacques Vidrine "", send_data, receive); 3764137ff4cSJacques Vidrine break; 3774137ff4cSJacques Vidrine case KRB5_KRBHST_TCP : 378b528cefcSMark Murray ret = send_and_recv_tcp (fd, context->kdc_timeout, 3798373020dSJacques Vidrine send_data, receive); 3804137ff4cSJacques Vidrine break; 3814137ff4cSJacques Vidrine case KRB5_KRBHST_UDP : 382b528cefcSMark Murray ret = send_and_recv_udp (fd, context->kdc_timeout, 3838373020dSJacques Vidrine send_data, receive); 3844137ff4cSJacques Vidrine break; 3854137ff4cSJacques Vidrine } 386b528cefcSMark Murray close (fd); 3874137ff4cSJacques Vidrine if(ret == 0 && receive->length != 0) 388b528cefcSMark Murray goto out; 389b528cefcSMark Murray } 390adb0ddaeSAssar Westerlund } 3914137ff4cSJacques Vidrine krb5_krbhst_reset(context, handle); 392adb0ddaeSAssar Westerlund } 393adb0ddaeSAssar Westerlund krb5_clear_error_string (context); 394b528cefcSMark Murray ret = KRB5_KDC_UNREACH; 395b528cefcSMark Murray out: 3965e9cd1aeSAssar Westerlund return ret; 3975e9cd1aeSAssar Westerlund } 3985e9cd1aeSAssar Westerlund 399c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 4005e9cd1aeSAssar Westerlund krb5_sendto_kdc(krb5_context context, 4018373020dSJacques Vidrine const krb5_data *send_data, 4025e9cd1aeSAssar Westerlund const krb5_realm *realm, 4035e9cd1aeSAssar Westerlund krb5_data *receive) 4045e9cd1aeSAssar Westerlund { 405c19800e8SDoug Rabson return krb5_sendto_kdc_flags(context, send_data, realm, receive, 0); 406c19800e8SDoug Rabson } 407c19800e8SDoug Rabson 408c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 409c19800e8SDoug Rabson krb5_sendto_kdc_flags(krb5_context context, 410c19800e8SDoug Rabson const krb5_data *send_data, 411c19800e8SDoug Rabson const krb5_realm *realm, 412c19800e8SDoug Rabson krb5_data *receive, 413c19800e8SDoug Rabson int flags) 414c19800e8SDoug Rabson { 415c19800e8SDoug Rabson krb5_error_code ret; 416c19800e8SDoug Rabson krb5_sendto_ctx ctx; 417c19800e8SDoug Rabson 418c19800e8SDoug Rabson ret = krb5_sendto_ctx_alloc(context, &ctx); 419c19800e8SDoug Rabson if (ret) 420c19800e8SDoug Rabson return ret; 421c19800e8SDoug Rabson krb5_sendto_ctx_add_flags(ctx, flags); 422c19800e8SDoug Rabson krb5_sendto_ctx_set_func(ctx, _krb5_kdc_retry, NULL); 423c19800e8SDoug Rabson 424c19800e8SDoug Rabson ret = krb5_sendto_context(context, ctx, send_data, *realm, receive); 425c19800e8SDoug Rabson krb5_sendto_ctx_free(context, ctx); 426c19800e8SDoug Rabson return ret; 427c19800e8SDoug Rabson } 428c19800e8SDoug Rabson 429c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 430c19800e8SDoug Rabson krb5_set_send_to_kdc_func(krb5_context context, 431c19800e8SDoug Rabson krb5_send_to_kdc_func func, 432c19800e8SDoug Rabson void *data) 433c19800e8SDoug Rabson { 434c19800e8SDoug Rabson free(context->send_to_kdc); 435c19800e8SDoug Rabson if (func == NULL) { 436c19800e8SDoug Rabson context->send_to_kdc = NULL; 437c19800e8SDoug Rabson return 0; 438c19800e8SDoug Rabson } 439c19800e8SDoug Rabson 440c19800e8SDoug Rabson context->send_to_kdc = malloc(sizeof(*context->send_to_kdc)); 441c19800e8SDoug Rabson if (context->send_to_kdc == NULL) { 442c19800e8SDoug Rabson krb5_set_error_string(context, "Out of memory"); 443c19800e8SDoug Rabson return ENOMEM; 444c19800e8SDoug Rabson } 445c19800e8SDoug Rabson 446c19800e8SDoug Rabson context->send_to_kdc->func = func; 447c19800e8SDoug Rabson context->send_to_kdc->data = data; 448c19800e8SDoug Rabson return 0; 449c19800e8SDoug Rabson } 450c19800e8SDoug Rabson 451c19800e8SDoug Rabson struct krb5_sendto_ctx_data { 452c19800e8SDoug Rabson int flags; 453c19800e8SDoug Rabson int type; 454c19800e8SDoug Rabson krb5_sendto_ctx_func func; 455c19800e8SDoug Rabson void *data; 456c19800e8SDoug Rabson }; 457c19800e8SDoug Rabson 458c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 459c19800e8SDoug Rabson krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx) 460c19800e8SDoug Rabson { 461c19800e8SDoug Rabson *ctx = calloc(1, sizeof(**ctx)); 462c19800e8SDoug Rabson if (*ctx == NULL) { 463c19800e8SDoug Rabson krb5_set_error_string(context, "out of memory"); 464c19800e8SDoug Rabson return ENOMEM; 465c19800e8SDoug Rabson } 466c19800e8SDoug Rabson return 0; 467c19800e8SDoug Rabson } 468c19800e8SDoug Rabson 469c19800e8SDoug Rabson void KRB5_LIB_FUNCTION 470c19800e8SDoug Rabson krb5_sendto_ctx_add_flags(krb5_sendto_ctx ctx, int flags) 471c19800e8SDoug Rabson { 472c19800e8SDoug Rabson ctx->flags |= flags; 473c19800e8SDoug Rabson } 474c19800e8SDoug Rabson 475c19800e8SDoug Rabson int KRB5_LIB_FUNCTION 476c19800e8SDoug Rabson krb5_sendto_ctx_get_flags(krb5_sendto_ctx ctx) 477c19800e8SDoug Rabson { 478c19800e8SDoug Rabson return ctx->flags; 479c19800e8SDoug Rabson } 480c19800e8SDoug Rabson 481c19800e8SDoug Rabson void KRB5_LIB_FUNCTION 482c19800e8SDoug Rabson krb5_sendto_ctx_set_type(krb5_sendto_ctx ctx, int type) 483c19800e8SDoug Rabson { 484c19800e8SDoug Rabson ctx->type = type; 485c19800e8SDoug Rabson } 486c19800e8SDoug Rabson 487c19800e8SDoug Rabson 488c19800e8SDoug Rabson void KRB5_LIB_FUNCTION 489c19800e8SDoug Rabson krb5_sendto_ctx_set_func(krb5_sendto_ctx ctx, 490c19800e8SDoug Rabson krb5_sendto_ctx_func func, 491c19800e8SDoug Rabson void *data) 492c19800e8SDoug Rabson { 493c19800e8SDoug Rabson ctx->func = func; 494c19800e8SDoug Rabson ctx->data = data; 495c19800e8SDoug Rabson } 496c19800e8SDoug Rabson 497c19800e8SDoug Rabson void KRB5_LIB_FUNCTION 498c19800e8SDoug Rabson krb5_sendto_ctx_free(krb5_context context, krb5_sendto_ctx ctx) 499c19800e8SDoug Rabson { 500c19800e8SDoug Rabson memset(ctx, 0, sizeof(*ctx)); 501c19800e8SDoug Rabson free(ctx); 502c19800e8SDoug Rabson } 503c19800e8SDoug Rabson 504c19800e8SDoug Rabson krb5_error_code KRB5_LIB_FUNCTION 505c19800e8SDoug Rabson krb5_sendto_context(krb5_context context, 506c19800e8SDoug Rabson krb5_sendto_ctx ctx, 507c19800e8SDoug Rabson const krb5_data *send_data, 508c19800e8SDoug Rabson const krb5_realm realm, 509c19800e8SDoug Rabson krb5_data *receive) 510c19800e8SDoug Rabson { 511c19800e8SDoug Rabson krb5_error_code ret; 512c19800e8SDoug Rabson krb5_krbhst_handle handle = NULL; 513c19800e8SDoug Rabson int type, freectx = 0; 514c19800e8SDoug Rabson int action; 515c19800e8SDoug Rabson 516c19800e8SDoug Rabson krb5_data_zero(receive); 517c19800e8SDoug Rabson 518c19800e8SDoug Rabson if (ctx == NULL) { 519c19800e8SDoug Rabson freectx = 1; 520c19800e8SDoug Rabson ret = krb5_sendto_ctx_alloc(context, &ctx); 521c19800e8SDoug Rabson if (ret) 522c19800e8SDoug Rabson return ret; 523c19800e8SDoug Rabson } 524c19800e8SDoug Rabson 525c19800e8SDoug Rabson type = ctx->type; 526c19800e8SDoug Rabson if (type == 0) { 527c19800e8SDoug Rabson if ((ctx->flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) 528c19800e8SDoug Rabson type = KRB5_KRBHST_ADMIN; 529c19800e8SDoug Rabson else 530c19800e8SDoug Rabson type = KRB5_KRBHST_KDC; 531c19800e8SDoug Rabson } 532c19800e8SDoug Rabson 533c19800e8SDoug Rabson if (send_data->length > context->large_msg_size) 534c19800e8SDoug Rabson ctx->flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; 535c19800e8SDoug Rabson 536c19800e8SDoug Rabson /* loop until we get back a appropriate response */ 537c19800e8SDoug Rabson 538c19800e8SDoug Rabson do { 539c19800e8SDoug Rabson action = KRB5_SENDTO_DONE; 540c19800e8SDoug Rabson 541c19800e8SDoug Rabson krb5_data_free(receive); 542c19800e8SDoug Rabson 543c19800e8SDoug Rabson if (handle == NULL) { 544c19800e8SDoug Rabson ret = krb5_krbhst_init_flags(context, realm, type, 545c19800e8SDoug Rabson ctx->flags, &handle); 546c19800e8SDoug Rabson if (ret) { 547c19800e8SDoug Rabson if (freectx) 548c19800e8SDoug Rabson krb5_sendto_ctx_free(context, ctx); 549c19800e8SDoug Rabson return ret; 550c19800e8SDoug Rabson } 551c19800e8SDoug Rabson } 552c19800e8SDoug Rabson 553c19800e8SDoug Rabson ret = krb5_sendto(context, send_data, handle, receive); 554c19800e8SDoug Rabson if (ret) 555c19800e8SDoug Rabson break; 556c19800e8SDoug Rabson if (ctx->func) { 557c19800e8SDoug Rabson ret = (*ctx->func)(context, ctx, ctx->data, receive, &action); 558c19800e8SDoug Rabson if (ret) 559c19800e8SDoug Rabson break; 560c19800e8SDoug Rabson } 561c19800e8SDoug Rabson if (action != KRB5_SENDTO_CONTINUE) { 562c19800e8SDoug Rabson krb5_krbhst_free(context, handle); 563c19800e8SDoug Rabson handle = NULL; 564c19800e8SDoug Rabson } 565c19800e8SDoug Rabson } while (action != KRB5_SENDTO_DONE); 566c19800e8SDoug Rabson if (handle) 567c19800e8SDoug Rabson krb5_krbhst_free(context, handle); 568c19800e8SDoug Rabson if (ret == KRB5_KDC_UNREACH) 569c19800e8SDoug Rabson krb5_set_error_string(context, 570c19800e8SDoug Rabson "unable to reach any KDC in realm %s", realm); 571c19800e8SDoug Rabson if (ret) 572c19800e8SDoug Rabson krb5_data_free(receive); 573c19800e8SDoug Rabson if (freectx) 574c19800e8SDoug Rabson krb5_sendto_ctx_free(context, ctx); 575c19800e8SDoug Rabson return ret; 576c19800e8SDoug Rabson } 577c19800e8SDoug Rabson 578c19800e8SDoug Rabson krb5_error_code 579c19800e8SDoug Rabson _krb5_kdc_retry(krb5_context context, krb5_sendto_ctx ctx, void *data, 580c19800e8SDoug Rabson const krb5_data *reply, int *action) 581c19800e8SDoug Rabson { 582c19800e8SDoug Rabson krb5_error_code ret; 583c19800e8SDoug Rabson KRB_ERROR error; 584c19800e8SDoug Rabson 585c19800e8SDoug Rabson if(krb5_rd_error(context, reply, &error)) 586c19800e8SDoug Rabson return 0; 587c19800e8SDoug Rabson 588c19800e8SDoug Rabson ret = krb5_error_from_rd_error(context, &error, NULL); 589c19800e8SDoug Rabson krb5_free_error_contents(context, &error); 590c19800e8SDoug Rabson 591c19800e8SDoug Rabson switch(ret) { 592c19800e8SDoug Rabson case KRB5KRB_ERR_RESPONSE_TOO_BIG: { 593c19800e8SDoug Rabson if (krb5_sendto_ctx_get_flags(ctx) & KRB5_KRBHST_FLAGS_LARGE_MSG) 594c19800e8SDoug Rabson break; 595c19800e8SDoug Rabson krb5_sendto_ctx_add_flags(ctx, KRB5_KRBHST_FLAGS_LARGE_MSG); 596c19800e8SDoug Rabson *action = KRB5_SENDTO_RESTART; 597c19800e8SDoug Rabson break; 598c19800e8SDoug Rabson } 599c19800e8SDoug Rabson case KRB5KDC_ERR_SVC_UNAVAILABLE: 600c19800e8SDoug Rabson *action = KRB5_SENDTO_CONTINUE; 601c19800e8SDoug Rabson break; 602c19800e8SDoug Rabson } 603c19800e8SDoug Rabson return 0; 6045e9cd1aeSAssar Westerlund } 605