xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/deprecated.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: deprecated.c,v 1.3 2019/12/15 22:50:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2009 Kungliga Tekniska H�gskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifdef __GNUC__
37 /* For some GCCs there's no way to shut them up about deprecated functions */
38 #define KRB5_DEPRECATED_FUNCTION(x)
39 #endif
40 
41 #include "krb5_locl.h"
42 
43 
44 #undef __attribute__
45 #define __attribute__(x)
46 
47 #ifndef HEIMDAL_SMALLER
48 
49 /**
50  * Same as krb5_data_free(). MIT compat.
51  *
52  * Deprecated: use krb5_data_free().
53  *
54  * @param context Kerberos 5 context.
55  * @param data krb5_data to free.
56  *
57  * @ingroup krb5_deprecated
58  */
59 
60 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
61 krb5_free_data_contents(krb5_context context, krb5_data *data)
62     KRB5_DEPRECATED_FUNCTION("Use X instead")
63 {
64     krb5_data_free(data);
65 }
66 
67 /**
68  * Deprecated: keytypes doesn't exists, they are really enctypes.
69  *
70  * @ingroup krb5_deprecated
71  */
72 
73 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
74 krb5_keytype_to_enctypes_default (krb5_context context,
75 				  krb5_keytype keytype,
76 				  unsigned *len,
77 				  krb5_enctype **val)
78     KRB5_DEPRECATED_FUNCTION("Use X instead")
79 {
80     unsigned int i, n;
81     krb5_enctype *ret;
82 
83     if (keytype != (krb5_keytype)KEYTYPE_DES || context->etypes_des == NULL)
84 	return krb5_keytype_to_enctypes (context, keytype, len, val);
85 
86     for (n = 0; context->etypes_des[n]; ++n)
87 	;
88     ret = malloc (n * sizeof(*ret));
89     if (ret == NULL && n != 0)
90 	return krb5_enomem(context);
91     for (i = 0; i < n; ++i)
92 	ret[i] = context->etypes_des[i];
93     *len = n;
94     *val = ret;
95     return 0;
96 }
97 
98 
99 static struct {
100     const char *name;
101     krb5_keytype type;
102 } keys[] = {
103     { "null", KRB5_ENCTYPE_NULL },
104     { "des", KRB5_ENCTYPE_DES_CBC_CRC },
105     { "des3", KRB5_ENCTYPE_OLD_DES3_CBC_SHA1 },
106     { "aes-128", KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96 },
107     { "aes-256", KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 },
108     { "arcfour", KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 },
109     { "arcfour-56", KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56 }
110 };
111 
112 static int num_keys = sizeof(keys) / sizeof(keys[0]);
113 
114 /**
115  * Deprecated: keytypes doesn't exists, they are really enctypes in
116  * most cases, use krb5_enctype_to_string().
117  *
118  * @ingroup krb5_deprecated
119  */
120 
121 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
122 krb5_keytype_to_string(krb5_context context,
123 		       krb5_keytype keytype,
124 		       char **string)
125     KRB5_DEPRECATED_FUNCTION("Use X instead")
126 {
127     const char *name = NULL;
128     int i;
129 
130     for(i = 0; i < num_keys; i++) {
131 	if(keys[i].type == keytype) {
132 	    name = keys[i].name;
133 	    break;
134 	}
135     }
136 
137     if(i >= num_keys) {
138 	krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
139 			       "key type %d not supported", keytype);
140 	return KRB5_PROG_KEYTYPE_NOSUPP;
141     }
142     *string = strdup(name);
143     if (*string == NULL)
144 	return krb5_enomem(context);
145     return 0;
146 }
147 
148 /**
149  * Deprecated: keytypes doesn't exists, they are really enctypes in
150  * most cases, use krb5_string_to_enctype().
151  *
152  * @ingroup krb5_deprecated
153  */
154 
155 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
156 krb5_string_to_keytype(krb5_context context,
157 		       const char *string,
158 		       krb5_keytype *keytype)
159     KRB5_DEPRECATED_FUNCTION("Use X instead")
160 {
161     char *end;
162     int i;
163 
164     for(i = 0; i < num_keys; i++)
165 	if(strcasecmp(keys[i].name, string) == 0){
166 	    *keytype = keys[i].type;
167 	    return 0;
168 	}
169 
170     /* check if the enctype is a number */
171     *keytype = strtol(string, &end, 0);
172     if(*end == '\0' && *keytype != 0) {
173 	if (krb5_enctype_valid(context, *keytype) == 0)
174 	    return 0;
175     }
176 
177     krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP,
178 			   "key type %s not supported", string);
179     return KRB5_PROG_KEYTYPE_NOSUPP;
180 }
181 
182 /**
183  * Deprecated: use krb5_get_init_creds() and friends.
184  *
185  * @ingroup krb5_deprecated
186  */
187 
188 KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV
189 krb5_password_key_proc (krb5_context context,
190 			krb5_enctype type,
191 			krb5_salt salt,
192 			krb5_const_pointer keyseed,
193 			krb5_keyblock **key)
194     KRB5_DEPRECATED_FUNCTION("Use X instead")
195 {
196     krb5_error_code ret;
197     const char *password = (const char *)keyseed;
198     char buf[BUFSIZ];
199 
200     *key = malloc (sizeof (**key));
201     if (*key == NULL)
202 	return krb5_enomem(context);
203     if (password == NULL) {
204 	if(UI_UTIL_read_pw_string (buf, sizeof(buf), "Password: ", 0)) {
205 	    free (*key);
206 	    krb5_clear_error_message(context);
207 	    return KRB5_LIBOS_PWDINTR;
208 	}
209 	password = buf;
210     }
211     ret = krb5_string_to_key_salt (context, type, password, salt, *key);
212     memset_s(buf, sizeof(buf), 0, sizeof(buf));
213     return ret;
214 }
215 
216 /**
217  * Deprecated: use krb5_get_init_creds() and friends.
218  *
219  * @ingroup krb5_deprecated
220  */
221 
222 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
223 krb5_get_in_tkt_with_password (krb5_context context,
224 			       krb5_flags options,
225 			       krb5_addresses *addrs,
226 			       const krb5_enctype *etypes,
227 			       const krb5_preauthtype *pre_auth_types,
228 			       const char *password,
229 			       krb5_ccache ccache,
230 			       krb5_creds *creds,
231 			       krb5_kdc_rep *ret_as_reply)
232     KRB5_DEPRECATED_FUNCTION("Use X instead")
233 {
234      return krb5_get_in_tkt (context,
235 			     options,
236 			     addrs,
237 			     etypes,
238 			     pre_auth_types,
239 			     krb5_password_key_proc,
240 			     password,
241 			     NULL,
242 			     NULL,
243 			     creds,
244 			     ccache,
245 			     ret_as_reply);
246 }
247 
248 static krb5_error_code KRB5_CALLCONV
249 krb5_skey_key_proc (krb5_context context,
250 		    krb5_enctype type,
251 		    krb5_salt salt,
252 		    krb5_const_pointer keyseed,
253 		    krb5_keyblock **key)
254 {
255     return krb5_copy_keyblock (context, keyseed, key);
256 }
257 
258 /**
259  * Deprecated: use krb5_get_init_creds() and friends.
260  *
261  * @ingroup krb5_deprecated
262  */
263 
264 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
265 krb5_get_in_tkt_with_skey (krb5_context context,
266 			   krb5_flags options,
267 			   krb5_addresses *addrs,
268 			   const krb5_enctype *etypes,
269 			   const krb5_preauthtype *pre_auth_types,
270 			   const krb5_keyblock *key,
271 			   krb5_ccache ccache,
272 			   krb5_creds *creds,
273 			   krb5_kdc_rep *ret_as_reply)
274     KRB5_DEPRECATED_FUNCTION("Use X instead")
275 {
276     if(key == NULL)
277 	return krb5_get_in_tkt_with_keytab (context,
278 					    options,
279 					    addrs,
280 					    etypes,
281 					    pre_auth_types,
282 					    NULL,
283 					    ccache,
284 					    creds,
285 					    ret_as_reply);
286     else
287 	return krb5_get_in_tkt (context,
288 				options,
289 				addrs,
290 				etypes,
291 				pre_auth_types,
292 				krb5_skey_key_proc,
293 				key,
294 				NULL,
295 				NULL,
296 				creds,
297 				ccache,
298 				ret_as_reply);
299 }
300 
301 /**
302  * Deprecated: use krb5_get_init_creds() and friends.
303  *
304  * @ingroup krb5_deprecated
305  */
306 
307 KRB5_LIB_FUNCTION krb5_error_code KRB5_CALLCONV
308 krb5_keytab_key_proc (krb5_context context,
309 		      krb5_enctype enctype,
310 		      krb5_salt salt,
311 		      krb5_const_pointer keyseed,
312 		      krb5_keyblock **key)
313     KRB5_DEPRECATED_FUNCTION("Use X instead")
314 {
315     krb5_keytab_key_proc_args *args  = rk_UNCONST(keyseed);
316     krb5_keytab keytab = args->keytab;
317     krb5_principal principal  = args->principal;
318     krb5_error_code ret;
319     krb5_keytab real_keytab;
320     krb5_keytab_entry entry;
321 
322     if(keytab == NULL)
323 	krb5_kt_default(context, &real_keytab);
324     else
325 	real_keytab = keytab;
326 
327     ret = krb5_kt_get_entry (context, real_keytab, principal,
328 			     0, enctype, &entry);
329 
330     if (keytab == NULL)
331 	krb5_kt_close (context, real_keytab);
332 
333     if (ret)
334 	return ret;
335 
336     ret = krb5_copy_keyblock (context, &entry.keyblock, key);
337     krb5_kt_free_entry(context, &entry);
338     return ret;
339 }
340 
341 /**
342  * Deprecated: use krb5_get_init_creds() and friends.
343  *
344  * @ingroup krb5_deprecated
345  */
346 
347 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
348 krb5_get_in_tkt_with_keytab (krb5_context context,
349 			     krb5_flags options,
350 			     krb5_addresses *addrs,
351 			     const krb5_enctype *etypes,
352 			     const krb5_preauthtype *pre_auth_types,
353 			     krb5_keytab keytab,
354 			     krb5_ccache ccache,
355 			     krb5_creds *creds,
356 			     krb5_kdc_rep *ret_as_reply)
357     KRB5_DEPRECATED_FUNCTION("Use X instead")
358 {
359     krb5_keytab_key_proc_args a;
360 
361     a.principal = creds->client;
362     a.keytab    = keytab;
363 
364     return krb5_get_in_tkt (context,
365 			    options,
366 			    addrs,
367 			    etypes,
368 			    pre_auth_types,
369 			    krb5_keytab_key_proc,
370 			    &a,
371 			    NULL,
372 			    NULL,
373 			    creds,
374 			    ccache,
375 			    ret_as_reply);
376 }
377 
378 /**
379  * Generate a new ccache of type `ops' in `id'.
380  *
381  * Deprecated: use krb5_cc_new_unique() instead.
382  *
383  * @return Return an error code or 0, see krb5_get_error_message().
384  *
385  * @ingroup krb5_ccache
386  */
387 
388 
389 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
390 krb5_cc_gen_new(krb5_context context,
391 		const krb5_cc_ops *ops,
392 		krb5_ccache *id)
393     KRB5_DEPRECATED_FUNCTION("Use X instead")
394 {
395     return krb5_cc_new_unique(context, ops->prefix, NULL, id);
396 }
397 
398 /**
399  * Deprecated: use krb5_principal_get_realm()
400  *
401  * @ingroup krb5_deprecated
402  */
403 
404 KRB5_LIB_FUNCTION krb5_realm * KRB5_LIB_CALL
405 krb5_princ_realm(krb5_context context,
406 		 krb5_principal principal)
407     KRB5_DEPRECATED_FUNCTION("Use X instead")
408 {
409     return &principal->realm;
410 }
411 
412 
413 /**
414  * Deprecated: use krb5_principal_set_realm()
415  *
416  * @ingroup krb5_deprecated
417  */
418 
419 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
420 krb5_princ_set_realm(krb5_context context,
421 		     krb5_principal principal,
422 		     krb5_realm *realm)
423     KRB5_DEPRECATED_FUNCTION("Use X instead")
424 {
425     principal->realm = *realm;
426 }
427 
428 /**
429  * Deprecated: use krb5_free_cred_contents()
430  *
431  * @ingroup krb5_deprecated
432  */
433 
434 /* keep this for compatibility with older code */
435 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
436 krb5_free_creds_contents (krb5_context context, krb5_creds *c)
437     KRB5_DEPRECATED_FUNCTION("Use X instead")
438 {
439     return krb5_free_cred_contents (context, c);
440 }
441 
442 /**
443  * Free the error message returned by krb5_get_error_string().
444  *
445  * Deprecated: use krb5_free_error_message()
446  *
447  * @param context Kerberos context
448  * @param str error message to free
449  *
450  * @ingroup krb5_deprecated
451  */
452 
453 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
454 krb5_free_error_string(krb5_context context, char *str)
455     KRB5_DEPRECATED_FUNCTION("Use X instead")
456 {
457     krb5_free_error_message(context, str);
458 }
459 
460 /**
461  * Set the error message returned by krb5_get_error_string().
462  *
463  * Deprecated: use krb5_get_error_message()
464  *
465  * @param context Kerberos context
466  * @param fmt error message to free
467  *
468  * @return Return an error code or 0.
469  *
470  * @ingroup krb5_deprecated
471  */
472 
473 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
474 krb5_set_error_string(krb5_context context, const char *fmt, ...)
475     __attribute__ ((__format__ (__printf__, 2, 3)))
476     KRB5_DEPRECATED_FUNCTION("Use X instead")
477 {
478     va_list ap;
479 
480     va_start(ap, fmt);
481     krb5_vset_error_message (context, 0, fmt, ap);
482     va_end(ap);
483     return 0;
484 }
485 
486 /**
487  * Set the error message returned by krb5_get_error_string(),
488  * deprecated, use krb5_set_error_message().
489  *
490  * Deprecated: use krb5_vset_error_message()
491  *
492  * @param context Kerberos context
493  * @param fmt error message to free
494  * @param args variable argument list vector
495  *
496  * @return Return an error code or 0.
497  *
498  * @ingroup krb5_deprecated
499  */
500 
501 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
502 krb5_vset_error_string(krb5_context context, const char *fmt, va_list args)
503     __attribute__ ((__format__ (__printf__, 2, 0)))
504     KRB5_DEPRECATED_FUNCTION("Use X instead")
505 {
506     krb5_vset_error_message(context, 0, fmt, args);
507     return 0;
508 }
509 
510 /**
511  * Clear the error message returned by krb5_get_error_string().
512  *
513  * Deprecated: use krb5_clear_error_message()
514  *
515  * @param context Kerberos context
516  *
517  * @ingroup krb5_deprecated
518  */
519 
520 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
521 krb5_clear_error_string(krb5_context context)
522     KRB5_DEPRECATED_FUNCTION("Use X instead")
523 {
524     krb5_clear_error_message(context);
525 }
526 
527 /**
528  * Deprecated: use krb5_get_credentials_with_flags().
529  *
530  * @ingroup krb5_deprecated
531  */
532 
533 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
534 krb5_get_cred_from_kdc_opt(krb5_context context,
535 			   krb5_ccache ccache,
536 			   krb5_creds *in_creds,
537 			   krb5_creds **out_creds,
538 			   krb5_creds ***ret_tgts,
539 			   krb5_flags flags)
540     KRB5_DEPRECATED_FUNCTION("Use X instead")
541 {
542     krb5_kdc_flags f;
543     f.i = flags;
544     return _krb5_get_cred_kdc_any(context, f, ccache,
545 				  in_creds, NULL, NULL,
546 				  out_creds, ret_tgts);
547 }
548 
549 /**
550  * Deprecated: use krb5_get_credentials_with_flags().
551  *
552  * @ingroup krb5_deprecated
553  */
554 
555 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
556 krb5_get_cred_from_kdc(krb5_context context,
557 		       krb5_ccache ccache,
558 		       krb5_creds *in_creds,
559 		       krb5_creds **out_creds,
560 		       krb5_creds ***ret_tgts)
561     KRB5_DEPRECATED_FUNCTION("Use X instead")
562 {
563     return krb5_get_cred_from_kdc_opt(context, ccache,
564 				      in_creds, out_creds, ret_tgts, 0);
565 }
566 
567 /**
568  * Deprecated: use krb5_xfree().
569  *
570  * @ingroup krb5_deprecated
571  */
572 
573 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
574 krb5_free_unparsed_name(krb5_context context, char *str)
575     KRB5_DEPRECATED_FUNCTION("Use X instead")
576 {
577     krb5_xfree(str);
578 }
579 
580 /**
581  * Deprecated: use krb5_generate_subkey_extended()
582  *
583  * @ingroup krb5_deprecated
584  */
585 
586 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
587 krb5_generate_subkey(krb5_context context,
588 		     const krb5_keyblock *key,
589 		     krb5_keyblock **subkey)
590     KRB5_DEPRECATED_FUNCTION("Use X instead")
591 {
592     return krb5_generate_subkey_extended(context, key, ETYPE_NULL, subkey);
593 }
594 
595 /**
596  * Deprecated: use krb5_auth_con_getremoteseqnumber()
597  *
598  * @ingroup krb5_deprecated
599  */
600 
601 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
602 krb5_auth_getremoteseqnumber(krb5_context context,
603 			     krb5_auth_context auth_context,
604 			     int32_t *seqnumber)
605     KRB5_DEPRECATED_FUNCTION("Use X instead")
606 {
607   *seqnumber = auth_context->remote_seqnumber;
608   return 0;
609 }
610 
611 /**
612  * Return the error message in context. On error or no error string,
613  * the function returns NULL.
614  *
615  * @param context Kerberos 5 context
616  *
617  * @return an error string, needs to be freed with
618  * krb5_free_error_message(). The functions return NULL on error.
619  *
620  * @ingroup krb5_error
621  */
622 
623 KRB5_LIB_FUNCTION char * KRB5_LIB_CALL
624 krb5_get_error_string(krb5_context context)
625     KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead")
626 {
627     char *ret = NULL;
628 
629     HEIMDAL_MUTEX_lock(&context->mutex);
630     if (context->error_string)
631 	ret = strdup(context->error_string);
632     HEIMDAL_MUTEX_unlock(&context->mutex);
633     return ret;
634 }
635 
636 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
637 krb5_have_error_string(krb5_context context)
638     KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead")
639 {
640     char *str;
641     HEIMDAL_MUTEX_lock(&context->mutex);
642     str = context->error_string;
643     HEIMDAL_MUTEX_unlock(&context->mutex);
644     return str != NULL;
645 }
646 
647 struct send_to_kdc {
648     krb5_send_to_kdc_func func;
649     void *data;
650 };
651 
652 /*
653  * Send the data `send' to one host from `handle` and get back the reply
654  * in `receive'.
655  */
656 
657 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
658 krb5_sendto (krb5_context context,
659 	     const krb5_data *send_data,
660 	     krb5_krbhst_handle handle,
661 	     krb5_data *receive)
662 {
663     krb5_error_code ret;
664     krb5_sendto_ctx ctx;
665 
666     ret = krb5_sendto_ctx_alloc(context, &ctx);
667     if (ret)
668 	return ret;
669     _krb5_sendto_ctx_set_krb5hst(context, ctx, handle);
670 
671     ret = krb5_sendto_context(context, ctx, send_data, (char *)_krb5_krbhst_get_realm(handle), receive);
672     krb5_sendto_ctx_free(context, ctx);
673     return ret;
674 }
675 
676 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
677 krb5_sendto_kdc(krb5_context context,
678 		const krb5_data *send_data,
679 		const krb5_realm *realm,
680 		krb5_data *receive)
681 {
682     return krb5_sendto_kdc_flags(context, send_data, realm, receive, 0);
683 }
684 
685 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
686 krb5_sendto_kdc_flags(krb5_context context,
687 		      const krb5_data *send_data,
688 		      const krb5_realm *realm,
689 		      krb5_data *receive,
690 		      int flags)
691 {
692     krb5_error_code ret;
693     krb5_sendto_ctx ctx;
694 
695     ret = krb5_sendto_ctx_alloc(context, &ctx);
696     if (ret)
697 	return ret;
698     krb5_sendto_ctx_add_flags(ctx, flags);
699     krb5_sendto_ctx_set_func(ctx, _krb5_kdc_retry, NULL);
700 
701     ret = krb5_sendto_context(context, ctx, send_data, *realm, receive);
702     krb5_sendto_ctx_free(context, ctx);
703     return ret;
704 }
705 
706 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
707 krb5_set_send_to_kdc_func(krb5_context context,
708 			  krb5_send_to_kdc_func func,
709 			  void *data)
710 {
711     free(context->send_to_kdc);
712     if (func == NULL) {
713 	context->send_to_kdc = NULL;
714 	return 0;
715     }
716 
717     context->send_to_kdc = malloc(sizeof(*context->send_to_kdc));
718     if (context->send_to_kdc == NULL) {
719 	krb5_set_error_message(context, ENOMEM,
720 			       N_("malloc: out of memory", ""));
721 	return ENOMEM;
722     }
723 
724     context->send_to_kdc->func = func;
725     context->send_to_kdc->data = data;
726     return 0;
727 }
728 
729 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
730 _krb5_copy_send_to_kdc_func(krb5_context context, krb5_context to)
731 {
732     if (context->send_to_kdc)
733 	return krb5_set_send_to_kdc_func(to,
734 					 context->send_to_kdc->func,
735 					 context->send_to_kdc->data);
736     else
737 	return krb5_set_send_to_kdc_func(to, NULL, NULL);
738 }
739 
740 #endif /* HEIMDAL_SMALLER */
741