Mon Jan 30 00:25:15 2017 UTC ()
fix printf args


(christos)
diff -r1.6 -r1.7 src/crypto/external/bsd/heimdal/dist/lib/krb5/send_to_kdc.c

cvs diff -r1.6 -r1.7 src/crypto/external/bsd/heimdal/dist/lib/krb5/send_to_kdc.c (switch to unified diff)

--- src/crypto/external/bsd/heimdal/dist/lib/krb5/send_to_kdc.c 2017/01/29 18:58:08 1.6
+++ src/crypto/external/bsd/heimdal/dist/lib/krb5/send_to_kdc.c 2017/01/30 00:25:15 1.7
@@ -1,1270 +1,1270 @@ @@ -1,1270 +1,1270 @@
1/* $NetBSD: send_to_kdc.c,v 1.6 2017/01/29 18:58:08 christos Exp $ */ 1/* $NetBSD: send_to_kdc.c,v 1.7 2017/01/30 00:25:15 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan 4 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden). 5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Portions Copyright (c) 2010 - 2013 Apple Inc. All rights reserved. 8 * Portions Copyright (c) 2010 - 2013 Apple Inc. All rights reserved.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 13 *
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer. 15 * notice, this list of conditions and the following disclaimer.
16 * 16 *
17 * 2. Redistributions in binary form must reproduce the above copyright 17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the 18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution. 19 * documentation and/or other materials provided with the distribution.
20 * 20 *
21 * 3. Neither the name of the Institute nor the names of its contributors 21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software 22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission. 23 * without specific prior written permission.
24 * 24 *
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE. 35 * SUCH DAMAGE.
36 */ 36 */
37 37
38#include "krb5_locl.h" 38#include "krb5_locl.h"
39#include "send_to_kdc_plugin.h" 39#include "send_to_kdc_plugin.h"
40 40
41/** 41/**
42 * @section send_to_kdc Locating and sending packets to the KDC 42 * @section send_to_kdc Locating and sending packets to the KDC
43 * 43 *
44 * The send to kdc code is responsible to request the list of KDC from 44 * The send to kdc code is responsible to request the list of KDC from
45 * the locate-kdc subsystem and then send requests to each of them. 45 * the locate-kdc subsystem and then send requests to each of them.
46 * 46 *
47 * - Each second a new hostname is tried. 47 * - Each second a new hostname is tried.
48 * - If the hostname have several addresses, the first will be tried 48 * - If the hostname have several addresses, the first will be tried
49 * directly then in turn the other will be tried every 3 seconds 49 * directly then in turn the other will be tried every 3 seconds
50 * (host_timeout). 50 * (host_timeout).
51 * - UDP requests are tried 3 times, and it tried with a individual timeout of kdc_timeout / 3. 51 * - UDP requests are tried 3 times, and it tried with a individual timeout of kdc_timeout / 3.
52 * - TCP and HTTP requests are tried 1 time. 52 * - TCP and HTTP requests are tried 1 time.
53 * 53 *
54 * Total wait time shorter then (number of addresses * 3) + kdc_timeout seconds. 54 * Total wait time shorter then (number of addresses * 3) + kdc_timeout seconds.
55 * 55 *
56 */ 56 */
57 57
58static int 58static int
59init_port(const char *s, int fallback) 59init_port(const char *s, int fallback)
60{ 60{
61 int tmp; 61 int tmp;
62 62
63 if (s && sscanf(s, "%d", &tmp) == 1) 63 if (s && sscanf(s, "%d", &tmp) == 1)
64 return htons(tmp); 64 return htons(tmp);
65 return fallback; 65 return fallback;
66} 66}
67 67
68struct send_via_plugin_s { 68struct send_via_plugin_s {
69 krb5_const_realm realm; 69 krb5_const_realm realm;
70 krb5_krbhst_info *hi; 70 krb5_krbhst_info *hi;
71 time_t timeout; 71 time_t timeout;
72 const krb5_data *send_data; 72 const krb5_data *send_data;
73 krb5_data *receive; 73 krb5_data *receive;
74}; 74};
75  75
76 76
77static krb5_error_code KRB5_LIB_CALL 77static krb5_error_code KRB5_LIB_CALL
78kdccallback(krb5_context context, const void *plug, void *plugctx, void *userctx) 78kdccallback(krb5_context context, const void *plug, void *plugctx, void *userctx)
79{ 79{
80 const krb5plugin_send_to_kdc_ftable *service = (const krb5plugin_send_to_kdc_ftable *)plug; 80 const krb5plugin_send_to_kdc_ftable *service = (const krb5plugin_send_to_kdc_ftable *)plug;
81 struct send_via_plugin_s *ctx = userctx; 81 struct send_via_plugin_s *ctx = userctx;
82 82
83 if (service->send_to_kdc == NULL) 83 if (service->send_to_kdc == NULL)
84 return KRB5_PLUGIN_NO_HANDLE; 84 return KRB5_PLUGIN_NO_HANDLE;
85 return service->send_to_kdc(context, plugctx, ctx->hi, ctx->timeout, 85 return service->send_to_kdc(context, plugctx, ctx->hi, ctx->timeout,
86 ctx->send_data, ctx->receive); 86 ctx->send_data, ctx->receive);
87} 87}
88 88
89static krb5_error_code KRB5_LIB_CALL 89static krb5_error_code KRB5_LIB_CALL
90realmcallback(krb5_context context, const void *plug, void *plugctx, void *userctx) 90realmcallback(krb5_context context, const void *plug, void *plugctx, void *userctx)
91{ 91{
92 const krb5plugin_send_to_kdc_ftable *service = (const krb5plugin_send_to_kdc_ftable *)plug; 92 const krb5plugin_send_to_kdc_ftable *service = (const krb5plugin_send_to_kdc_ftable *)plug;
93 struct send_via_plugin_s *ctx = userctx; 93 struct send_via_plugin_s *ctx = userctx;
94 94
95 if (service->send_to_realm == NULL) 95 if (service->send_to_realm == NULL)
96 return KRB5_PLUGIN_NO_HANDLE; 96 return KRB5_PLUGIN_NO_HANDLE;
97 return service->send_to_realm(context, plugctx, ctx->realm, ctx->timeout, 97 return service->send_to_realm(context, plugctx, ctx->realm, ctx->timeout,
98 ctx->send_data, ctx->receive); 98 ctx->send_data, ctx->receive);
99} 99}
100 100
101static krb5_error_code 101static krb5_error_code
102kdc_via_plugin(krb5_context context, 102kdc_via_plugin(krb5_context context,
103 krb5_krbhst_info *hi, 103 krb5_krbhst_info *hi,
104 time_t timeout, 104 time_t timeout,
105 const krb5_data *send_data, 105 const krb5_data *send_data,
106 krb5_data *receive) 106 krb5_data *receive)
107{ 107{
108 struct send_via_plugin_s userctx; 108 struct send_via_plugin_s userctx;
109 109
110 userctx.realm = NULL; 110 userctx.realm = NULL;
111 userctx.hi = hi; 111 userctx.hi = hi;
112 userctx.timeout = timeout; 112 userctx.timeout = timeout;
113 userctx.send_data = send_data; 113 userctx.send_data = send_data;
114 userctx.receive = receive; 114 userctx.receive = receive;
115 115
116 return _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_SEND_TO_KDC, 116 return _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_SEND_TO_KDC,
117 KRB5_PLUGIN_SEND_TO_KDC_VERSION_0, 0, 117 KRB5_PLUGIN_SEND_TO_KDC_VERSION_0, 0,
118 &userctx, kdccallback); 118 &userctx, kdccallback);
119} 119}
120 120
121static krb5_error_code 121static krb5_error_code
122realm_via_plugin(krb5_context context, 122realm_via_plugin(krb5_context context,
123 krb5_const_realm realm, 123 krb5_const_realm realm,
124 time_t timeout, 124 time_t timeout,
125 const krb5_data *send_data, 125 const krb5_data *send_data,
126 krb5_data *receive) 126 krb5_data *receive)
127{ 127{
128 struct send_via_plugin_s userctx; 128 struct send_via_plugin_s userctx;
129 129
130 userctx.realm = realm; 130 userctx.realm = realm;
131 userctx.hi = NULL; 131 userctx.hi = NULL;
132 userctx.timeout = timeout; 132 userctx.timeout = timeout;
133 userctx.send_data = send_data; 133 userctx.send_data = send_data;
134 userctx.receive = receive; 134 userctx.receive = receive;
135 135
136 return _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_SEND_TO_KDC, 136 return _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_SEND_TO_KDC,
137 KRB5_PLUGIN_SEND_TO_KDC_VERSION_2, 0, 137 KRB5_PLUGIN_SEND_TO_KDC_VERSION_2, 0,
138 &userctx, realmcallback); 138 &userctx, realmcallback);
139} 139}
140 140
141struct krb5_sendto_ctx_data { 141struct krb5_sendto_ctx_data {
142 int flags; 142 int flags;
143 int type; 143 int type;
144 krb5_sendto_ctx_func func; 144 krb5_sendto_ctx_func func;
145 void *data; 145 void *data;
146 char *hostname; 146 char *hostname;
147 krb5_krbhst_handle krbhst; 147 krb5_krbhst_handle krbhst;
148 148
149 /* context2 */ 149 /* context2 */
150 const krb5_data *send_data; 150 const krb5_data *send_data;
151 krb5_data response; 151 krb5_data response;
152 heim_array_t hosts; 152 heim_array_t hosts;
153 int stateflags; 153 int stateflags;
154#define KRBHST_COMPLETED 1 154#define KRBHST_COMPLETED 1
155 155
156 /* prexmit */ 156 /* prexmit */
157 krb5_sendto_prexmit prexmit_func; 157 krb5_sendto_prexmit prexmit_func;
158 void *prexmit_ctx; 158 void *prexmit_ctx;
159 159
160 /* stats */ 160 /* stats */
161 struct { 161 struct {
162 struct timeval start_time; 162 struct timeval start_time;
163 struct timeval name_resolution; 163 struct timeval name_resolution;
164 struct timeval krbhst; 164 struct timeval krbhst;
165 unsigned long sent_packets; 165 unsigned long sent_packets;
166 unsigned long num_hosts; 166 unsigned long num_hosts;
167 } stats; 167 } stats;
168 unsigned int stid; 168 unsigned int stid;
169}; 169};
170 170
171static void 171static void
172dealloc_sendto_ctx(void *ptr) 172dealloc_sendto_ctx(void *ptr)
173{ 173{
174 krb5_sendto_ctx ctx = (krb5_sendto_ctx)ptr; 174 krb5_sendto_ctx ctx = (krb5_sendto_ctx)ptr;
175 if (ctx->hostname) 175 if (ctx->hostname)
176 free(ctx->hostname); 176 free(ctx->hostname);
177 heim_release(ctx->hosts); 177 heim_release(ctx->hosts);
178 heim_release(ctx->krbhst); 178 heim_release(ctx->krbhst);
179} 179}
180 180
181KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 181KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
182krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx) 182krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx)
183{ 183{
184 *ctx = heim_alloc(sizeof(**ctx), "sendto-context", dealloc_sendto_ctx); 184 *ctx = heim_alloc(sizeof(**ctx), "sendto-context", dealloc_sendto_ctx);
185 if (*ctx == NULL) 185 if (*ctx == NULL)
186 return krb5_enomem(context); 186 return krb5_enomem(context);
187 (*ctx)->hosts = heim_array_create(); 187 (*ctx)->hosts = heim_array_create();
188 188
189 return 0; 189 return 0;
190} 190}
191 191
192KRB5_LIB_FUNCTION void KRB5_LIB_CALL 192KRB5_LIB_FUNCTION void KRB5_LIB_CALL
193krb5_sendto_ctx_add_flags(krb5_sendto_ctx ctx, int flags) 193krb5_sendto_ctx_add_flags(krb5_sendto_ctx ctx, int flags)
194{ 194{
195 ctx->flags |= flags; 195 ctx->flags |= flags;
196} 196}
197 197
198KRB5_LIB_FUNCTION int KRB5_LIB_CALL 198KRB5_LIB_FUNCTION int KRB5_LIB_CALL
199krb5_sendto_ctx_get_flags(krb5_sendto_ctx ctx) 199krb5_sendto_ctx_get_flags(krb5_sendto_ctx ctx)
200{ 200{
201 return ctx->flags; 201 return ctx->flags;
202} 202}
203 203
204KRB5_LIB_FUNCTION void KRB5_LIB_CALL 204KRB5_LIB_FUNCTION void KRB5_LIB_CALL
205krb5_sendto_ctx_set_type(krb5_sendto_ctx ctx, int type) 205krb5_sendto_ctx_set_type(krb5_sendto_ctx ctx, int type)
206{ 206{
207 ctx->type = type; 207 ctx->type = type;
208} 208}
209 209
210KRB5_LIB_FUNCTION void KRB5_LIB_CALL 210KRB5_LIB_FUNCTION void KRB5_LIB_CALL
211krb5_sendto_ctx_set_func(krb5_sendto_ctx ctx, 211krb5_sendto_ctx_set_func(krb5_sendto_ctx ctx,
212 krb5_sendto_ctx_func func, 212 krb5_sendto_ctx_func func,
213 void *data) 213 void *data)
214{ 214{
215 ctx->func = func; 215 ctx->func = func;
216 ctx->data = data; 216 ctx->data = data;
217} 217}
218 218
219KRB5_LIB_FUNCTION void KRB5_LIB_CALL 219KRB5_LIB_FUNCTION void KRB5_LIB_CALL
220_krb5_sendto_ctx_set_prexmit(krb5_sendto_ctx ctx, 220_krb5_sendto_ctx_set_prexmit(krb5_sendto_ctx ctx,
221 krb5_sendto_prexmit prexmit, 221 krb5_sendto_prexmit prexmit,
222 void *data) 222 void *data)
223{ 223{
224 ctx->prexmit_func = prexmit; 224 ctx->prexmit_func = prexmit;
225 ctx->prexmit_ctx = data; 225 ctx->prexmit_ctx = data;
226} 226}
227 227
228KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 228KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
229krb5_sendto_set_hostname(krb5_context context, 229krb5_sendto_set_hostname(krb5_context context,
230 krb5_sendto_ctx ctx, 230 krb5_sendto_ctx ctx,
231 const char *hostname) 231 const char *hostname)
232{ 232{
233 if (ctx->hostname == NULL) 233 if (ctx->hostname == NULL)
234 free(ctx->hostname); 234 free(ctx->hostname);
235 ctx->hostname = strdup(hostname); 235 ctx->hostname = strdup(hostname);
236 if (ctx->hostname == NULL) { 236 if (ctx->hostname == NULL) {
237 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 237 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
238 return ENOMEM; 238 return ENOMEM;
239 } 239 }
240 return 0; 240 return 0;
241} 241}
242 242
243KRB5_LIB_FUNCTION void KRB5_LIB_CALL 243KRB5_LIB_FUNCTION void KRB5_LIB_CALL
244_krb5_sendto_ctx_set_krb5hst(krb5_context context, 244_krb5_sendto_ctx_set_krb5hst(krb5_context context,
245 krb5_sendto_ctx ctx, 245 krb5_sendto_ctx ctx,
246 krb5_krbhst_handle handle) 246 krb5_krbhst_handle handle)
247{ 247{
248 heim_release(ctx->krbhst); 248 heim_release(ctx->krbhst);
249 ctx->krbhst = heim_retain(handle); 249 ctx->krbhst = heim_retain(handle);
250} 250}
251 251
252KRB5_LIB_FUNCTION void KRB5_LIB_CALL 252KRB5_LIB_FUNCTION void KRB5_LIB_CALL
253krb5_sendto_ctx_free(krb5_context context, krb5_sendto_ctx ctx) 253krb5_sendto_ctx_free(krb5_context context, krb5_sendto_ctx ctx)
254{ 254{
255 heim_release(ctx); 255 heim_release(ctx);
256} 256}
257 257
258KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 258KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
259_krb5_kdc_retry(krb5_context context, krb5_sendto_ctx ctx, void *data, 259_krb5_kdc_retry(krb5_context context, krb5_sendto_ctx ctx, void *data,
260 const krb5_data *reply, int *action) 260 const krb5_data *reply, int *action)
261{ 261{
262 krb5_error_code ret; 262 krb5_error_code ret;
263 KRB_ERROR error; 263 KRB_ERROR error;
264 264
265 if(krb5_rd_error(context, reply, &error)) 265 if(krb5_rd_error(context, reply, &error))
266 return 0; 266 return 0;
267 267
268 ret = krb5_error_from_rd_error(context, &error, NULL); 268 ret = krb5_error_from_rd_error(context, &error, NULL);
269 krb5_free_error_contents(context, &error); 269 krb5_free_error_contents(context, &error);
270 270
271 switch(ret) { 271 switch(ret) {
272 case KRB5KRB_ERR_RESPONSE_TOO_BIG: { 272 case KRB5KRB_ERR_RESPONSE_TOO_BIG: {
273 if (krb5_sendto_ctx_get_flags(ctx) & KRB5_KRBHST_FLAGS_LARGE_MSG) 273 if (krb5_sendto_ctx_get_flags(ctx) & KRB5_KRBHST_FLAGS_LARGE_MSG)
274 break; 274 break;
275 krb5_sendto_ctx_add_flags(ctx, KRB5_KRBHST_FLAGS_LARGE_MSG); 275 krb5_sendto_ctx_add_flags(ctx, KRB5_KRBHST_FLAGS_LARGE_MSG);
276 *action = KRB5_SENDTO_RESET; 276 *action = KRB5_SENDTO_RESET;
277 break; 277 break;
278 } 278 }
279 case KRB5KDC_ERR_SVC_UNAVAILABLE: 279 case KRB5KDC_ERR_SVC_UNAVAILABLE:
280 *action = KRB5_SENDTO_CONTINUE; 280 *action = KRB5_SENDTO_CONTINUE;
281 break; 281 break;
282 } 282 }
283 return 0; 283 return 0;
284} 284}
285 285
286/* 286/*
287 * 287 *
288 */ 288 */
289 289
290struct host; 290struct host;
291 291
292struct host_fun { 292struct host_fun {
293 krb5_error_code (*prepare)(krb5_context, struct host *, const krb5_data *); 293 krb5_error_code (*prepare)(krb5_context, struct host *, const krb5_data *);
294 krb5_error_code (*send_fn)(krb5_context, struct host *); 294 krb5_error_code (*send_fn)(krb5_context, struct host *);
295 krb5_error_code (*recv_fn)(krb5_context, struct host *, krb5_data *); 295 krb5_error_code (*recv_fn)(krb5_context, struct host *, krb5_data *);
296 int ntries; 296 int ntries;
297}; 297};
298 298
299struct host { 299struct host {
300 enum host_state { CONNECT, CONNECTING, CONNECTED, WAITING_REPLY, DEAD } state; 300 enum host_state { CONNECT, CONNECTING, CONNECTED, WAITING_REPLY, DEAD } state;
301 krb5_krbhst_info *hi; 301 krb5_krbhst_info *hi;
302 struct addrinfo *ai; 302 struct addrinfo *ai;
303 rk_socket_t fd; 303 rk_socket_t fd;
304 struct host_fun *fun; 304 struct host_fun *fun;
305 unsigned int tries; 305 unsigned int tries;
306 time_t timeout; 306 time_t timeout;
307 krb5_data data; 307 krb5_data data;
308 unsigned int tid; 308 unsigned int tid;
309}; 309};
310 310
311static void 311static void
312debug_host(krb5_context context, int level, struct host *host, const char *fmt, ...) 312debug_host(krb5_context context, int level, struct host *host, const char *fmt, ...)
313 __attribute__ ((__format__ (__printf__, 4, 5))); 313 __attribute__ ((__format__ (__printf__, 4, 5)));
314 314
315static void 315static void
316debug_host(krb5_context context, int level, struct host *host, const char *fmt, ...) 316debug_host(krb5_context context, int level, struct host *host, const char *fmt, ...)
317{ 317{
318 const char *proto = "unknown"; 318 const char *proto = "unknown";
319 char name[NI_MAXHOST], port[NI_MAXSERV]; 319 char name[NI_MAXHOST], port[NI_MAXSERV];
320 char *text = NULL; 320 char *text = NULL;
321 va_list ap; 321 va_list ap;
322 int ret; 322 int ret;
323 323
324 if (!_krb5_have_debug(context, 5)) 324 if (!_krb5_have_debug(context, 5))
325 return; 325 return;
326 326
327 va_start(ap, fmt); 327 va_start(ap, fmt);
328 ret = vasprintf(&text, fmt, ap); 328 ret = vasprintf(&text, fmt, ap);
329 va_end(ap); 329 va_end(ap);
330 if (ret == -1 || text == NULL) 330 if (ret == -1 || text == NULL)
331 return; 331 return;
332 332
333 if (host->hi->proto == KRB5_KRBHST_HTTP) 333 if (host->hi->proto == KRB5_KRBHST_HTTP)
334 proto = "http"; 334 proto = "http";
335 else if (host->hi->proto == KRB5_KRBHST_TCP) 335 else if (host->hi->proto == KRB5_KRBHST_TCP)
336 proto = "tcp"; 336 proto = "tcp";
337 else if (host->hi->proto == KRB5_KRBHST_UDP) 337 else if (host->hi->proto == KRB5_KRBHST_UDP)
338 proto = "udp"; 338 proto = "udp";
339 339
340 if (getnameinfo(host->ai->ai_addr, host->ai->ai_addrlen, 340 if (getnameinfo(host->ai->ai_addr, host->ai->ai_addrlen,
341 name, sizeof(name), port, sizeof(port), NI_NUMERICHOST) != 0) 341 name, sizeof(name), port, sizeof(port), NI_NUMERICHOST) != 0)
342 name[0] = '\0'; 342 name[0] = '\0';
343 343
344 _krb5_debug(context, level, "%s: %s %s:%s (%s) tid: %08x", text, 344 _krb5_debug(context, level, "%s: %s %s:%s (%s) tid: %08x", text,
345 proto, name, port, host->hi->hostname, host->tid); 345 proto, name, port, host->hi->hostname, host->tid);
346 free(text); 346 free(text);
347} 347}
348 348
349 349
350static void 350static void
351deallocate_host(void *ptr) 351deallocate_host(void *ptr)
352{ 352{
353 struct host *host = ptr; 353 struct host *host = ptr;
354 if (!rk_IS_BAD_SOCKET(host->fd)) 354 if (!rk_IS_BAD_SOCKET(host->fd))
355 rk_closesocket(host->fd); 355 rk_closesocket(host->fd);
356 krb5_data_free(&host->data); 356 krb5_data_free(&host->data);
357 host->ai = NULL; 357 host->ai = NULL;
358} 358}
359 359
360static void 360static void
361host_dead(krb5_context context, struct host *host, const char *msg) 361host_dead(krb5_context context, struct host *host, const char *msg)
362{ 362{
363 debug_host(context, 5, host, "%s", msg); 363 debug_host(context, 5, host, "%s", msg);
364 rk_closesocket(host->fd); 364 rk_closesocket(host->fd);
365 host->fd = rk_INVALID_SOCKET; 365 host->fd = rk_INVALID_SOCKET;
366 host->state = DEAD; 366 host->state = DEAD;
367} 367}
368 368
369static krb5_error_code 369static krb5_error_code
370send_stream(krb5_context context, struct host *host) 370send_stream(krb5_context context, struct host *host)
371{ 371{
372 ssize_t len; 372 ssize_t len;
373 373
374 len = krb5_net_write(context, &host->fd, host->data.data, host->data.length); 374 len = krb5_net_write(context, &host->fd, host->data.data, host->data.length);
375 375
376 if (len < 0) 376 if (len < 0)
377 return errno; 377 return errno;
378 else if (len < host->data.length) { 378 else if (len < host->data.length) {
379 host->data.length -= len; 379 host->data.length -= len;
380 memmove(host->data.data, ((uint8_t *)host->data.data) + len, host->data.length - len); 380 memmove(host->data.data, ((uint8_t *)host->data.data) + len, host->data.length - len);
381 return -1; 381 return -1;
382 } else { 382 } else {
383 krb5_data_free(&host->data); 383 krb5_data_free(&host->data);
384 return 0; 384 return 0;
385 } 385 }
386} 386}
387 387
388static krb5_error_code 388static krb5_error_code
389recv_stream(krb5_context context, struct host *host) 389recv_stream(krb5_context context, struct host *host)
390{ 390{
391 krb5_error_code ret; 391 krb5_error_code ret;
392 size_t oldlen; 392 size_t oldlen;
393 ssize_t sret; 393 ssize_t sret;
394 int nbytes; 394 int nbytes;
395 395
396 if (rk_SOCK_IOCTL(host->fd, FIONREAD, &nbytes) != 0 || nbytes <= 0) 396 if (rk_SOCK_IOCTL(host->fd, FIONREAD, &nbytes) != 0 || nbytes <= 0)
397 return HEIM_NET_CONN_REFUSED; 397 return HEIM_NET_CONN_REFUSED;
398 398
399 if (context->max_msg_size - host->data.length < nbytes) { 399 if (context->max_msg_size - host->data.length < nbytes) {
400 krb5_set_error_message(context, KRB5KRB_ERR_FIELD_TOOLONG, 400 krb5_set_error_message(context, KRB5KRB_ERR_FIELD_TOOLONG,
401 N_("TCP message from KDC too large %d", ""), 401 N_("TCP message from KDC too large %d", ""),
402 (int)(host->data.length + nbytes)); 402 (int)(host->data.length + nbytes));
403 return KRB5KRB_ERR_FIELD_TOOLONG; 403 return KRB5KRB_ERR_FIELD_TOOLONG;
404 } 404 }
405 405
406 oldlen = host->data.length; 406 oldlen = host->data.length;
407 407
408 ret = krb5_data_realloc(&host->data, oldlen + nbytes + 1 /* NUL */); 408 ret = krb5_data_realloc(&host->data, oldlen + nbytes + 1 /* NUL */);
409 if (ret) 409 if (ret)
410 return ret; 410 return ret;
411 411
412 sret = krb5_net_read(context, &host->fd, ((uint8_t *)host->data.data) + oldlen, nbytes); 412 sret = krb5_net_read(context, &host->fd, ((uint8_t *)host->data.data) + oldlen, nbytes);
413 if (sret <= 0) { 413 if (sret <= 0) {
414 ret = errno; 414 ret = errno;
415 return ret; 415 return ret;
416 } 416 }
417 host->data.length = oldlen + sret; 417 host->data.length = oldlen + sret;
418 /* zero terminate for http transport */ 418 /* zero terminate for http transport */
419 ((uint8_t *)host->data.data)[host->data.length] = '\0'; 419 ((uint8_t *)host->data.data)[host->data.length] = '\0';
420 420
421 return 0; 421 return 0;
422} 422}
423 423
424/* 424/*
425 * 425 *
426 */ 426 */
427 427
428static void 428static void
429host_next_timeout(krb5_context context, struct host *host) 429host_next_timeout(krb5_context context, struct host *host)
430{ 430{
431 host->timeout = context->kdc_timeout / host->fun->ntries; 431 host->timeout = context->kdc_timeout / host->fun->ntries;
432 if (host->timeout == 0) 432 if (host->timeout == 0)
433 host->timeout = 1; 433 host->timeout = 1;
434 434
435 host->timeout += time(NULL); 435 host->timeout += time(NULL);
436} 436}
437 437
438/* 438/*
439 * connected host 439 * connected host
440 */ 440 */
441 441
442static void 442static void
443host_connected(krb5_context context, krb5_sendto_ctx ctx, struct host *host) 443host_connected(krb5_context context, krb5_sendto_ctx ctx, struct host *host)
444{ 444{
445 krb5_error_code ret; 445 krb5_error_code ret;
446 446
447 host->state = CONNECTED;  447 host->state = CONNECTED;
448 /* 448 /*
449 * Now prepare data to send to host 449 * Now prepare data to send to host
450 */ 450 */
451 if (ctx->prexmit_func) { 451 if (ctx->prexmit_func) {
452 krb5_data data; 452 krb5_data data;
453  453
454 krb5_data_zero(&data); 454 krb5_data_zero(&data);
455 455
456 ret = ctx->prexmit_func(context, host->hi->proto, 456 ret = ctx->prexmit_func(context, host->hi->proto,
457 ctx->prexmit_ctx, host->fd, &data); 457 ctx->prexmit_ctx, host->fd, &data);
458 if (ret == 0) { 458 if (ret == 0) {
459 if (data.length == 0) { 459 if (data.length == 0) {
460 host_dead(context, host, "prexmit function didn't send data"); 460 host_dead(context, host, "prexmit function didn't send data");
461 return; 461 return;
462 } 462 }
463 ret = host->fun->prepare(context, host, &data); 463 ret = host->fun->prepare(context, host, &data);
464 krb5_data_free(&data); 464 krb5_data_free(&data);
465 } 465 }
466  466
467 } else { 467 } else {
468 ret = host->fun->prepare(context, host, ctx->send_data); 468 ret = host->fun->prepare(context, host, ctx->send_data);
469 } 469 }
470 if (ret) 470 if (ret)
471 debug_host(context, 5, host, "failed to prexmit/prepare"); 471 debug_host(context, 5, host, "failed to prexmit/prepare");
472} 472}
473 473
474/* 474/*
475 * connect host 475 * connect host
476 */ 476 */
477 477
478static void 478static void
479host_connect(krb5_context context, krb5_sendto_ctx ctx, struct host *host) 479host_connect(krb5_context context, krb5_sendto_ctx ctx, struct host *host)
480{ 480{
481 krb5_krbhst_info *hi = host->hi; 481 krb5_krbhst_info *hi = host->hi;
482 struct addrinfo *ai = host->ai; 482 struct addrinfo *ai = host->ai;
483 483
484 debug_host(context, 5, host, "connecting to host"); 484 debug_host(context, 5, host, "connecting to host");
485 485
486 if (connect(host->fd, ai->ai_addr, ai->ai_addrlen) < 0) { 486 if (connect(host->fd, ai->ai_addr, ai->ai_addrlen) < 0) {
487#ifdef HAVE_WINSOCK 487#ifdef HAVE_WINSOCK
488 if (WSAGetLastError() == WSAEWOULDBLOCK) 488 if (WSAGetLastError() == WSAEWOULDBLOCK)
489 errno = EINPROGRESS; 489 errno = EINPROGRESS;
490#endif /* HAVE_WINSOCK */ 490#endif /* HAVE_WINSOCK */
491 if (errno == EINPROGRESS && (hi->proto == KRB5_KRBHST_HTTP || hi->proto == KRB5_KRBHST_TCP)) { 491 if (errno == EINPROGRESS && (hi->proto == KRB5_KRBHST_HTTP || hi->proto == KRB5_KRBHST_TCP)) {
492 debug_host(context, 5, host, "connecting to %d", host->fd); 492 debug_host(context, 5, host, "connecting to %d", host->fd);
493 host->state = CONNECTING; 493 host->state = CONNECTING;
494 } else { 494 } else {
495 host_dead(context, host, "failed to connect"); 495 host_dead(context, host, "failed to connect");
496 } 496 }
497 } else { 497 } else {
498 host_connected(context, ctx, host); 498 host_connected(context, ctx, host);
499 } 499 }
500 500
501 host_next_timeout(context, host); 501 host_next_timeout(context, host);
502} 502}
503 503
504/* 504/*
505 * HTTP transport 505 * HTTP transport
506 */ 506 */
507 507
508static krb5_error_code 508static krb5_error_code
509prepare_http(krb5_context context, struct host *host, const krb5_data *data) 509prepare_http(krb5_context context, struct host *host, const krb5_data *data)
510{ 510{
511 char *str = NULL, *request = NULL; 511 char *str = NULL, *request = NULL;
512 krb5_error_code ret; 512 krb5_error_code ret;
513 int len; 513 int len;
514 514
515 heim_assert(host->data.length == 0, "prepare_http called twice"); 515 heim_assert(host->data.length == 0, "prepare_http called twice");
516 516
517 len = rk_base64_encode(data->data, data->length, &str); 517 len = rk_base64_encode(data->data, data->length, &str);
518 if(len < 0) 518 if(len < 0)
519 return ENOMEM; 519 return ENOMEM;
520 520
521 if (context->http_proxy) 521 if (context->http_proxy)
522 ret = asprintf(&request, "GET http://%s/%s HTTP/1.0\r\n\r\n", host->hi->hostname, str); 522 ret = asprintf(&request, "GET http://%s/%s HTTP/1.0\r\n\r\n", host->hi->hostname, str);
523 else 523 else
524 ret = asprintf(&request, "GET /%s HTTP/1.0\r\n\r\n", str); 524 ret = asprintf(&request, "GET /%s HTTP/1.0\r\n\r\n", str);
525 free(str); 525 free(str);
526 if(ret < 0 || request == NULL) 526 if(ret < 0 || request == NULL)
527 return ENOMEM; 527 return ENOMEM;
528  528
529 host->data.data = request; 529 host->data.data = request;
530 host->data.length = strlen(request); 530 host->data.length = strlen(request);
531 531
532 return 0; 532 return 0;
533} 533}
534 534
535static krb5_error_code 535static krb5_error_code
536recv_http(krb5_context context, struct host *host, krb5_data *data) 536recv_http(krb5_context context, struct host *host, krb5_data *data)
537{ 537{
538 krb5_error_code ret; 538 krb5_error_code ret;
539 unsigned long rep_len; 539 unsigned long rep_len;
540 size_t len; 540 size_t len;
541 char *p; 541 char *p;
542 542
543 /* 543 /*
544 * recv_stream returns a NUL terminated stream 544 * recv_stream returns a NUL terminated stream
545 */ 545 */
546 546
547 ret = recv_stream(context, host); 547 ret = recv_stream(context, host);
548 if (ret) 548 if (ret)
549 return ret; 549 return ret;
550 550
551 p = strstr(host->data.data, "\r\n\r\n"); 551 p = strstr(host->data.data, "\r\n\r\n");
552 if (p == NULL) 552 if (p == NULL)
553 return -1; 553 return -1;
554 p += 4; 554 p += 4;
555 555
556 len = host->data.length - (p - (char *)host->data.data); 556 len = host->data.length - (p - (char *)host->data.data);
557 if (len < 4) 557 if (len < 4)
558 return -1; 558 return -1;
559 559
560 _krb5_get_int(p, &rep_len, 4); 560 _krb5_get_int(p, &rep_len, 4);
561 if (len < rep_len) 561 if (len < rep_len)
562 return -1; 562 return -1;
563 563
564 p += 4; 564 p += 4;
565 565
566 memmove(host->data.data, p, rep_len); 566 memmove(host->data.data, p, rep_len);
567 host->data.length = rep_len; 567 host->data.length = rep_len;
568 568
569 *data = host->data; 569 *data = host->data;
570 krb5_data_zero(&host->data); 570 krb5_data_zero(&host->data);
571 571
572 return 0; 572 return 0;
573} 573}
574 574
575/* 575/*
576 * TCP transport 576 * TCP transport
577 */ 577 */
578 578
579static krb5_error_code 579static krb5_error_code
580prepare_tcp(krb5_context context, struct host *host, const krb5_data *data) 580prepare_tcp(krb5_context context, struct host *host, const krb5_data *data)
581{ 581{
582 krb5_error_code ret; 582 krb5_error_code ret;
583 krb5_storage *sp; 583 krb5_storage *sp;
584 584
585 heim_assert(host->data.length == 0, "prepare_tcp called twice"); 585 heim_assert(host->data.length == 0, "prepare_tcp called twice");
586 586
587 sp = krb5_storage_emem(); 587 sp = krb5_storage_emem();
588 if (sp == NULL) 588 if (sp == NULL)
589 return ENOMEM; 589 return ENOMEM;
590  590
591 ret = krb5_store_data(sp, *data); 591 ret = krb5_store_data(sp, *data);
592 if (ret) { 592 if (ret) {
593 krb5_storage_free(sp); 593 krb5_storage_free(sp);
594 return ret; 594 return ret;
595 } 595 }
596 ret = krb5_storage_to_data(sp, &host->data); 596 ret = krb5_storage_to_data(sp, &host->data);
597 krb5_storage_free(sp); 597 krb5_storage_free(sp);
598 598
599 return ret; 599 return ret;
600} 600}
601 601
602static krb5_error_code 602static krb5_error_code
603recv_tcp(krb5_context context, struct host *host, krb5_data *data) 603recv_tcp(krb5_context context, struct host *host, krb5_data *data)
604{ 604{
605 krb5_error_code ret; 605 krb5_error_code ret;
606 unsigned long pktlen; 606 unsigned long pktlen;
607 607
608 ret = recv_stream(context, host); 608 ret = recv_stream(context, host);
609 if (ret) 609 if (ret)
610 return ret; 610 return ret;
611 611
612 if (host->data.length < 4) 612 if (host->data.length < 4)
613 return -1; 613 return -1;
614 614
615 _krb5_get_int(host->data.data, &pktlen, 4); 615 _krb5_get_int(host->data.data, &pktlen, 4);
616  616
617 if (pktlen > host->data.length - 4) 617 if (pktlen > host->data.length - 4)
618 return -1; 618 return -1;
619 619
620 memmove(host->data.data, ((uint8_t *)host->data.data) + 4, host->data.length - 4); 620 memmove(host->data.data, ((uint8_t *)host->data.data) + 4, host->data.length - 4);
621 host->data.length -= 4; 621 host->data.length -= 4;
622 622
623 *data = host->data; 623 *data = host->data;
624 krb5_data_zero(&host->data); 624 krb5_data_zero(&host->data);
625  625
626 return 0; 626 return 0;
627} 627}
628 628
629/* 629/*
630 * UDP transport 630 * UDP transport
631 */ 631 */
632 632
633static krb5_error_code 633static krb5_error_code
634prepare_udp(krb5_context context, struct host *host, const krb5_data *data) 634prepare_udp(krb5_context context, struct host *host, const krb5_data *data)
635{ 635{
636 return krb5_data_copy(&host->data, data->data, data->length); 636 return krb5_data_copy(&host->data, data->data, data->length);
637} 637}
638 638
639static krb5_error_code 639static krb5_error_code
640send_udp(krb5_context context, struct host *host) 640send_udp(krb5_context context, struct host *host)
641{ 641{
642 if (send(host->fd, host->data.data, host->data.length, 0) < 0) 642 if (send(host->fd, host->data.data, host->data.length, 0) < 0)
643 return errno; 643 return errno;
644 return 0; 644 return 0;
645} 645}
646 646
647static krb5_error_code 647static krb5_error_code
648recv_udp(krb5_context context, struct host *host, krb5_data *data) 648recv_udp(krb5_context context, struct host *host, krb5_data *data)
649{ 649{
650 krb5_error_code ret; 650 krb5_error_code ret;
651 int nbytes; 651 int nbytes;
652 652
653 653
654 if (rk_SOCK_IOCTL(host->fd, FIONREAD, &nbytes) != 0 || nbytes <= 0) 654 if (rk_SOCK_IOCTL(host->fd, FIONREAD, &nbytes) != 0 || nbytes <= 0)
655 return HEIM_NET_CONN_REFUSED; 655 return HEIM_NET_CONN_REFUSED;
656 656
657 if (context->max_msg_size < nbytes) { 657 if (context->max_msg_size < nbytes) {
658 krb5_set_error_message(context, KRB5KRB_ERR_FIELD_TOOLONG, 658 krb5_set_error_message(context, KRB5KRB_ERR_FIELD_TOOLONG,
659 N_("UDP message from KDC too large %d", ""), 659 N_("UDP message from KDC too large %d", ""),
660 (int)nbytes); 660 (int)nbytes);
661 return KRB5KRB_ERR_FIELD_TOOLONG; 661 return KRB5KRB_ERR_FIELD_TOOLONG;
662 } 662 }
663 663
664 ret = krb5_data_alloc(data, nbytes); 664 ret = krb5_data_alloc(data, nbytes);
665 if (ret) 665 if (ret)
666 return ret; 666 return ret;
667 667
668 ret = recv(host->fd, data->data, data->length, 0); 668 ret = recv(host->fd, data->data, data->length, 0);
669 if (ret < 0) { 669 if (ret < 0) {
670 ret = errno; 670 ret = errno;
671 krb5_data_free(data); 671 krb5_data_free(data);
672 return ret; 672 return ret;
673 } 673 }
674 data->length = ret; 674 data->length = ret;
675 675
676 return 0; 676 return 0;
677} 677}
678 678
679static struct host_fun http_fun = { 679static struct host_fun http_fun = {
680 prepare_http, 680 prepare_http,
681 send_stream, 681 send_stream,
682 recv_http, 682 recv_http,
683 1 683 1
684}; 684};
685static struct host_fun tcp_fun = { 685static struct host_fun tcp_fun = {
686 prepare_tcp, 686 prepare_tcp,
687 send_stream, 687 send_stream,
688 recv_tcp, 688 recv_tcp,
689 1 689 1
690}; 690};
691static struct host_fun udp_fun = { 691static struct host_fun udp_fun = {
692 prepare_udp, 692 prepare_udp,
693 send_udp, 693 send_udp,
694 recv_udp, 694 recv_udp,
695 3 695 3
696}; 696};
697 697
698 698
699/* 699/*
700 * Host state machine 700 * Host state machine
701 */ 701 */
702 702
703static int 703static int
704eval_host_state(krb5_context context, 704eval_host_state(krb5_context context,
705 krb5_sendto_ctx ctx, 705 krb5_sendto_ctx ctx,
706 struct host *host, 706 struct host *host,
707 int readable, int writeable) 707 int readable, int writeable)
708{ 708{
709 krb5_error_code ret; 709 krb5_error_code ret;
710 710
711 if (host->state == CONNECT) { 711 if (host->state == CONNECT) {
712 /* check if its this host time to connect */ 712 /* check if its this host time to connect */
713 if (host->timeout < time(NULL)) 713 if (host->timeout < time(NULL))
714 host_connect(context, ctx, host); 714 host_connect(context, ctx, host);
715 return 0; 715 return 0;
716 } 716 }
717 717
718 if (host->state == CONNECTING && writeable) 718 if (host->state == CONNECTING && writeable)
719 host_connected(context, ctx, host); 719 host_connected(context, ctx, host);
720 720
721 if (readable) { 721 if (readable) {
722 722
723 debug_host(context, 5, host, "reading packet"); 723 debug_host(context, 5, host, "reading packet");
724 724
725 ret = host->fun->recv_fn(context, host, &ctx->response); 725 ret = host->fun->recv_fn(context, host, &ctx->response);
726 if (ret == -1) { 726 if (ret == -1) {
727 /* not done yet */ 727 /* not done yet */
728 } else if (ret == 0) { 728 } else if (ret == 0) {
729 /* if recv_foo function returns 0, we have a complete reply */ 729 /* if recv_foo function returns 0, we have a complete reply */
730 debug_host(context, 5, host, "host completed"); 730 debug_host(context, 5, host, "host completed");
731 return 1; 731 return 1;
732 } else { 732 } else {
733 host_dead(context, host, "host disconnected"); 733 host_dead(context, host, "host disconnected");
734 } 734 }
735 } 735 }
736 736
737 /* check if there is anything to send, state might DEAD after read */ 737 /* check if there is anything to send, state might DEAD after read */
738 if (writeable && host->state == CONNECTED) { 738 if (writeable && host->state == CONNECTED) {
739 739
740 ctx->stats.sent_packets++; 740 ctx->stats.sent_packets++;
741 741
742 debug_host(context, 5, host, "writing packet"); 742 debug_host(context, 5, host, "writing packet");
743 743
744 ret = host->fun->send_fn(context, host); 744 ret = host->fun->send_fn(context, host);
745 if (ret == -1) { 745 if (ret == -1) {
746 /* not done yet */ 746 /* not done yet */
747 } else if (ret) { 747 } else if (ret) {
748 host_dead(context, host, "host dead, write failed"); 748 host_dead(context, host, "host dead, write failed");
749 } else 749 } else
750 host->state = WAITING_REPLY; 750 host->state = WAITING_REPLY;
751 } 751 }
752 752
753 return 0; 753 return 0;
754} 754}
755 755
756/* 756/*
757 * 757 *
758 */ 758 */
759 759
760static krb5_error_code 760static krb5_error_code
761submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi) 761submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
762{ 762{
763 unsigned long submitted_host = 0; 763 unsigned long submitted_host = 0;
764 krb5_boolean freeai = FALSE; 764 krb5_boolean freeai = FALSE;
765 struct timeval nrstart, nrstop; 765 struct timeval nrstart, nrstop;
766 krb5_error_code ret; 766 krb5_error_code ret;
767 struct addrinfo *ai = NULL, *a; 767 struct addrinfo *ai = NULL, *a;
768 struct host *host; 768 struct host *host;
769 769
770 ret = kdc_via_plugin(context, hi, context->kdc_timeout, 770 ret = kdc_via_plugin(context, hi, context->kdc_timeout,
771 ctx->send_data, &ctx->response); 771 ctx->send_data, &ctx->response);
772 if (ret == 0) { 772 if (ret == 0) {
773 return 0; 773 return 0;
774 } else if (ret != KRB5_PLUGIN_NO_HANDLE) { 774 } else if (ret != KRB5_PLUGIN_NO_HANDLE) {
775 _krb5_debug(context, 5, "send via plugin failed %s: %d", 775 _krb5_debug(context, 5, "send via plugin failed %s: %d",
776 hi->hostname, ret); 776 hi->hostname, ret);
777 return ret; 777 return ret;
778 } 778 }
779 779
780 /* 780 /*
781 * If we have a proxy, let use the address of the proxy instead of 781 * If we have a proxy, let use the address of the proxy instead of
782 * the KDC and let the proxy deal with the resolving of the KDC. 782 * the KDC and let the proxy deal with the resolving of the KDC.
783 */ 783 */
784 784
785 gettimeofday(&nrstart, NULL); 785 gettimeofday(&nrstart, NULL);
786 786
787 if (hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) { 787 if (hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) {
788 char *proxy2 = strdup(context->http_proxy); 788 char *proxy2 = strdup(context->http_proxy);
789 char *el, *proxy = proxy2; 789 char *el, *proxy = proxy2;
790 struct addrinfo hints; 790 struct addrinfo hints;
791 char portstr[NI_MAXSERV]; 791 char portstr[NI_MAXSERV];
792 unsigned short nport; 792 unsigned short nport;
793  793
794 if (proxy == NULL) 794 if (proxy == NULL)
795 return ENOMEM; 795 return ENOMEM;
796 if (strncmp(proxy, "http://", 7) == 0) 796 if (strncmp(proxy, "http://", 7) == 0)
797 proxy += 7; 797 proxy += 7;
798  798
799 /* check for url terminating slash */ 799 /* check for url terminating slash */
800 el = strchr(proxy, '/'); 800 el = strchr(proxy, '/');
801 if (el != NULL) 801 if (el != NULL)
802 *el = '\0'; 802 *el = '\0';
803 803
804 /* check for port in hostname, used below as port */ 804 /* check for port in hostname, used below as port */
805 el = strchr(proxy, ':'); 805 el = strchr(proxy, ':');
806 if(el != NULL) 806 if(el != NULL)
807 *el++ = '\0'; 807 *el++ = '\0';
808 808
809 memset(&hints, 0, sizeof(hints)); 809 memset(&hints, 0, sizeof(hints));
810 hints.ai_family = PF_UNSPEC; 810 hints.ai_family = PF_UNSPEC;
811 hints.ai_socktype = SOCK_STREAM; 811 hints.ai_socktype = SOCK_STREAM;
812 812
813 /* On some systems ntohs(foo(..., htons(...))) causes shadowing */ 813 /* On some systems ntohs(foo(..., htons(...))) causes shadowing */
814 nport = init_port(el, htons(80)); 814 nport = init_port(el, htons(80));
815 snprintf(portstr, sizeof(portstr), "%d", ntohs(nport)); 815 snprintf(portstr, sizeof(portstr), "%d", ntohs(nport));
816 816
817 ret = getaddrinfo(proxy, portstr, &hints, &ai); 817 ret = getaddrinfo(proxy, portstr, &hints, &ai);
818 free(proxy2); 818 free(proxy2);
819 if (ret) 819 if (ret)
820 return krb5_eai_to_heim_errno(ret, errno); 820 return krb5_eai_to_heim_errno(ret, errno);
821  821
822 freeai = TRUE; 822 freeai = TRUE;
823 823
824 } else { 824 } else {
825 ret = krb5_krbhst_get_addrinfo(context, hi, &ai); 825 ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
826 if (ret) 826 if (ret)
827 return ret; 827 return ret;
828 } 828 }
829 829
830 /* add up times */ 830 /* add up times */
831 gettimeofday(&nrstop, NULL); 831 gettimeofday(&nrstop, NULL);
832 timevalsub(&nrstop, &nrstart); 832 timevalsub(&nrstop, &nrstart);
833 timevaladd(&ctx->stats.name_resolution, &nrstop); 833 timevaladd(&ctx->stats.name_resolution, &nrstop);
834 834
835 ctx->stats.num_hosts++; 835 ctx->stats.num_hosts++;
836 836
837 for (a = ai; a != NULL; a = a->ai_next) { 837 for (a = ai; a != NULL; a = a->ai_next) {
838 rk_socket_t fd; 838 rk_socket_t fd;
839 839
840 fd = socket(a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol); 840 fd = socket(a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
841 if (rk_IS_BAD_SOCKET(fd)) 841 if (rk_IS_BAD_SOCKET(fd))
842 continue; 842 continue;
843 rk_cloexec(fd); 843 rk_cloexec(fd);
844 844
845#ifndef NO_LIMIT_FD_SETSIZE 845#ifndef NO_LIMIT_FD_SETSIZE
846 if (fd >= FD_SETSIZE) { 846 if (fd >= FD_SETSIZE) {
847 _krb5_debug(context, 0, "fd too large for select"); 847 _krb5_debug(context, 0, "fd too large for select");
848 rk_closesocket(fd); 848 rk_closesocket(fd);
849 continue; 849 continue;
850 } 850 }
851#endif 851#endif
852 socket_set_nonblocking(fd, 1); 852 socket_set_nonblocking(fd, 1);
853 853
854 host = heim_alloc(sizeof(*host), "sendto-host", deallocate_host); 854 host = heim_alloc(sizeof(*host), "sendto-host", deallocate_host);
855 if (host == NULL) { 855 if (host == NULL) {
856 if (freeai) 856 if (freeai)
857 freeaddrinfo(ai); 857 freeaddrinfo(ai);
858 rk_closesocket(fd); 858 rk_closesocket(fd);
859 return ENOMEM; 859 return ENOMEM;
860 } 860 }
861 host->hi = hi; 861 host->hi = hi;
862 host->fd = fd; 862 host->fd = fd;
863 host->ai = a; 863 host->ai = a;
864 /* next version of stid */ 864 /* next version of stid */
865 host->tid = ctx->stid = (ctx->stid & 0xffff0000) | ((ctx->stid & 0xffff) + 1); 865 host->tid = ctx->stid = (ctx->stid & 0xffff0000) | ((ctx->stid & 0xffff) + 1);
866 866
867 host->state = CONNECT; 867 host->state = CONNECT;
868 868
869 switch (host->hi->proto) { 869 switch (host->hi->proto) {
870 case KRB5_KRBHST_HTTP : 870 case KRB5_KRBHST_HTTP :
871 host->fun = &http_fun; 871 host->fun = &http_fun;
872 break; 872 break;
873 case KRB5_KRBHST_TCP : 873 case KRB5_KRBHST_TCP :
874 host->fun = &tcp_fun; 874 host->fun = &tcp_fun;
875 break; 875 break;
876 case KRB5_KRBHST_UDP : 876 case KRB5_KRBHST_UDP :
877 host->fun = &udp_fun; 877 host->fun = &udp_fun;
878 break; 878 break;
879 default: 879 default:
880 heim_abort("undefined http transport protocol: %d", (int)host->hi->proto); 880 heim_abort("undefined http transport protocol: %d", (int)host->hi->proto);
881 } 881 }
882 882
883 host->tries = host->fun->ntries; 883 host->tries = host->fun->ntries;
884 884
885 /* 885 /*
886 * Connect directly next host, wait a host_timeout for each next address 886 * Connect directly next host, wait a host_timeout for each next address
887 */ 887 */
888 if (submitted_host == 0) 888 if (submitted_host == 0)
889 host_connect(context, ctx, host); 889 host_connect(context, ctx, host);
890 else { 890 else {
891 debug_host(context, 5, host, 891 debug_host(context, 5, host,
892 "Queuing host in future (in %ds), its the %lu address on the same name", 892 "Queuing host in future (in %ds), its the %lu address on the same name",
893 (int)(context->host_timeout * submitted_host), submitted_host + 1); 893 (int)(context->host_timeout * submitted_host), submitted_host + 1);
894 host->timeout = time(NULL) + (submitted_host * context->host_timeout); 894 host->timeout = time(NULL) + (submitted_host * context->host_timeout);
895 } 895 }
896 896
897 heim_array_append_value(ctx->hosts, host); 897 heim_array_append_value(ctx->hosts, host);
898 898
899 heim_release(host); 899 heim_release(host);
900 900
901 submitted_host++; 901 submitted_host++;
902 } 902 }
903 903
904 if (freeai) 904 if (freeai)
905 freeaddrinfo(ai); 905 freeaddrinfo(ai);
906 906
907 if (!submitted_host) 907 if (!submitted_host)
908 return KRB5_KDC_UNREACH; 908 return KRB5_KDC_UNREACH;
909 909
910 return 0; 910 return 0;
911} 911}
912 912
913struct wait_ctx { 913struct wait_ctx {
914 krb5_context context; 914 krb5_context context;
915 krb5_sendto_ctx ctx; 915 krb5_sendto_ctx ctx;
916 fd_set rfds; 916 fd_set rfds;
917 fd_set wfds; 917 fd_set wfds;
918 unsigned max_fd; 918 unsigned max_fd;
919 int got_reply; 919 int got_reply;
920 time_t timenow; 920 time_t timenow;
921}; 921};
922 922
923static void 923static void
924wait_setup(heim_object_t obj, void *iter_ctx, int *stop) 924wait_setup(heim_object_t obj, void *iter_ctx, int *stop)
925{ 925{
926 struct wait_ctx *wait_ctx = iter_ctx; 926 struct wait_ctx *wait_ctx = iter_ctx;
927 struct host *h = (struct host *)obj; 927 struct host *h = (struct host *)obj;
928 928
929 /* skip dead hosts */ 929 /* skip dead hosts */
930 if (h->state == DEAD) 930 if (h->state == DEAD)
931 return; 931 return;
932 932
933 if (h->state == CONNECT) { 933 if (h->state == CONNECT) {
934 if (h->timeout < wait_ctx->timenow) 934 if (h->timeout < wait_ctx->timenow)
935 host_connect(wait_ctx->context, wait_ctx->ctx, h); 935 host_connect(wait_ctx->context, wait_ctx->ctx, h);
936 return; 936 return;
937 } 937 }
938 938
939 /* if host timed out, dec tries and (retry or kill host) */ 939 /* if host timed out, dec tries and (retry or kill host) */
940 if (h->timeout < wait_ctx->timenow) { 940 if (h->timeout < wait_ctx->timenow) {
941 heim_assert(h->tries != 0, "tries should not reach 0"); 941 heim_assert(h->tries != 0, "tries should not reach 0");
942 h->tries--; 942 h->tries--;
943 if (h->tries == 0) { 943 if (h->tries == 0) {
944 host_dead(wait_ctx->context, h, "host timed out"); 944 host_dead(wait_ctx->context, h, "host timed out");
945 return; 945 return;
946 } else { 946 } else {
947 debug_host(wait_ctx->context, 5, h, "retrying sending to"); 947 debug_host(wait_ctx->context, 5, h, "retrying sending to");
948 host_next_timeout(wait_ctx->context, h); 948 host_next_timeout(wait_ctx->context, h);
949 host_connected(wait_ctx->context, wait_ctx->ctx, h); 949 host_connected(wait_ctx->context, wait_ctx->ctx, h);
950 } 950 }
951 } 951 }
952  952
953#ifndef NO_LIMIT_FD_SETSIZE 953#ifndef NO_LIMIT_FD_SETSIZE
954 heim_assert(h->fd < FD_SETSIZE, "fd too large"); 954 heim_assert(h->fd < FD_SETSIZE, "fd too large");
955#endif 955#endif
956 switch (h->state) { 956 switch (h->state) {
957 case WAITING_REPLY: 957 case WAITING_REPLY:
958 FD_SET(h->fd, &wait_ctx->rfds); 958 FD_SET(h->fd, &wait_ctx->rfds);
959 break; 959 break;
960 case CONNECTING: 960 case CONNECTING:
961 case CONNECTED: 961 case CONNECTED:
962 FD_SET(h->fd, &wait_ctx->rfds); 962 FD_SET(h->fd, &wait_ctx->rfds);
963 FD_SET(h->fd, &wait_ctx->wfds); 963 FD_SET(h->fd, &wait_ctx->wfds);
964 break; 964 break;
965 default: 965 default:
966 heim_abort("invalid sendto host state"); 966 heim_abort("invalid sendto host state");
967 } 967 }
968 if (h->fd > wait_ctx->max_fd) 968 if (h->fd > wait_ctx->max_fd)
969 wait_ctx->max_fd = h->fd; 969 wait_ctx->max_fd = h->fd;
970} 970}
971 971
972static int 972static int
973wait_filter_dead(heim_object_t obj, void *ctx) 973wait_filter_dead(heim_object_t obj, void *ctx)
974{ 974{
975 struct host *h = (struct host *)obj; 975 struct host *h = (struct host *)obj;
976 return (int)((h->state == DEAD) ? true : false); 976 return (int)((h->state == DEAD) ? true : false);
977} 977}
978 978
979static void 979static void
980wait_process(heim_object_t obj, void *ctx, int *stop) 980wait_process(heim_object_t obj, void *ctx, int *stop)
981{ 981{
982 struct wait_ctx *wait_ctx = ctx; 982 struct wait_ctx *wait_ctx = ctx;
983 struct host *h = (struct host *)obj; 983 struct host *h = (struct host *)obj;
984 int readable, writeable; 984 int readable, writeable;
985 heim_assert(h->state != DEAD, "dead host resurected"); 985 heim_assert(h->state != DEAD, "dead host resurected");
986 986
987#ifndef NO_LIMIT_FD_SETSIZE 987#ifndef NO_LIMIT_FD_SETSIZE
988 heim_assert(h->fd < FD_SETSIZE, "fd too large"); 988 heim_assert(h->fd < FD_SETSIZE, "fd too large");
989#endif 989#endif
990 readable = FD_ISSET(h->fd, &wait_ctx->rfds); 990 readable = FD_ISSET(h->fd, &wait_ctx->rfds);
991 writeable = FD_ISSET(h->fd, &wait_ctx->wfds); 991 writeable = FD_ISSET(h->fd, &wait_ctx->wfds);
992 992
993 if (readable || writeable || h->state == CONNECT) 993 if (readable || writeable || h->state == CONNECT)
994 wait_ctx->got_reply |= eval_host_state(wait_ctx->context, wait_ctx->ctx, h, readable, writeable); 994 wait_ctx->got_reply |= eval_host_state(wait_ctx->context, wait_ctx->ctx, h, readable, writeable);
995 995
996 /* if there is already a reply, just fall though the array */ 996 /* if there is already a reply, just fall though the array */
997 if (wait_ctx->got_reply) 997 if (wait_ctx->got_reply)
998 *stop = 1; 998 *stop = 1;
999} 999}
1000 1000
1001static krb5_error_code 1001static krb5_error_code
1002wait_response(krb5_context context, int *action, krb5_sendto_ctx ctx) 1002wait_response(krb5_context context, int *action, krb5_sendto_ctx ctx)
1003{ 1003{
1004 struct wait_ctx wait_ctx; 1004 struct wait_ctx wait_ctx;
1005 struct timeval tv; 1005 struct timeval tv;
1006 int ret; 1006 int ret;
1007 1007
1008 wait_ctx.context = context; 1008 wait_ctx.context = context;
1009 wait_ctx.ctx = ctx; 1009 wait_ctx.ctx = ctx;
1010 FD_ZERO(&wait_ctx.rfds); 1010 FD_ZERO(&wait_ctx.rfds);
1011 FD_ZERO(&wait_ctx.wfds); 1011 FD_ZERO(&wait_ctx.wfds);
1012 wait_ctx.max_fd = 0; 1012 wait_ctx.max_fd = 0;
1013 1013
1014 /* oh, we have a reply, it must be a plugin that got it for us */ 1014 /* oh, we have a reply, it must be a plugin that got it for us */
1015 if (ctx->response.length) { 1015 if (ctx->response.length) {
1016 *action = KRB5_SENDTO_FILTER; 1016 *action = KRB5_SENDTO_FILTER;
1017 return 0; 1017 return 0;
1018 } 1018 }
1019 1019
1020 wait_ctx.timenow = time(NULL); 1020 wait_ctx.timenow = time(NULL);
1021 1021
1022 heim_array_iterate_f(ctx->hosts, &wait_ctx, wait_setup); 1022 heim_array_iterate_f(ctx->hosts, &wait_ctx, wait_setup);
1023 heim_array_filter_f(ctx->hosts, &wait_ctx, wait_filter_dead); 1023 heim_array_filter_f(ctx->hosts, &wait_ctx, wait_filter_dead);
1024 1024
1025 if (heim_array_get_length(ctx->hosts) == 0) { 1025 if (heim_array_get_length(ctx->hosts) == 0) {
1026 if (ctx->stateflags & KRBHST_COMPLETED) { 1026 if (ctx->stateflags & KRBHST_COMPLETED) {
1027 _krb5_debug(context, 5, "no more hosts to send/recv packets to/from " 1027 _krb5_debug(context, 5, "no more hosts to send/recv packets to/from "
1028 "trying to pulling more hosts"); 1028 "trying to pulling more hosts");
1029 *action = KRB5_SENDTO_FAILED; 1029 *action = KRB5_SENDTO_FAILED;
1030 } else { 1030 } else {
1031 _krb5_debug(context, 5, "no more hosts to send/recv packets to/from " 1031 _krb5_debug(context, 5, "no more hosts to send/recv packets to/from "
1032 "and no more hosts -> failure"); 1032 "and no more hosts -> failure");
1033 *action = KRB5_SENDTO_TIMEOUT; 1033 *action = KRB5_SENDTO_TIMEOUT;
1034 } 1034 }
1035 return 0; 1035 return 0;
1036 } 1036 }
1037 1037
1038 tv.tv_sec = 1; 1038 tv.tv_sec = 1;
1039 tv.tv_usec = 0; 1039 tv.tv_usec = 0;
1040 1040
1041 ret = select(wait_ctx.max_fd + 1, &wait_ctx.rfds, &wait_ctx.wfds, NULL, &tv); 1041 ret = select(wait_ctx.max_fd + 1, &wait_ctx.rfds, &wait_ctx.wfds, NULL, &tv);
1042 if (ret < 0) 1042 if (ret < 0)
1043 return errno; 1043 return errno;
1044 if (ret == 0) { 1044 if (ret == 0) {
1045 *action = KRB5_SENDTO_TIMEOUT; 1045 *action = KRB5_SENDTO_TIMEOUT;
1046 return 0; 1046 return 0;
1047 } 1047 }
1048 1048
1049 wait_ctx.got_reply = 0; 1049 wait_ctx.got_reply = 0;
1050 heim_array_iterate_f(ctx->hosts, &wait_ctx, wait_process); 1050 heim_array_iterate_f(ctx->hosts, &wait_ctx, wait_process);
1051 if (wait_ctx.got_reply) 1051 if (wait_ctx.got_reply)
1052 *action = KRB5_SENDTO_FILTER; 1052 *action = KRB5_SENDTO_FILTER;
1053 else 1053 else
1054 *action = KRB5_SENDTO_CONTINUE; 1054 *action = KRB5_SENDTO_CONTINUE;
1055 1055
1056 return 0; 1056 return 0;
1057} 1057}
1058 1058
1059static void 1059static void
1060reset_context(krb5_context context, krb5_sendto_ctx ctx) 1060reset_context(krb5_context context, krb5_sendto_ctx ctx)
1061{ 1061{
1062 krb5_data_free(&ctx->response); 1062 krb5_data_free(&ctx->response);
1063 heim_release(ctx->hosts); 1063 heim_release(ctx->hosts);
1064 ctx->hosts = heim_array_create(); 1064 ctx->hosts = heim_array_create();
1065 ctx->stateflags = 0; 1065 ctx->stateflags = 0;
1066} 1066}
1067 1067
1068 1068
1069/* 1069/*
1070 * 1070 *
1071 */ 1071 */
1072 1072
1073KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1073KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1074krb5_sendto_context(krb5_context context, 1074krb5_sendto_context(krb5_context context,
1075 krb5_sendto_ctx ctx, 1075 krb5_sendto_ctx ctx,
1076 const krb5_data *send_data, 1076 const krb5_data *send_data,
1077 krb5_const_realm realm, 1077 krb5_const_realm realm,
1078 krb5_data *receive) 1078 krb5_data *receive)
1079{ 1079{
1080 krb5_error_code ret = 0; 1080 krb5_error_code ret = 0;
1081 krb5_krbhst_handle handle = NULL; 1081 krb5_krbhst_handle handle = NULL;
1082 struct timeval nrstart, nrstop, stop_time; 1082 struct timeval nrstart, nrstop, stop_time;
1083 int type, freectx = 0; 1083 int type, freectx = 0;
1084 int action; 1084 int action;
1085 int numreset = 0; 1085 int numreset = 0;
1086 1086
1087 krb5_data_zero(receive); 1087 krb5_data_zero(receive);
1088  1088
1089 if (ctx == NULL) { 1089 if (ctx == NULL) {
1090 ret = krb5_sendto_ctx_alloc(context, &ctx); 1090 ret = krb5_sendto_ctx_alloc(context, &ctx);
1091 if (ret) 1091 if (ret)
1092 goto out; 1092 goto out;
1093 freectx = 1; 1093 freectx = 1;
1094 } 1094 }
1095 1095
1096 ctx->stid = (context->num_kdc_requests++) << 16; 1096 ctx->stid = (context->num_kdc_requests++) << 16;
1097 1097
1098 memset(&ctx->stats, 0, sizeof(ctx->stats)); 1098 memset(&ctx->stats, 0, sizeof(ctx->stats));
1099 gettimeofday(&ctx->stats.start_time, NULL); 1099 gettimeofday(&ctx->stats.start_time, NULL);
1100 1100
1101 type = ctx->type; 1101 type = ctx->type;
1102 if (type == 0) { 1102 if (type == 0) {
1103 if ((ctx->flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) 1103 if ((ctx->flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc)
1104 type = KRB5_KRBHST_ADMIN; 1104 type = KRB5_KRBHST_ADMIN;
1105 else 1105 else
1106 type = KRB5_KRBHST_KDC; 1106 type = KRB5_KRBHST_KDC;
1107 } 1107 }
1108 1108
1109 ctx->send_data = send_data; 1109 ctx->send_data = send_data;
1110 1110
1111 if ((int)send_data->length > context->large_msg_size) 1111 if ((int)send_data->length > context->large_msg_size)
1112 ctx->flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; 1112 ctx->flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
1113 1113
1114 /* loop until we get back a appropriate response */ 1114 /* loop until we get back a appropriate response */
1115 1115
1116 action = KRB5_SENDTO_INITIAL; 1116 action = KRB5_SENDTO_INITIAL;
1117 1117
1118 while (action != KRB5_SENDTO_DONE && action != KRB5_SENDTO_FAILED) { 1118 while (action != KRB5_SENDTO_DONE && action != KRB5_SENDTO_FAILED) {
1119 krb5_krbhst_info *hi; 1119 krb5_krbhst_info *hi;
1120 1120
1121 switch (action) { 1121 switch (action) {
1122 case KRB5_SENDTO_INITIAL: 1122 case KRB5_SENDTO_INITIAL:
1123 ret = realm_via_plugin(context, realm, context->kdc_timeout, 1123 ret = realm_via_plugin(context, realm, context->kdc_timeout,
1124 send_data, &ctx->response); 1124 send_data, &ctx->response);
1125 if (ret == 0 || ret != KRB5_PLUGIN_NO_HANDLE) { 1125 if (ret == 0 || ret != KRB5_PLUGIN_NO_HANDLE) {
1126 action = KRB5_SENDTO_DONE; 1126 action = KRB5_SENDTO_DONE;
1127 break; 1127 break;
1128 } 1128 }
1129 action = KRB5_SENDTO_KRBHST; 1129 action = KRB5_SENDTO_KRBHST;
1130 /* FALLTHOUGH */ 1130 /* FALLTHOUGH */
1131 case KRB5_SENDTO_KRBHST: 1131 case KRB5_SENDTO_KRBHST:
1132 if (ctx->krbhst == NULL) { 1132 if (ctx->krbhst == NULL) {
1133 ret = krb5_krbhst_init_flags(context, realm, type, 1133 ret = krb5_krbhst_init_flags(context, realm, type,
1134 ctx->flags, &handle); 1134 ctx->flags, &handle);
1135 if (ret) 1135 if (ret)
1136 goto out; 1136 goto out;
1137 1137
1138 if (ctx->hostname) { 1138 if (ctx->hostname) {
1139 ret = krb5_krbhst_set_hostname(context, handle, ctx->hostname); 1139 ret = krb5_krbhst_set_hostname(context, handle, ctx->hostname);
1140 if (ret) 1140 if (ret)
1141 goto out; 1141 goto out;
1142 } 1142 }
1143 1143
1144 } else { 1144 } else {
1145 handle = heim_retain(ctx->krbhst); 1145 handle = heim_retain(ctx->krbhst);
1146 } 1146 }
1147 action = KRB5_SENDTO_TIMEOUT; 1147 action = KRB5_SENDTO_TIMEOUT;
1148 /* FALLTHOUGH */ 1148 /* FALLTHOUGH */
1149 case KRB5_SENDTO_TIMEOUT: 1149 case KRB5_SENDTO_TIMEOUT:
1150 1150
1151 /* 1151 /*
1152 * If we completed, just got to next step 1152 * If we completed, just got to next step
1153 */ 1153 */
1154 1154
1155 if (ctx->stateflags & KRBHST_COMPLETED) { 1155 if (ctx->stateflags & KRBHST_COMPLETED) {
1156 action = KRB5_SENDTO_CONTINUE; 1156 action = KRB5_SENDTO_CONTINUE;
1157 break; 1157 break;
1158 } 1158 }
1159 1159
1160 /* 1160 /*
1161 * Pull out next host, if there is no more, close the 1161 * Pull out next host, if there is no more, close the
1162 * handle and mark as completed. 1162 * handle and mark as completed.
1163 * 1163 *
1164 * Collect time spent in krbhst (dns, plugin, etc) 1164 * Collect time spent in krbhst (dns, plugin, etc)
1165 */ 1165 */
1166 1166
1167 1167
1168 gettimeofday(&nrstart, NULL); 1168 gettimeofday(&nrstart, NULL);
1169 1169
1170 ret = krb5_krbhst_next(context, handle, &hi); 1170 ret = krb5_krbhst_next(context, handle, &hi);
1171 1171
1172 gettimeofday(&nrstop, NULL); 1172 gettimeofday(&nrstop, NULL);
1173 timevalsub(&nrstop, &nrstart); 1173 timevalsub(&nrstop, &nrstart);
1174 timevaladd(&ctx->stats.krbhst, &nrstop); 1174 timevaladd(&ctx->stats.krbhst, &nrstop);
1175 1175
1176 action = KRB5_SENDTO_CONTINUE; 1176 action = KRB5_SENDTO_CONTINUE;
1177 if (ret == 0) { 1177 if (ret == 0) {
1178 _krb5_debug(context, 5, "submissing new requests to new host"); 1178 _krb5_debug(context, 5, "submissing new requests to new host");
1179 if (submit_request(context, ctx, hi) != 0) 1179 if (submit_request(context, ctx, hi) != 0)
1180 action = KRB5_SENDTO_TIMEOUT; 1180 action = KRB5_SENDTO_TIMEOUT;
1181 } else { 1181 } else {
1182 _krb5_debug(context, 5, "out of hosts, waiting for replies"); 1182 _krb5_debug(context, 5, "out of hosts, waiting for replies");
1183 ctx->stateflags |= KRBHST_COMPLETED; 1183 ctx->stateflags |= KRBHST_COMPLETED;
1184 } 1184 }
1185 1185
1186 break; 1186 break;
1187 case KRB5_SENDTO_CONTINUE: 1187 case KRB5_SENDTO_CONTINUE:
1188 1188
1189 ret = wait_response(context, &action, ctx); 1189 ret = wait_response(context, &action, ctx);
1190 if (ret) 1190 if (ret)
1191 goto out; 1191 goto out;
1192 1192
1193 break; 1193 break;
1194 case KRB5_SENDTO_RESET: 1194 case KRB5_SENDTO_RESET:
1195 /* start over */ 1195 /* start over */
1196 _krb5_debug(context, 5, 1196 _krb5_debug(context, 5,
1197 "krb5_sendto trying over again (reset): %d", 1197 "krb5_sendto trying over again (reset): %d",
1198 numreset); 1198 numreset);
1199 reset_context(context, ctx); 1199 reset_context(context, ctx);
1200 if (handle) { 1200 if (handle) {
1201 krb5_krbhst_free(context, handle); 1201 krb5_krbhst_free(context, handle);
1202 handle = NULL; 1202 handle = NULL;
1203 } 1203 }
1204 numreset++; 1204 numreset++;
1205 if (numreset >= 3) 1205 if (numreset >= 3)
1206 action = KRB5_SENDTO_FAILED; 1206 action = KRB5_SENDTO_FAILED;
1207 else 1207 else
1208 action = KRB5_SENDTO_KRBHST; 1208 action = KRB5_SENDTO_KRBHST;
1209 1209
1210 break; 1210 break;
1211 case KRB5_SENDTO_FILTER: 1211 case KRB5_SENDTO_FILTER:
1212 /* default to next state, the filter function might modify this */ 1212 /* default to next state, the filter function might modify this */
1213 action = KRB5_SENDTO_DONE; 1213 action = KRB5_SENDTO_DONE;
1214 1214
1215 if (ctx->func) { 1215 if (ctx->func) {
1216 ret = (*ctx->func)(context, ctx, ctx->data, 1216 ret = (*ctx->func)(context, ctx, ctx->data,
1217 &ctx->response, &action); 1217 &ctx->response, &action);
1218 if (ret) 1218 if (ret)
1219 goto out; 1219 goto out;
1220 } 1220 }
1221 break; 1221 break;
1222 case KRB5_SENDTO_FAILED: 1222 case KRB5_SENDTO_FAILED:
1223 ret = KRB5_KDC_UNREACH; 1223 ret = KRB5_KDC_UNREACH;
1224 break; 1224 break;
1225 case KRB5_SENDTO_DONE: 1225 case KRB5_SENDTO_DONE:
1226 ret = 0; 1226 ret = 0;
1227 break; 1227 break;
1228 default: 1228 default:
1229 heim_abort("invalid krb5_sendto_context state"); 1229 heim_abort("invalid krb5_sendto_context state");
1230 } 1230 }
1231 } 1231 }
1232 1232
1233out: 1233out:
1234 gettimeofday(&stop_time, NULL); 1234 gettimeofday(&stop_time, NULL);
1235 timevalsub(&stop_time, &ctx->stats.start_time); 1235 timevalsub(&stop_time, &ctx->stats.start_time);
1236 if (ret == 0 && ctx->response.length) { 1236 if (ret == 0 && ctx->response.length) {
1237 *receive = ctx->response; 1237 *receive = ctx->response;
1238 krb5_data_zero(&ctx->response); 1238 krb5_data_zero(&ctx->response);
1239 } else { 1239 } else {
1240 krb5_data_free(&ctx->response); 1240 krb5_data_free(&ctx->response);
1241 krb5_clear_error_message (context); 1241 krb5_clear_error_message (context);
1242 ret = KRB5_KDC_UNREACH; 1242 ret = KRB5_KDC_UNREACH;
1243 krb5_set_error_message(context, ret, 1243 krb5_set_error_message(context, ret,
1244 N_("unable to reach any KDC in realm %s", ""), 1244 N_("unable to reach any KDC in realm %s", ""),
1245 realm); 1245 realm);
1246 } 1246 }
1247 1247
1248 _krb5_debug(context, 1, 1248 _krb5_debug(context, 1,
1249 "%s %s done: %d hosts %lu packets %lu:" 1249 "%s %s done: %d hosts %lu packets %lu:"
1250 " wc: %jd.%06ld nr: %jd.%06ld kh: %jd.%06ld tid: %08x", 1250 " wc: %jd.%06ld nr: %jd.%06ld kh: %jd.%06ld tid: %08x",
1251 realm, ret, __func__, 1251 __func__, realm, ret,
1252 ctx->stats.num_hosts, ctx->stats.sent_packets, 1252 ctx->stats.num_hosts, ctx->stats.sent_packets,
1253 (intmax_t)stop_time.tv_sec, 1253 (intmax_t)stop_time.tv_sec,
1254 (long)stop_time.tv_usec, 1254 (long)stop_time.tv_usec,
1255 (intmax_t)ctx->stats.name_resolution.tv_sec, 1255 (intmax_t)ctx->stats.name_resolution.tv_sec,
1256 (long)ctx->stats.name_resolution.tv_usec, 1256 (long)ctx->stats.name_resolution.tv_usec,
1257 (intmax_t)ctx->stats.krbhst.tv_sec, 1257 (intmax_t)ctx->stats.krbhst.tv_sec,
1258 (long)ctx->stats.krbhst.tv_usec, ctx->stid); 1258 (long)ctx->stats.krbhst.tv_usec, ctx->stid);
1259 1259
1260 1260
1261 if (freectx) 1261 if (freectx)
1262 krb5_sendto_ctx_free(context, ctx); 1262 krb5_sendto_ctx_free(context, ctx);
1263 else 1263 else
1264 reset_context(context, ctx); 1264 reset_context(context, ctx);
1265 1265
1266 if (handle) 1266 if (handle)
1267 krb5_krbhst_free(context, handle); 1267 krb5_krbhst_free(context, handle);
1268 1268
1269 return ret; 1269 return ret;
1270} 1270}