kssl.c revision 194206
1/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
2/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
3 */
4/* ====================================================================
5 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 *    software must display the following acknowledgment:
21 *    "This product includes software developed by the OpenSSL Project
22 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 *    endorse or promote products derived from this software without
26 *    prior written permission. For written permission, please contact
27 *    licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 *    nor may "OpenSSL" appear in their names without prior written
31 *    permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 *    acknowledgment:
35 *    "This product includes software developed by the OpenSSL Project
36 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This product includes cryptographic software written by Eric Young
53 * (eay@cryptsoft.com).  This product includes software written by Tim
54 * Hudson (tjh@cryptsoft.com).
55 *
56 */
57
58
59/*  ssl/kssl.c  --  Routines to support (& debug) Kerberos5 auth for openssl
60**
61**  19990701	VRS 	Started.
62**  200011??	Jeffrey Altman, Richard Levitte
63**          		Generalized for Heimdal, Newer MIT, & Win32.
64**          		Integrated into main OpenSSL 0.9.7 snapshots.
65**  20010413	Simon Wilkinson, VRS
66**          		Real RFC2712 KerberosWrapper replaces AP_REQ.
67*/
68
69#include <openssl/opensslconf.h>
70
71#define _XOPEN_SOURCE 500 /* glibc2 needs this to declare strptime() */
72#include <time.h>
73#if 0 /* experimental */
74#undef _XOPEN_SOURCE /* To avoid clashes with anything else... */
75#endif
76#include <string.h>
77
78#define KRB5_PRIVATE	1
79
80#include <openssl/ssl.h>
81#include <openssl/evp.h>
82#include <openssl/objects.h>
83#include <openssl/krb5_asn.h>
84
85#ifndef OPENSSL_NO_KRB5
86
87#ifndef ENOMEM
88#define ENOMEM KRB5KRB_ERR_GENERIC
89#endif
90
91/*
92 * When OpenSSL is built on Windows, we do not want to require that
93 * the Kerberos DLLs be available in order for the OpenSSL DLLs to
94 * work.  Therefore, all Kerberos routines are loaded at run time
95 * and we do not link to a .LIB file.
96 */
97
98#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
99/*
100 * The purpose of the following pre-processor statements is to provide
101 * compatibility with different releases of MIT Kerberos for Windows.
102 * All versions up to 1.2 used macros.  But macros do not allow for
103 * a binary compatible interface for DLLs.  Therefore, all macros are
104 * being replaced by function calls.  The following code will allow
105 * an OpenSSL DLL built on Windows to work whether or not the macro
106 * or function form of the routines are utilized.
107 */
108#ifdef  krb5_cc_get_principal
109#define NO_DEF_KRB5_CCACHE
110#undef  krb5_cc_get_principal
111#endif
112#define krb5_cc_get_principal    kssl_krb5_cc_get_principal
113
114#define krb5_free_data_contents  kssl_krb5_free_data_contents
115#define krb5_free_context        kssl_krb5_free_context
116#define krb5_auth_con_free       kssl_krb5_auth_con_free
117#define krb5_free_principal      kssl_krb5_free_principal
118#define krb5_mk_req_extended     kssl_krb5_mk_req_extended
119#define krb5_get_credentials     kssl_krb5_get_credentials
120#define krb5_cc_default          kssl_krb5_cc_default
121#define krb5_sname_to_principal  kssl_krb5_sname_to_principal
122#define krb5_init_context        kssl_krb5_init_context
123#define krb5_free_ticket         kssl_krb5_free_ticket
124#define krb5_rd_req              kssl_krb5_rd_req
125#define krb5_kt_default          kssl_krb5_kt_default
126#define krb5_kt_resolve          kssl_krb5_kt_resolve
127/* macros in mit 1.2.2 and earlier; functions in mit 1.2.3 and greater */
128#ifndef krb5_kt_close
129#define krb5_kt_close            kssl_krb5_kt_close
130#endif /* krb5_kt_close */
131#ifndef krb5_kt_get_entry
132#define krb5_kt_get_entry        kssl_krb5_kt_get_entry
133#endif /* krb5_kt_get_entry */
134#define krb5_auth_con_init       kssl_krb5_auth_con_init
135
136#define krb5_principal_compare   kssl_krb5_principal_compare
137#define krb5_decrypt_tkt_part    kssl_krb5_decrypt_tkt_part
138#define krb5_timeofday           kssl_krb5_timeofday
139#define krb5_rc_default           kssl_krb5_rc_default
140
141#ifdef krb5_rc_initialize
142#undef krb5_rc_initialize
143#endif
144#define krb5_rc_initialize   kssl_krb5_rc_initialize
145
146#ifdef krb5_rc_get_lifespan
147#undef krb5_rc_get_lifespan
148#endif
149#define krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
150
151#ifdef krb5_rc_destroy
152#undef krb5_rc_destroy
153#endif
154#define krb5_rc_destroy      kssl_krb5_rc_destroy
155
156#define valid_cksumtype      kssl_valid_cksumtype
157#define krb5_checksum_size   kssl_krb5_checksum_size
158#define krb5_kt_free_entry   kssl_krb5_kt_free_entry
159#define krb5_auth_con_setrcache  kssl_krb5_auth_con_setrcache
160#define krb5_auth_con_getrcache  kssl_krb5_auth_con_getrcache
161#define krb5_get_server_rcache   kssl_krb5_get_server_rcache
162
163/* Prototypes for built in stubs */
164void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
165void kssl_krb5_free_principal(krb5_context, krb5_principal );
166krb5_error_code kssl_krb5_kt_resolve(krb5_context,
167                                     krb5_const char *,
168                                     krb5_keytab *);
169krb5_error_code kssl_krb5_kt_default(krb5_context,
170                                     krb5_keytab *);
171krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
172krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
173                                 krb5_const krb5_data *,
174                                 krb5_const_principal, krb5_keytab,
175                                 krb5_flags *,krb5_ticket **);
176
177krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
178                                         krb5_const_principal);
179krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
180                                          krb5_auth_context  *,
181                                          krb5_const krb5_flags,
182                                          krb5_data  *,
183                                          krb5_creds  *,
184                                          krb5_data  * );
185krb5_error_code kssl_krb5_init_context(krb5_context *);
186void kssl_krb5_free_context(krb5_context);
187krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache  *);
188krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
189                                             krb5_const char  *,
190                                             krb5_const char  *,
191                                             krb5_int32,
192                                             krb5_principal  *);
193krb5_error_code kssl_krb5_get_credentials(krb5_context,
194                                          krb5_const krb5_flags,
195                                          krb5_ccache,
196                                          krb5_creds  *,
197                                          krb5_creds  *  *);
198krb5_error_code kssl_krb5_auth_con_init(krb5_context,
199                                        krb5_auth_context  *);
200krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
201                                           krb5_ccache cache,
202                                           krb5_principal *principal);
203krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
204size_t kssl_krb5_checksum_size(krb5_context context,krb5_cksumtype ctype);
205krb5_boolean kssl_valid_cksumtype(krb5_cksumtype ctype);
206krb5_error_code krb5_kt_free_entry(krb5_context,krb5_keytab_entry FAR * );
207krb5_error_code kssl_krb5_auth_con_setrcache(krb5_context,
208                                             krb5_auth_context,
209                                             krb5_rcache);
210krb5_error_code kssl_krb5_get_server_rcache(krb5_context,
211                                            krb5_const krb5_data *,
212                                            krb5_rcache *);
213krb5_error_code kssl_krb5_auth_con_getrcache(krb5_context,
214                                             krb5_auth_context,
215                                             krb5_rcache *);
216
217/* Function pointers (almost all Kerberos functions are _stdcall) */
218static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)
219	=NULL;
220static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )
221	=NULL;
222static krb5_error_code(_stdcall *p_krb5_kt_resolve)
223			(krb5_context, krb5_const char *, krb5_keytab *)=NULL;
224static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
225                                                     krb5_keytab *)=NULL;
226static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
227                                                      krb5_ticket *)=NULL;
228static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
229                                                 krb5_auth_context *,
230                                                 krb5_const krb5_data *,
231                                                 krb5_const_principal,
232                                                 krb5_keytab, krb5_flags *,
233                                                 krb5_ticket **)=NULL;
234static krb5_error_code (_stdcall *p_krb5_mk_req_extended)
235			(krb5_context, krb5_auth_context *,
236			 krb5_const krb5_flags, krb5_data *, krb5_creds *,
237			 krb5_data * )=NULL;
238static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
239static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
240static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
241                                                     krb5_ccache  *)=NULL;
242static krb5_error_code (_stdcall *p_krb5_sname_to_principal)
243			(krb5_context, krb5_const char *, krb5_const char *,
244			 krb5_int32, krb5_principal *)=NULL;
245static krb5_error_code (_stdcall *p_krb5_get_credentials)
246			(krb5_context, krb5_const krb5_flags, krb5_ccache,
247			 krb5_creds *, krb5_creds **)=NULL;
248static krb5_error_code (_stdcall *p_krb5_auth_con_init)
249			(krb5_context, krb5_auth_context *)=NULL;
250static krb5_error_code (_stdcall *p_krb5_cc_get_principal)
251			(krb5_context context, krb5_ccache cache,
252			 krb5_principal *principal)=NULL;
253static krb5_error_code (_stdcall *p_krb5_auth_con_free)
254			(krb5_context, krb5_auth_context)=NULL;
255static krb5_error_code (_stdcall *p_krb5_decrypt_tkt_part)
256                        (krb5_context, krb5_const krb5_keyblock *,
257                                           krb5_ticket *)=NULL;
258static krb5_error_code (_stdcall *p_krb5_timeofday)
259                        (krb5_context context, krb5_int32 *timeret)=NULL;
260static krb5_error_code (_stdcall *p_krb5_rc_default)
261                        (krb5_context context, krb5_rcache *rc)=NULL;
262static krb5_error_code (_stdcall *p_krb5_rc_initialize)
263                        (krb5_context context, krb5_rcache rc,
264                                     krb5_deltat lifespan)=NULL;
265static krb5_error_code (_stdcall *p_krb5_rc_get_lifespan)
266                        (krb5_context context, krb5_rcache rc,
267                                       krb5_deltat *lifespan)=NULL;
268static krb5_error_code (_stdcall *p_krb5_rc_destroy)
269                        (krb5_context context, krb5_rcache rc)=NULL;
270static krb5_boolean (_stdcall *p_krb5_principal_compare)
271                     (krb5_context, krb5_const_principal, krb5_const_principal)=NULL;
272static size_t (_stdcall *p_krb5_checksum_size)(krb5_context context,krb5_cksumtype ctype)=NULL;
273static krb5_boolean (_stdcall *p_valid_cksumtype)(krb5_cksumtype ctype)=NULL;
274static krb5_error_code (_stdcall *p_krb5_kt_free_entry)
275                        (krb5_context,krb5_keytab_entry * )=NULL;
276static krb5_error_code (_stdcall * p_krb5_auth_con_setrcache)(krb5_context,
277                                                               krb5_auth_context,
278                                                               krb5_rcache)=NULL;
279static krb5_error_code (_stdcall * p_krb5_get_server_rcache)(krb5_context,
280                                                              krb5_const krb5_data *,
281                                                              krb5_rcache *)=NULL;
282static krb5_error_code (* p_krb5_auth_con_getrcache)(krb5_context,
283                                                      krb5_auth_context,
284                                                      krb5_rcache *)=NULL;
285static krb5_error_code (_stdcall * p_krb5_kt_close)(krb5_context context,
286                                                    krb5_keytab keytab)=NULL;
287static krb5_error_code (_stdcall * p_krb5_kt_get_entry)(krb5_context context,
288                                                        krb5_keytab keytab,
289                       krb5_const_principal principal, krb5_kvno vno,
290                       krb5_enctype enctype, krb5_keytab_entry *entry)=NULL;
291static int krb5_loaded = 0;     /* only attempt to initialize func ptrs once */
292
293/* Function to Load the Kerberos 5 DLL and initialize function pointers */
294void
295load_krb5_dll(void)
296	{
297	HANDLE hKRB5_32;
298
299	krb5_loaded++;
300	hKRB5_32 = LoadLibrary(TEXT("KRB5_32"));
301	if (!hKRB5_32)
302		return;
303
304	(FARPROC) p_krb5_free_data_contents =
305		GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
306	(FARPROC) p_krb5_free_context =
307		GetProcAddress( hKRB5_32, "krb5_free_context" );
308	(FARPROC) p_krb5_auth_con_free =
309		GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
310	(FARPROC) p_krb5_free_principal =
311		GetProcAddress( hKRB5_32, "krb5_free_principal" );
312	(FARPROC) p_krb5_mk_req_extended =
313		GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
314	(FARPROC) p_krb5_get_credentials =
315		GetProcAddress( hKRB5_32, "krb5_get_credentials" );
316	(FARPROC) p_krb5_cc_get_principal =
317		GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
318	(FARPROC) p_krb5_cc_default =
319		GetProcAddress( hKRB5_32, "krb5_cc_default" );
320	(FARPROC) p_krb5_sname_to_principal =
321		GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
322	(FARPROC) p_krb5_init_context =
323		GetProcAddress( hKRB5_32, "krb5_init_context" );
324	(FARPROC) p_krb5_free_ticket =
325		GetProcAddress( hKRB5_32, "krb5_free_ticket" );
326	(FARPROC) p_krb5_rd_req =
327		GetProcAddress( hKRB5_32, "krb5_rd_req" );
328	(FARPROC) p_krb5_principal_compare =
329		GetProcAddress( hKRB5_32, "krb5_principal_compare" );
330	(FARPROC) p_krb5_decrypt_tkt_part =
331		GetProcAddress( hKRB5_32, "krb5_decrypt_tkt_part" );
332	(FARPROC) p_krb5_timeofday =
333		GetProcAddress( hKRB5_32, "krb5_timeofday" );
334	(FARPROC) p_krb5_rc_default =
335		GetProcAddress( hKRB5_32, "krb5_rc_default" );
336	(FARPROC) p_krb5_rc_initialize =
337		GetProcAddress( hKRB5_32, "krb5_rc_initialize" );
338	(FARPROC) p_krb5_rc_get_lifespan =
339		GetProcAddress( hKRB5_32, "krb5_rc_get_lifespan" );
340	(FARPROC) p_krb5_rc_destroy =
341		GetProcAddress( hKRB5_32, "krb5_rc_destroy" );
342	(FARPROC) p_krb5_kt_default =
343		GetProcAddress( hKRB5_32, "krb5_kt_default" );
344	(FARPROC) p_krb5_kt_resolve =
345		GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
346	(FARPROC) p_krb5_auth_con_init =
347		GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
348        (FARPROC) p_valid_cksumtype =
349                GetProcAddress( hKRB5_32, "valid_cksumtype" );
350        (FARPROC) p_krb5_checksum_size =
351                GetProcAddress( hKRB5_32, "krb5_checksum_size" );
352        (FARPROC) p_krb5_kt_free_entry =
353                GetProcAddress( hKRB5_32, "krb5_kt_free_entry" );
354        (FARPROC) p_krb5_auth_con_setrcache =
355                GetProcAddress( hKRB5_32, "krb5_auth_con_setrcache" );
356        (FARPROC) p_krb5_get_server_rcache =
357                GetProcAddress( hKRB5_32, "krb5_get_server_rcache" );
358        (FARPROC) p_krb5_auth_con_getrcache =
359                GetProcAddress( hKRB5_32, "krb5_auth_con_getrcache" );
360        (FARPROC) p_krb5_kt_close =
361                GetProcAddress( hKRB5_32, "krb5_kt_close" );
362        (FARPROC) p_krb5_kt_get_entry =
363                GetProcAddress( hKRB5_32, "krb5_kt_get_entry" );
364	}
365
366/* Stubs for each function to be dynamicly loaded */
367void
368kssl_krb5_free_data_contents(krb5_context CO, krb5_data  * data)
369	{
370	if (!krb5_loaded)
371		load_krb5_dll();
372
373	if ( p_krb5_free_data_contents )
374		p_krb5_free_data_contents(CO,data);
375	}
376
377krb5_error_code
378kssl_krb5_mk_req_extended (krb5_context CO,
379                          krb5_auth_context  * pACO,
380                          krb5_const krb5_flags F,
381                          krb5_data  * pD1,
382                          krb5_creds  * pC,
383                          krb5_data  * pD2)
384	{
385	if (!krb5_loaded)
386		load_krb5_dll();
387
388	if ( p_krb5_mk_req_extended )
389		return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
390	else
391		return KRB5KRB_ERR_GENERIC;
392	}
393krb5_error_code
394kssl_krb5_auth_con_init(krb5_context CO,
395                       krb5_auth_context  * pACO)
396	{
397	if (!krb5_loaded)
398		load_krb5_dll();
399
400	if ( p_krb5_auth_con_init )
401		return(p_krb5_auth_con_init(CO,pACO));
402	else
403		return KRB5KRB_ERR_GENERIC;
404	}
405krb5_error_code
406kssl_krb5_auth_con_free (krb5_context CO,
407                        krb5_auth_context ACO)
408	{
409	if (!krb5_loaded)
410		load_krb5_dll();
411
412	if ( p_krb5_auth_con_free )
413		return(p_krb5_auth_con_free(CO,ACO));
414	else
415		return KRB5KRB_ERR_GENERIC;
416	}
417krb5_error_code
418kssl_krb5_get_credentials(krb5_context CO,
419                         krb5_const krb5_flags F,
420                         krb5_ccache CC,
421                         krb5_creds  * pCR,
422                         krb5_creds  ** ppCR)
423	{
424	if (!krb5_loaded)
425		load_krb5_dll();
426
427	if ( p_krb5_get_credentials )
428		return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
429	else
430		return KRB5KRB_ERR_GENERIC;
431	}
432krb5_error_code
433kssl_krb5_sname_to_principal(krb5_context CO,
434                            krb5_const char  * pC1,
435                            krb5_const char  * pC2,
436                            krb5_int32 I,
437                            krb5_principal  * pPR)
438	{
439	if (!krb5_loaded)
440		load_krb5_dll();
441
442	if ( p_krb5_sname_to_principal )
443		return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
444	else
445		return KRB5KRB_ERR_GENERIC;
446	}
447
448krb5_error_code
449kssl_krb5_cc_default(krb5_context CO,
450                    krb5_ccache  * pCC)
451	{
452	if (!krb5_loaded)
453		load_krb5_dll();
454
455	if ( p_krb5_cc_default )
456		return(p_krb5_cc_default(CO,pCC));
457	else
458		return KRB5KRB_ERR_GENERIC;
459	}
460
461krb5_error_code
462kssl_krb5_init_context(krb5_context * pCO)
463	{
464	if (!krb5_loaded)
465		load_krb5_dll();
466
467	if ( p_krb5_init_context )
468		return(p_krb5_init_context(pCO));
469	else
470		return KRB5KRB_ERR_GENERIC;
471	}
472
473void
474kssl_krb5_free_context(krb5_context CO)
475	{
476	if (!krb5_loaded)
477		load_krb5_dll();
478
479	if ( p_krb5_free_context )
480		p_krb5_free_context(CO);
481	}
482
483void
484kssl_krb5_free_principal(krb5_context c, krb5_principal p)
485	{
486	if (!krb5_loaded)
487		load_krb5_dll();
488
489	if ( p_krb5_free_principal )
490		p_krb5_free_principal(c,p);
491	}
492
493krb5_error_code
494kssl_krb5_kt_resolve(krb5_context con,
495                    krb5_const char * sz,
496                    krb5_keytab * kt)
497	{
498	if (!krb5_loaded)
499		load_krb5_dll();
500
501	if ( p_krb5_kt_resolve )
502		return(p_krb5_kt_resolve(con,sz,kt));
503	else
504		return KRB5KRB_ERR_GENERIC;
505	}
506
507krb5_error_code
508kssl_krb5_kt_default(krb5_context con,
509                    krb5_keytab * kt)
510	{
511	if (!krb5_loaded)
512		load_krb5_dll();
513
514	if ( p_krb5_kt_default )
515		return(p_krb5_kt_default(con,kt));
516	else
517		return KRB5KRB_ERR_GENERIC;
518	}
519
520krb5_error_code
521kssl_krb5_free_ticket(krb5_context con,
522                     krb5_ticket * kt)
523	{
524	if (!krb5_loaded)
525		load_krb5_dll();
526
527	if ( p_krb5_free_ticket )
528		return(p_krb5_free_ticket(con,kt));
529	else
530		return KRB5KRB_ERR_GENERIC;
531	}
532
533krb5_error_code
534kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
535                krb5_const krb5_data * data,
536                krb5_const_principal princ, krb5_keytab keytab,
537                krb5_flags * flags, krb5_ticket ** pptkt)
538	{
539	if (!krb5_loaded)
540		load_krb5_dll();
541
542	if ( p_krb5_rd_req )
543		return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
544	else
545		return KRB5KRB_ERR_GENERIC;
546	}
547
548krb5_boolean
549krb5_principal_compare(krb5_context con, krb5_const_principal princ1,
550                krb5_const_principal princ2)
551	{
552	if (!krb5_loaded)
553		load_krb5_dll();
554
555	if ( p_krb5_principal_compare )
556		return(p_krb5_principal_compare(con,princ1,princ2));
557	else
558		return KRB5KRB_ERR_GENERIC;
559	}
560
561krb5_error_code
562krb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys,
563                krb5_ticket *ticket)
564	{
565	if (!krb5_loaded)
566		load_krb5_dll();
567
568	if ( p_krb5_decrypt_tkt_part )
569		return(p_krb5_decrypt_tkt_part(con,keys,ticket));
570	else
571		return KRB5KRB_ERR_GENERIC;
572	}
573
574krb5_error_code
575krb5_timeofday(krb5_context con, krb5_int32 *timeret)
576	{
577	if (!krb5_loaded)
578		load_krb5_dll();
579
580	if ( p_krb5_timeofday )
581		return(p_krb5_timeofday(con,timeret));
582	else
583		return KRB5KRB_ERR_GENERIC;
584	}
585
586krb5_error_code
587krb5_rc_default(krb5_context con, krb5_rcache *rc)
588	{
589	if (!krb5_loaded)
590		load_krb5_dll();
591
592	if ( p_krb5_rc_default )
593		return(p_krb5_rc_default(con,rc));
594	else
595		return KRB5KRB_ERR_GENERIC;
596	}
597
598krb5_error_code
599krb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan)
600	{
601	if (!krb5_loaded)
602		load_krb5_dll();
603
604	if ( p_krb5_rc_initialize )
605		return(p_krb5_rc_initialize(con, rc, lifespan));
606	else
607		return KRB5KRB_ERR_GENERIC;
608	}
609
610krb5_error_code
611krb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp)
612	{
613	if (!krb5_loaded)
614		load_krb5_dll();
615
616	if ( p_krb5_rc_get_lifespan )
617		return(p_krb5_rc_get_lifespan(con, rc, lifespanp));
618	else
619		return KRB5KRB_ERR_GENERIC;
620	}
621
622krb5_error_code
623krb5_rc_destroy(krb5_context con, krb5_rcache rc)
624	{
625	if (!krb5_loaded)
626		load_krb5_dll();
627
628	if ( p_krb5_rc_destroy )
629		return(p_krb5_rc_destroy(con, rc));
630	else
631		return KRB5KRB_ERR_GENERIC;
632	}
633
634size_t
635krb5_checksum_size(krb5_context context,krb5_cksumtype ctype)
636        {
637        if (!krb5_loaded)
638                load_krb5_dll();
639
640        if ( p_krb5_checksum_size )
641                return(p_krb5_checksum_size(context, ctype));
642        else
643                return KRB5KRB_ERR_GENERIC;
644        }
645
646krb5_boolean
647valid_cksumtype(krb5_cksumtype ctype)
648        {
649        if (!krb5_loaded)
650                load_krb5_dll();
651
652        if ( p_valid_cksumtype )
653                return(p_valid_cksumtype(ctype));
654        else
655                return KRB5KRB_ERR_GENERIC;
656        }
657
658krb5_error_code
659krb5_kt_free_entry(krb5_context con,krb5_keytab_entry * entry)
660        {
661        if (!krb5_loaded)
662                load_krb5_dll();
663
664        if ( p_krb5_kt_free_entry )
665                return(p_krb5_kt_free_entry(con,entry));
666        else
667                return KRB5KRB_ERR_GENERIC;
668        }
669
670/* Structure definitions  */
671#ifndef NO_DEF_KRB5_CCACHE
672#ifndef krb5_x
673#define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
674#define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
675#endif
676
677typedef	krb5_pointer	krb5_cc_cursor;	/* cursor for sequential lookup */
678
679typedef struct _krb5_ccache
680	{
681	krb5_magic magic;
682	struct _krb5_cc_ops FAR *ops;
683	krb5_pointer data;
684	} *krb5_ccache;
685
686typedef struct _krb5_cc_ops
687	{
688	krb5_magic magic;
689	char  *prefix;
690	char  * (KRB5_CALLCONV *get_name)
691		(krb5_context, krb5_ccache);
692	krb5_error_code (KRB5_CALLCONV *resolve)
693		(krb5_context, krb5_ccache  *, const char  *);
694	krb5_error_code (KRB5_CALLCONV *gen_new)
695		(krb5_context, krb5_ccache  *);
696	krb5_error_code (KRB5_CALLCONV *init)
697		(krb5_context, krb5_ccache, krb5_principal);
698	krb5_error_code (KRB5_CALLCONV *destroy)
699		(krb5_context, krb5_ccache);
700	krb5_error_code (KRB5_CALLCONV *close)
701		(krb5_context, krb5_ccache);
702	krb5_error_code (KRB5_CALLCONV *store)
703		(krb5_context, krb5_ccache, krb5_creds  *);
704	krb5_error_code (KRB5_CALLCONV *retrieve)
705		(krb5_context, krb5_ccache,
706		krb5_flags, krb5_creds  *, krb5_creds  *);
707	krb5_error_code (KRB5_CALLCONV *get_princ)
708		(krb5_context, krb5_ccache, krb5_principal  *);
709	krb5_error_code (KRB5_CALLCONV *get_first)
710		(krb5_context, krb5_ccache, krb5_cc_cursor  *);
711	krb5_error_code (KRB5_CALLCONV *get_next)
712		(krb5_context, krb5_ccache,
713		krb5_cc_cursor  *, krb5_creds  *);
714	krb5_error_code (KRB5_CALLCONV *end_get)
715		(krb5_context, krb5_ccache, krb5_cc_cursor  *);
716	krb5_error_code (KRB5_CALLCONV *remove_cred)
717		(krb5_context, krb5_ccache,
718		krb5_flags, krb5_creds  *);
719	krb5_error_code (KRB5_CALLCONV *set_flags)
720		(krb5_context, krb5_ccache, krb5_flags);
721	} krb5_cc_ops;
722#endif /* NO_DEF_KRB5_CCACHE */
723
724krb5_error_code
725kssl_krb5_cc_get_principal
726    (krb5_context context, krb5_ccache cache,
727      krb5_principal *principal)
728	{
729	if ( p_krb5_cc_get_principal )
730		return(p_krb5_cc_get_principal(context,cache,principal));
731	else
732		return(krb5_x
733			((cache)->ops->get_princ,(context, cache, principal)));
734	}
735
736krb5_error_code
737kssl_krb5_auth_con_setrcache(krb5_context con, krb5_auth_context acon,
738                             krb5_rcache rcache)
739        {
740        if ( p_krb5_auth_con_setrcache )
741                 return(p_krb5_auth_con_setrcache(con,acon,rcache));
742        else
743                 return KRB5KRB_ERR_GENERIC;
744        }
745
746krb5_error_code
747kssl_krb5_get_server_rcache(krb5_context con, krb5_const krb5_data * data,
748                            krb5_rcache * rcache)
749        {
750	if ( p_krb5_get_server_rcache )
751		return(p_krb5_get_server_rcache(con,data,rcache));
752	else
753		return KRB5KRB_ERR_GENERIC;
754        }
755
756krb5_error_code
757kssl_krb5_auth_con_getrcache(krb5_context con, krb5_auth_context acon,
758                             krb5_rcache * prcache)
759        {
760	if ( p_krb5_auth_con_getrcache )
761		return(p_krb5_auth_con_getrcache(con,acon, prcache));
762	else
763		return KRB5KRB_ERR_GENERIC;
764	}
765
766krb5_error_code
767kssl_krb5_kt_close(krb5_context context, krb5_keytab keytab)
768	{
769	if ( p_krb5_kt_close )
770		return(p_krb5_kt_close(context,keytab));
771	else
772		return KRB5KRB_ERR_GENERIC;
773	}
774
775krb5_error_code
776kssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
777                       krb5_const_principal principal, krb5_kvno vno,
778                       krb5_enctype enctype, krb5_keytab_entry *entry)
779	{
780	if ( p_krb5_kt_get_entry )
781		return(p_krb5_kt_get_entry(context,keytab,principal,vno,enctype,entry));
782	else
783		return KRB5KRB_ERR_GENERIC;
784        }
785#endif  /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
786
787
788/* memory allocation functions for non-temporary storage
789 * (e.g. stuff that gets saved into the kssl context) */
790static void* kssl_calloc(size_t nmemb, size_t size)
791{
792	void* p;
793
794	p=OPENSSL_malloc(nmemb*size);
795	if (p){
796		memset(p, 0, nmemb*size);
797	}
798	return p;
799}
800
801#define kssl_malloc(size) OPENSSL_malloc((size))
802#define kssl_realloc(ptr, size) OPENSSL_realloc(ptr, size)
803#define kssl_free(ptr) OPENSSL_free((ptr))
804
805
806char
807*kstring(char *string)
808        {
809        static char	*null = "[NULL]";
810
811	return ((string == NULL)? null: string);
812        }
813
814/*	Given KRB5 enctype (basically DES or 3DES),
815**	return closest match openssl EVP_ encryption algorithm.
816**	Return NULL for unknown or problematic (krb5_dk_encrypt) enctypes.
817**	Assume ENCTYPE_*_RAW (krb5_raw_encrypt) are OK.
818*/
819const EVP_CIPHER *
820kssl_map_enc(krb5_enctype enctype)
821        {
822	switch (enctype)
823		{
824	case ENCTYPE_DES_HMAC_SHA1:		/*    EVP_des_cbc();       */
825	case ENCTYPE_DES_CBC_CRC:
826	case ENCTYPE_DES_CBC_MD4:
827	case ENCTYPE_DES_CBC_MD5:
828	case ENCTYPE_DES_CBC_RAW:
829				return EVP_des_cbc();
830				break;
831	case ENCTYPE_DES3_CBC_SHA1:		/*    EVP_des_ede3_cbc();  */
832	case ENCTYPE_DES3_CBC_SHA:
833	case ENCTYPE_DES3_CBC_RAW:
834				return EVP_des_ede3_cbc();
835				break;
836	default:                return NULL;
837				break;
838		}
839	}
840
841
842/*	Return true:1 if p "looks like" the start of the real authenticator
843**	described in kssl_skip_confound() below.  The ASN.1 pattern is
844**	"62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
845**	xx and yy are possibly multi-byte length fields.
846*/
847int 	kssl_test_confound(unsigned char *p)
848	{
849	int 	len = 2;
850	int 	xx = 0, yy = 0;
851
852	if (*p++ != 0x62)  return 0;
853	if (*p > 0x82)  return 0;
854	switch(*p)  {
855		case 0x82:  p++;          xx = (*p++ << 8);  xx += *p++;  break;
856		case 0x81:  p++;          xx =  *p++;  break;
857		case 0x80:  return 0;
858		default:    xx = *p++;  break;
859		}
860	if (*p++ != 0x30)  return 0;
861	if (*p > 0x82)  return 0;
862	switch(*p)  {
863		case 0x82:  p++; len+=2;  yy = (*p++ << 8);  yy += *p++;  break;
864		case 0x81:  p++; len++;   yy =  *p++;  break;
865		case 0x80:  return 0;
866		default:    yy = *p++;  break;
867		}
868
869	return (xx - len == yy)? 1: 0;
870	}
871
872/*	Allocate, fill, and return cksumlens array of checksum lengths.
873**	This array holds just the unique elements from the krb5_cksumarray[].
874**	array[n] == 0 signals end of data.
875**
876**      The krb5_cksumarray[] was an internal variable that has since been
877**      replaced by a more general method for storing the data.  It should
878**      not be used.  Instead we use real API calls and make a guess for
879**      what the highest assigned CKSUMTYPE_ constant is.  As of 1.2.2
880**      it is 0x000c (CKSUMTYPE_HMAC_SHA1_DES3).  So we will use 0x0010.
881*/
882size_t  *populate_cksumlens(void)
883	{
884	int 		i, j, n;
885	static size_t 	*cklens = NULL;
886
887#ifdef KRB5_MIT_OLD11
888	n = krb5_max_cksum;
889#else
890	n = 0x0010;
891#endif	/* KRB5_MIT_OLD11 */
892
893#ifdef KRB5CHECKAUTH
894	if (!cklens && !(cklens = (size_t *) calloc(sizeof(int),n+1)))  return NULL;
895
896	for (i=0; i < n; i++)  {
897		if (!valid_cksumtype(i))  continue;	/*  array has holes  */
898		for (j=0; j < n; j++)  {
899			if (cklens[j] == 0)  {
900				cklens[j] = krb5_checksum_size(NULL,i);
901				break;		/*  krb5 elem was new: add   */
902				}
903			if (cklens[j] == krb5_checksum_size(NULL,i))  {
904				break;		/*  ignore duplicate elements */
905				}
906			}
907		}
908#endif	/* KRB5CHECKAUTH */
909
910	return cklens;
911	}
912
913/*	Return pointer to start of real authenticator within authenticator, or
914**	return NULL on error.
915**	Decrypted authenticator looks like this:
916**		[0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
917**	This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
918**	krb5_auth_con_getcksumtype() function advertised in its krb5.h.
919*/
920unsigned char	*kssl_skip_confound(krb5_enctype etype, unsigned char *a)
921	{
922	int 		i, conlen;
923	size_t		cklen;
924	static size_t 	*cksumlens = NULL;
925	unsigned char	*test_auth;
926
927	conlen = (etype)? 8: 0;
928
929	if (!cksumlens  &&  !(cksumlens = populate_cksumlens()))  return NULL;
930	for (i=0; (cklen = cksumlens[i]) != 0; i++)
931		{
932		test_auth = a + conlen + cklen;
933		if (kssl_test_confound(test_auth))  return test_auth;
934		}
935
936	return NULL;
937	}
938
939
940/*	Set kssl_err error info when reason text is a simple string
941**		kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
942*/
943void
944kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
945        {
946	if (kssl_err == NULL)  return;
947
948	kssl_err->reason = reason;
949	BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, "%s", text);
950	return;
951        }
952
953
954/*	Display contents of krb5_data struct, for debugging
955*/
956void
957print_krb5_data(char *label, krb5_data *kdata)
958        {
959	int i;
960
961	printf("%s[%d] ", label, kdata->length);
962	for (i=0; i < (int)kdata->length; i++)
963                {
964		if (0 &&  isprint((int) kdata->data[i]))
965                        printf(	"%c ",  kdata->data[i]);
966		else
967                        printf(	"%02x ", (unsigned char) kdata->data[i]);
968		}
969	printf("\n");
970        }
971
972
973/*	Display contents of krb5_authdata struct, for debugging
974*/
975void
976print_krb5_authdata(char *label, krb5_authdata **adata)
977        {
978	if (adata == NULL)
979                {
980		printf("%s, authdata==0\n", label);
981		return;
982		}
983	printf("%s [%p]\n", label, (void *)adata);
984#if 0
985	{
986        int 	i;
987	printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
988	for (i=0; i < adata->length; i++)
989                {
990                printf((isprint(adata->contents[i]))? "%c ": "%02x",
991                        adata->contents[i]);
992		}
993	printf("\n");
994	}
995#endif
996	}
997
998
999/*	Display contents of krb5_keyblock struct, for debugging
1000*/
1001void
1002print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
1003        {
1004	int i;
1005
1006	if (keyblk == NULL)
1007                {
1008		printf("%s, keyblk==0\n", label);
1009		return;
1010		}
1011#ifdef KRB5_HEIMDAL
1012	printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
1013					   keyblk->keyvalue->length);
1014	for (i=0; i < (int)keyblk->keyvalue->length; i++)
1015                {
1016		printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
1017		}
1018	printf("\n");
1019#else
1020	printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
1021	for (i=0; i < (int)keyblk->length; i++)
1022                {
1023		printf("%02x",keyblk->contents[i]);
1024		}
1025	printf("\n");
1026#endif
1027        }
1028
1029
1030/*	Display contents of krb5_principal_data struct, for debugging
1031**	(krb5_principal is typedef'd == krb5_principal_data *)
1032*/
1033void
1034print_krb5_princ(char *label, krb5_principal_data *princ)
1035        {
1036	int i, ui, uj;
1037
1038	printf("%s principal Realm: ", label);
1039	if (princ == NULL)  return;
1040	for (ui=0; ui < (int)princ->realm.length; ui++)  putchar(princ->realm.data[ui]);
1041	printf(" (nametype %d) has %d strings:\n", princ->type,princ->length);
1042	for (i=0; i < (int)princ->length; i++)
1043                {
1044		printf("\t%d [%d]: ", i, princ->data[i].length);
1045		for (uj=0; uj < (int)princ->data[i].length; uj++)  {
1046			putchar(princ->data[i].data[uj]);
1047			}
1048		printf("\n");
1049		}
1050	return;
1051        }
1052
1053
1054/*	Given krb5 service (typically "kssl") and hostname in kssl_ctx,
1055**	Return encrypted Kerberos ticket for service @ hostname.
1056**	If authenp is non-NULL, also return encrypted authenticator,
1057**	whose data should be freed by caller.
1058**	(Originally was: Create Kerberos AP_REQ message for SSL Client.)
1059**
1060**	19990628	VRS 	Started; Returns Kerberos AP_REQ message.
1061**	20010409	VRS 	Modified for RFC2712; Returns enc tkt.
1062**	20010606	VRS 	May also return optional authenticator.
1063*/
1064krb5_error_code
1065kssl_cget_tkt(	/* UPDATE */	KSSL_CTX *kssl_ctx,
1066                /* OUT    */	krb5_data **enc_ticketp,
1067                /* UPDATE */	krb5_data *authenp,
1068                /* OUT    */	KSSL_ERR *kssl_err)
1069	{
1070	krb5_error_code		krb5rc = KRB5KRB_ERR_GENERIC;
1071	krb5_context		krb5context = NULL;
1072	krb5_auth_context	krb5auth_context = NULL;
1073	krb5_ccache 		krb5ccdef = NULL;
1074	krb5_creds		krb5creds, *krb5credsp = NULL;
1075	krb5_data		krb5_app_req;
1076
1077	kssl_err_set(kssl_err, 0, "");
1078	memset((char *)&krb5creds, 0, sizeof(krb5creds));
1079
1080	if (!kssl_ctx)
1081                {
1082		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1083                        "No kssl_ctx defined.\n");
1084		goto err;
1085		}
1086	else if (!kssl_ctx->service_host)
1087                {
1088		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1089                        "kssl_ctx service_host undefined.\n");
1090		goto err;
1091		}
1092
1093	if ((krb5rc = krb5_init_context(&krb5context)) != 0)
1094                {
1095		BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
1096                        "krb5_init_context() fails: %d\n", krb5rc);
1097		kssl_err->reason = SSL_R_KRB5_C_INIT;
1098		goto err;
1099		}
1100
1101	if ((krb5rc = krb5_sname_to_principal(krb5context,
1102                kssl_ctx->service_host,
1103                (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1104                KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
1105                {
1106		BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
1107                        "krb5_sname_to_principal() fails for %s/%s\n",
1108                        kssl_ctx->service_host,
1109                        (kssl_ctx->service_name)? kssl_ctx->service_name:
1110						  KRB5SVC);
1111		kssl_err->reason = SSL_R_KRB5_C_INIT;
1112		goto err;
1113		}
1114
1115	if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
1116                {
1117		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1118                        "krb5_cc_default fails.\n");
1119		goto err;
1120		}
1121
1122	if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1123                &krb5creds.client)) != 0)
1124                {
1125		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1126                        "krb5_cc_get_principal() fails.\n");
1127		goto err;
1128		}
1129
1130	if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1131                &krb5creds, &krb5credsp)) != 0)
1132                {
1133		kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
1134                        "krb5_get_credentials() fails.\n");
1135		goto err;
1136		}
1137
1138	*enc_ticketp = &krb5credsp->ticket;
1139#ifdef KRB5_HEIMDAL
1140	kssl_ctx->enctype = krb5credsp->session.keytype;
1141#else
1142	kssl_ctx->enctype = krb5credsp->keyblock.enctype;
1143#endif
1144
1145	krb5rc = KRB5KRB_ERR_GENERIC;
1146	/*	caller should free data of krb5_app_req  */
1147	/*  20010406 VRS deleted for real KerberosWrapper
1148	**  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
1149	*/
1150	krb5_app_req.length = 0;
1151	if (authenp)
1152                {
1153		krb5_data	krb5in_data;
1154		const unsigned char	*p;
1155		long		arlen;
1156		KRB5_APREQBODY	*ap_req;
1157
1158		authenp->length = 0;
1159		krb5in_data.data = NULL;
1160		krb5in_data.length = 0;
1161		if ((krb5rc = krb5_mk_req_extended(krb5context,
1162			&krb5auth_context, 0, &krb5in_data, krb5credsp,
1163			&krb5_app_req)) != 0)
1164			{
1165			kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
1166				"krb5_mk_req_extended() fails.\n");
1167			goto err;
1168			}
1169
1170		arlen = krb5_app_req.length;
1171		p = (unsigned char *)krb5_app_req.data;
1172		ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
1173		if (ap_req)
1174			{
1175			authenp->length = i2d_KRB5_ENCDATA(
1176					ap_req->authenticator, NULL);
1177			if (authenp->length  &&
1178				(authenp->data = malloc(authenp->length)))
1179				{
1180				unsigned char	*adp = (unsigned char *)authenp->data;
1181				authenp->length = i2d_KRB5_ENCDATA(
1182						ap_req->authenticator, &adp);
1183				}
1184			}
1185
1186		if (ap_req)  KRB5_APREQ_free((KRB5_APREQ *) ap_req);
1187		if (krb5_app_req.length)
1188                        kssl_krb5_free_data_contents(krb5context,&krb5_app_req);
1189		}
1190#ifdef KRB5_HEIMDAL
1191	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
1192                {
1193		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1194                        "kssl_ctx_setkey() fails.\n");
1195		}
1196#else
1197	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
1198                {
1199		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1200                        "kssl_ctx_setkey() fails.\n");
1201		}
1202#endif
1203	else	krb5rc = 0;
1204
1205 err:
1206#ifdef KSSL_DEBUG
1207	kssl_ctx_show(kssl_ctx);
1208#endif	/* KSSL_DEBUG */
1209
1210	if (krb5creds.client)	krb5_free_principal(krb5context,
1211							krb5creds.client);
1212	if (krb5creds.server)	krb5_free_principal(krb5context,
1213							krb5creds.server);
1214	if (krb5auth_context)	krb5_auth_con_free(krb5context,
1215							krb5auth_context);
1216	if (krb5context)	krb5_free_context(krb5context);
1217	return (krb5rc);
1218	}
1219
1220
1221/*  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
1222**  Return Kerberos error code and kssl_err struct on error.
1223**  Allocates krb5_ticket and krb5_principal; caller should free these.
1224**
1225**	20010410	VRS	Implemented krb5_decode_ticket() as
1226**				old_krb5_decode_ticket(). Missing from MIT1.0.6.
1227**	20010615	VRS 	Re-cast as openssl/asn1 d2i_*() functions.
1228**				Re-used some of the old krb5_decode_ticket()
1229**				code here.  This tkt should alloc/free just
1230**				like the real thing.
1231*/
1232krb5_error_code
1233kssl_TKT2tkt(	/* IN     */	krb5_context	krb5context,
1234		/* IN     */	KRB5_TKTBODY	*asn1ticket,
1235		/* OUT    */	krb5_ticket	**krb5ticket,
1236		/* OUT    */	KSSL_ERR *kssl_err  )
1237        {
1238        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
1239	krb5_ticket 			*new5ticket = NULL;
1240	ASN1_GENERALSTRING		*gstr_svc, *gstr_host;
1241
1242	*krb5ticket = NULL;
1243
1244	if (asn1ticket == NULL  ||  asn1ticket->realm == NULL  ||
1245		asn1ticket->sname == NULL  ||
1246		sk_ASN1_GENERALSTRING_num(asn1ticket->sname->namestring) < 2)
1247		{
1248		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1249			"Null field in asn1ticket.\n");
1250		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1251		return KRB5KRB_ERR_GENERIC;
1252		}
1253
1254	if ((new5ticket = (krb5_ticket *) calloc(1, sizeof(krb5_ticket)))==NULL)
1255		{
1256		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1257			"Unable to allocate new krb5_ticket.\n");
1258		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1259		return ENOMEM;		/*  or  KRB5KRB_ERR_GENERIC;	*/
1260		}
1261
1262	gstr_svc  = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 0);
1263	gstr_host = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 1);
1264
1265	if ((krb5rc = kssl_build_principal_2(krb5context,
1266			&new5ticket->server,
1267			asn1ticket->realm->length, (char *)asn1ticket->realm->data,
1268			gstr_svc->length,  (char *)gstr_svc->data,
1269			gstr_host->length, (char *)gstr_host->data)) != 0)
1270		{
1271		free(new5ticket);
1272		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1273			"Error building ticket server principal.\n");
1274		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1275		return krb5rc;		/*  or  KRB5KRB_ERR_GENERIC;	*/
1276		}
1277
1278	krb5_princ_type(krb5context, new5ticket->server) =
1279			asn1ticket->sname->nametype->data[0];
1280	new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0];
1281	new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0];
1282	new5ticket->enc_part.ciphertext.length =
1283			asn1ticket->encdata->cipher->length;
1284	if ((new5ticket->enc_part.ciphertext.data =
1285		calloc(1, asn1ticket->encdata->cipher->length)) == NULL)
1286		{
1287		free(new5ticket);
1288		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1289			"Error allocating cipher in krb5ticket.\n");
1290		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1291		return KRB5KRB_ERR_GENERIC;
1292		}
1293	else
1294		{
1295		memcpy(new5ticket->enc_part.ciphertext.data,
1296			asn1ticket->encdata->cipher->data,
1297			asn1ticket->encdata->cipher->length);
1298		}
1299
1300	*krb5ticket = new5ticket;
1301	return 0;
1302	}
1303
1304
1305/*	Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
1306**		and krb5 AP_REQ message & message length,
1307**	Return Kerberos session key and client principle
1308**		to SSL Server in KSSL_CTX *kssl_ctx.
1309**
1310**	19990702	VRS 	Started.
1311*/
1312krb5_error_code
1313kssl_sget_tkt(	/* UPDATE */	KSSL_CTX		*kssl_ctx,
1314		/* IN     */	krb5_data		*indata,
1315		/* OUT    */	krb5_ticket_times	*ttimes,
1316		/* OUT    */	KSSL_ERR		*kssl_err  )
1317        {
1318        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
1319        static krb5_context		krb5context = NULL;
1320	static krb5_auth_context	krb5auth_context = NULL;
1321	krb5_ticket 			*krb5ticket = NULL;
1322	KRB5_TKTBODY 			*asn1ticket = NULL;
1323	const unsigned char		*p;
1324	krb5_keytab 			krb5keytab = NULL;
1325	krb5_keytab_entry		kt_entry;
1326	krb5_principal			krb5server;
1327        krb5_rcache                     rcache = NULL;
1328
1329	kssl_err_set(kssl_err, 0, "");
1330
1331	if (!kssl_ctx)
1332                {
1333		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1334			"No kssl_ctx defined.\n");
1335		goto err;
1336		}
1337
1338#ifdef KSSL_DEBUG
1339	printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
1340#endif	/* KSSL_DEBUG */
1341
1342	if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
1343                {
1344		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1345                        "krb5_init_context() fails.\n");
1346		goto err;
1347		}
1348	if (krb5auth_context  &&
1349		(krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
1350                {
1351		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1352                        "krb5_auth_con_free() fails.\n");
1353		goto err;
1354		}
1355	else  krb5auth_context = NULL;
1356	if (!krb5auth_context  &&
1357		(krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
1358                {
1359		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1360                        "krb5_auth_con_init() fails.\n");
1361		goto err;
1362		}
1363
1364
1365	if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
1366		&rcache)))
1367		{
1368 		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1369			"krb5_auth_con_getrcache() fails.\n");
1370 		goto err;
1371		}
1372
1373	if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
1374                (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1375                KRB5_NT_SRV_HST, &krb5server)) != 0)
1376                {
1377		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1378                        "krb5_sname_to_principal() fails.\n");
1379		goto err;
1380		}
1381
1382	if (rcache == NULL)
1383                {
1384                if ((krb5rc = krb5_get_server_rcache(krb5context,
1385			krb5_princ_component(krb5context, krb5server, 0),
1386			&rcache)))
1387                        {
1388		        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1389                                "krb5_get_server_rcache() fails.\n");
1390                  	goto err;
1391                        }
1392                }
1393
1394        if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache)))
1395                {
1396                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1397			"krb5_auth_con_setrcache() fails.\n");
1398                goto err;
1399                }
1400
1401
1402	/*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
1403	*/
1404	if (kssl_ctx->keytab_file)
1405		{
1406		krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1407                        &krb5keytab);
1408		if (krb5rc)
1409			{
1410			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1411				"krb5_kt_resolve() fails.\n");
1412			goto err;
1413			}
1414		}
1415	else
1416		{
1417                krb5rc = krb5_kt_default(krb5context,&krb5keytab);
1418                if (krb5rc)
1419			{
1420			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1421				"krb5_kt_default() fails.\n");
1422			goto err;
1423			}
1424		}
1425
1426	/*	Actual Kerberos5 krb5_recvauth() has initial conversation here
1427	**	o	check KRB5_SENDAUTH_BADAUTHVERS
1428	**		unless KRB5_RECVAUTH_SKIP_VERSION
1429	**	o	check KRB5_SENDAUTH_BADAPPLVERS
1430	**	o	send "0" msg if all OK
1431	*/
1432
1433	/*  20010411 was using AP_REQ instead of true KerberosWrapper
1434	**
1435	**  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
1436	**			&krb5in_data, krb5server, krb5keytab,
1437	**			&ap_option, &krb5ticket)) != 0)  { Error }
1438	*/
1439
1440	p = (unsigned char *)indata->data;
1441	if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
1442						(long) indata->length)) == NULL)
1443		{
1444		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1445			"d2i_KRB5_TICKET() ASN.1 decode failure.\n");
1446		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1447		goto err;
1448		}
1449
1450	/* Was:  krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
1451	if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
1452					kssl_err)) != 0)
1453		{
1454		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1455			"Error converting ASN.1 ticket to krb5_ticket.\n");
1456		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1457		goto err;
1458		}
1459
1460	if (! krb5_principal_compare(krb5context, krb5server,
1461						  krb5ticket->server))  {
1462		krb5rc = KRB5_PRINC_NOMATCH;
1463		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1464			"server principal != ticket principal\n");
1465		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1466		goto err;
1467		}
1468	if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1469			krb5ticket->server, krb5ticket->enc_part.kvno,
1470			krb5ticket->enc_part.enctype, &kt_entry)) != 0)  {
1471		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1472			"krb5_kt_get_entry() fails with %x.\n", krb5rc);
1473		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1474		goto err;
1475		}
1476	if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
1477			krb5ticket)) != 0)  {
1478		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1479			"krb5_decrypt_tkt_part() failed.\n");
1480		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1481		goto err;
1482		}
1483	else  {
1484		krb5_kt_free_entry(krb5context, &kt_entry);
1485#ifdef KSSL_DEBUG
1486		{
1487		int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
1488		printf("Decrypted ticket fields:\n");
1489		printf("\tflags: %X, transit-type: %X",
1490			krb5ticket->enc_part2->flags,
1491			krb5ticket->enc_part2->transited.tr_type);
1492		print_krb5_data("\ttransit-data: ",
1493			&(krb5ticket->enc_part2->transited.tr_contents));
1494		printf("\tcaddrs: %p, authdata: %p\n",
1495			krb5ticket->enc_part2->caddrs,
1496			krb5ticket->enc_part2->authorization_data);
1497		if (paddr)
1498			{
1499			printf("\tcaddrs:\n");
1500			for (i=0; paddr[i] != NULL; i++)
1501				{
1502				krb5_data d;
1503				d.length=paddr[i]->length;
1504				d.data=paddr[i]->contents;
1505				print_krb5_data("\t\tIP: ", &d);
1506				}
1507			}
1508		printf("\tstart/auth/end times: %d / %d / %d\n",
1509			krb5ticket->enc_part2->times.starttime,
1510			krb5ticket->enc_part2->times.authtime,
1511			krb5ticket->enc_part2->times.endtime);
1512		}
1513#endif	/* KSSL_DEBUG */
1514		}
1515
1516	krb5rc = KRB5_NO_TKT_SUPPLIED;
1517	if (!krb5ticket  ||	!krb5ticket->enc_part2  ||
1518                !krb5ticket->enc_part2->client  ||
1519                !krb5ticket->enc_part2->client->data  ||
1520                !krb5ticket->enc_part2->session)
1521                {
1522                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1523                        "bad ticket from krb5_rd_req.\n");
1524		}
1525	else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
1526		 &krb5ticket->enc_part2->client->realm,
1527		 krb5ticket->enc_part2->client->data,
1528		 krb5ticket->enc_part2->client->length))
1529                {
1530		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1531                        "kssl_ctx_setprinc() fails.\n");
1532		}
1533	else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
1534                {
1535		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1536                        "kssl_ctx_setkey() fails.\n");
1537		}
1538	else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID)
1539                {
1540		krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
1541                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1542                        "invalid ticket from krb5_rd_req.\n");
1543		}
1544	else	krb5rc = 0;
1545
1546	kssl_ctx->enctype	= krb5ticket->enc_part.enctype;
1547	ttimes->authtime	= krb5ticket->enc_part2->times.authtime;
1548	ttimes->starttime	= krb5ticket->enc_part2->times.starttime;
1549	ttimes->endtime 	= krb5ticket->enc_part2->times.endtime;
1550	ttimes->renew_till	= krb5ticket->enc_part2->times.renew_till;
1551
1552 err:
1553#ifdef KSSL_DEBUG
1554	kssl_ctx_show(kssl_ctx);
1555#endif	/* KSSL_DEBUG */
1556
1557	if (asn1ticket) 	KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
1558        if (krb5keytab)         krb5_kt_close(krb5context, krb5keytab);
1559	if (krb5ticket) 	krb5_free_ticket(krb5context, krb5ticket);
1560	if (krb5server) 	krb5_free_principal(krb5context, krb5server);
1561	return (krb5rc);
1562        }
1563
1564
1565/*	Allocate & return a new kssl_ctx struct.
1566*/
1567KSSL_CTX	*
1568kssl_ctx_new(void)
1569        {
1570	return ((KSSL_CTX *) kssl_calloc(1, sizeof(KSSL_CTX)));
1571        }
1572
1573
1574/*	Frees a kssl_ctx struct and any allocated memory it holds.
1575**	Returns NULL.
1576*/
1577KSSL_CTX	*
1578kssl_ctx_free(KSSL_CTX *kssl_ctx)
1579        {
1580	if (kssl_ctx == NULL)  return kssl_ctx;
1581
1582	if (kssl_ctx->key)  		OPENSSL_cleanse(kssl_ctx->key,
1583							      kssl_ctx->length);
1584	if (kssl_ctx->key)  		kssl_free(kssl_ctx->key);
1585	if (kssl_ctx->client_princ) 	kssl_free(kssl_ctx->client_princ);
1586	if (kssl_ctx->service_host) 	kssl_free(kssl_ctx->service_host);
1587	if (kssl_ctx->service_name) 	kssl_free(kssl_ctx->service_name);
1588	if (kssl_ctx->keytab_file) 	kssl_free(kssl_ctx->keytab_file);
1589
1590	kssl_free(kssl_ctx);
1591	return (KSSL_CTX *) NULL;
1592        }
1593
1594
1595/*	Given an array of (krb5_data *) entity (and optional realm),
1596**	set the plain (char *) client_princ or service_host member
1597**	of the kssl_ctx struct.
1598*/
1599krb5_error_code
1600kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
1601        krb5_data *realm, krb5_data *entity, int nentities)
1602        {
1603	char	**princ;
1604	int 	length;
1605	int i;
1606
1607	if (kssl_ctx == NULL  ||  entity == NULL)  return KSSL_CTX_ERR;
1608
1609	switch (which)
1610                {
1611        case KSSL_CLIENT:	princ = &kssl_ctx->client_princ;	break;
1612        case KSSL_SERVER:	princ = &kssl_ctx->service_host;	break;
1613        default:		return KSSL_CTX_ERR;			break;
1614		}
1615	if (*princ)  kssl_free(*princ);
1616
1617	/* Add up all the entity->lengths */
1618	length = 0;
1619	for (i=0; i < nentities; i++)
1620		{
1621		length += entity[i].length;
1622		}
1623	/* Add in space for the '/' character(s) (if any) */
1624	length += nentities-1;
1625	/* Space for the ('@'+realm+NULL | NULL) */
1626	length += ((realm)? realm->length + 2: 1);
1627
1628	if ((*princ = kssl_calloc(1, length)) == NULL)
1629		return KSSL_CTX_ERR;
1630	else
1631		{
1632		for (i = 0; i < nentities; i++)
1633			{
1634			strncat(*princ, entity[i].data, entity[i].length);
1635			if (i < nentities-1)
1636				{
1637				strcat (*princ, "/");
1638				}
1639			}
1640		if (realm)
1641                        {
1642			strcat (*princ, "@");
1643			(void) strncat(*princ, realm->data, realm->length);
1644			}
1645		}
1646
1647	return KSSL_CTX_OK;
1648        }
1649
1650
1651/*	Set one of the plain (char *) string members of the kssl_ctx struct.
1652**	Default values should be:
1653**		which == KSSL_SERVICE	=>	"khost" (KRB5SVC)
1654**		which == KSSL_KEYTAB	=>	"/etc/krb5.keytab" (KRB5KEYTAB)
1655*/
1656krb5_error_code
1657kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
1658        {
1659	char	**string;
1660
1661	if (!kssl_ctx)  return KSSL_CTX_ERR;
1662
1663	switch (which)
1664                {
1665        case KSSL_SERVICE:	string = &kssl_ctx->service_name;	break;
1666        case KSSL_SERVER:	string = &kssl_ctx->service_host;	break;
1667        case KSSL_CLIENT:	string = &kssl_ctx->client_princ;	break;
1668        case KSSL_KEYTAB:	string = &kssl_ctx->keytab_file;	break;
1669        default:		return KSSL_CTX_ERR;			break;
1670		}
1671	if (*string)  kssl_free(*string);
1672
1673	if (!text)
1674                {
1675		*string = '\0';
1676		return KSSL_CTX_OK;
1677		}
1678
1679	if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL)
1680		return KSSL_CTX_ERR;
1681	else
1682		strcpy(*string, text);
1683
1684	return KSSL_CTX_OK;
1685        }
1686
1687
1688/*	Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
1689**	struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
1690*/
1691krb5_error_code
1692kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
1693        {
1694	int 		length;
1695	krb5_enctype	enctype;
1696	krb5_octet FAR	*contents = NULL;
1697
1698	if (!kssl_ctx)  return KSSL_CTX_ERR;
1699
1700	if (kssl_ctx->key)
1701                {
1702		OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
1703		kssl_free(kssl_ctx->key);
1704		}
1705
1706	if (session)
1707                {
1708
1709#ifdef KRB5_HEIMDAL
1710		length = session->keyvalue->length;
1711		enctype = session->keytype;
1712		contents = session->keyvalue->contents;
1713#else
1714		length = session->length;
1715		enctype = session->enctype;
1716		contents = session->contents;
1717#endif
1718		kssl_ctx->enctype = enctype;
1719		kssl_ctx->length  = length;
1720		}
1721	else
1722                {
1723		kssl_ctx->enctype = ENCTYPE_UNKNOWN;
1724		kssl_ctx->length  = 0;
1725		return KSSL_CTX_OK;
1726		}
1727
1728	if ((kssl_ctx->key =
1729                (krb5_octet FAR *) kssl_calloc(1, kssl_ctx->length)) == NULL)
1730                {
1731		kssl_ctx->length  = 0;
1732		return KSSL_CTX_ERR;
1733		}
1734	else
1735		memcpy(kssl_ctx->key, contents, length);
1736
1737	return KSSL_CTX_OK;
1738        }
1739
1740
1741/*	Display contents of kssl_ctx struct
1742*/
1743void
1744kssl_ctx_show(KSSL_CTX *kssl_ctx)
1745        {
1746	int 	i;
1747
1748	printf("kssl_ctx: ");
1749	if (kssl_ctx == NULL)
1750                {
1751		printf("NULL\n");
1752		return;
1753		}
1754	else
1755		printf("%p\n", (void *)kssl_ctx);
1756
1757	printf("\tservice:\t%s\n",
1758                (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1759	printf("\tclient:\t%s\n",
1760                (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1761	printf("\tserver:\t%s\n",
1762                (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1763	printf("\tkeytab:\t%s\n",
1764                (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1765	printf("\tkey [%d:%d]:\t",
1766                kssl_ctx->enctype, kssl_ctx->length);
1767
1768	for (i=0; i < kssl_ctx->length  &&  kssl_ctx->key; i++)
1769                {
1770		printf("%02x", kssl_ctx->key[i]);
1771		}
1772	printf("\n");
1773	return;
1774        }
1775
1776    int
1777    kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
1778{
1779    krb5_context		krb5context = NULL;
1780    krb5_keytab 		krb5keytab = NULL;
1781    krb5_keytab_entry           entry;
1782    krb5_principal              princ = NULL;
1783    krb5_error_code  		krb5rc = KRB5KRB_ERR_GENERIC;
1784    int rc = 0;
1785
1786    if ((krb5rc = krb5_init_context(&krb5context)))
1787        return(0);
1788
1789    /*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
1790    */
1791    if (kssl_ctx->keytab_file)
1792    {
1793        krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1794                                  &krb5keytab);
1795        if (krb5rc)
1796            goto exit;
1797    }
1798    else
1799    {
1800        krb5rc = krb5_kt_default(krb5context,&krb5keytab);
1801        if (krb5rc)
1802            goto exit;
1803    }
1804
1805    /* the host key we are looking for */
1806    krb5rc = krb5_sname_to_principal(krb5context, NULL,
1807                                     kssl_ctx->service_name ? kssl_ctx->service_name: KRB5SVC,
1808                                     KRB5_NT_SRV_HST, &princ);
1809
1810    krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1811                                princ,
1812                                0 /* IGNORE_VNO */,
1813                                0 /* IGNORE_ENCTYPE */,
1814                                &entry);
1815    if ( krb5rc == KRB5_KT_NOTFOUND ) {
1816        rc = 1;
1817        goto exit;
1818    } else if ( krb5rc )
1819        goto exit;
1820
1821    krb5_kt_free_entry(krb5context, &entry);
1822    rc = 1;
1823
1824  exit:
1825    if (krb5keytab)     krb5_kt_close(krb5context, krb5keytab);
1826    if (princ)          krb5_free_principal(krb5context, princ);
1827    if (krb5context)	krb5_free_context(krb5context);
1828    return(rc);
1829}
1830
1831int
1832kssl_tgt_is_available(KSSL_CTX *kssl_ctx)
1833        {
1834        krb5_error_code		krb5rc = KRB5KRB_ERR_GENERIC;
1835        krb5_context		krb5context = NULL;
1836        krb5_ccache 		krb5ccdef = NULL;
1837        krb5_creds		krb5creds, *krb5credsp = NULL;
1838        int                     rc = 0;
1839
1840        memset((char *)&krb5creds, 0, sizeof(krb5creds));
1841
1842        if (!kssl_ctx)
1843            return(0);
1844
1845        if (!kssl_ctx->service_host)
1846            return(0);
1847
1848        if ((krb5rc = krb5_init_context(&krb5context)) != 0)
1849            goto err;
1850
1851        if ((krb5rc = krb5_sname_to_principal(krb5context,
1852                                              kssl_ctx->service_host,
1853                                              (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1854                                              KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
1855            goto err;
1856
1857        if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
1858            goto err;
1859
1860        if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1861                                             &krb5creds.client)) != 0)
1862            goto err;
1863
1864        if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1865                                            &krb5creds, &krb5credsp)) != 0)
1866            goto err;
1867
1868        rc = 1;
1869
1870      err:
1871#ifdef KSSL_DEBUG
1872	kssl_ctx_show(kssl_ctx);
1873#endif	/* KSSL_DEBUG */
1874
1875	if (krb5creds.client)	krb5_free_principal(krb5context, krb5creds.client);
1876	if (krb5creds.server)	krb5_free_principal(krb5context, krb5creds.server);
1877	if (krb5context)	krb5_free_context(krb5context);
1878        return(rc);
1879	}
1880
1881#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_WIN32)
1882void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1883	{
1884#ifdef KRB5_HEIMDAL
1885	data->length = 0;
1886        if (data->data)
1887            free(data->data);
1888#elif defined(KRB5_MIT_OLD11)
1889	if (data->data)  {
1890		krb5_xfree(data->data);
1891		data->data = 0;
1892		}
1893#else
1894	krb5_free_data_contents(NULL, data);
1895#endif
1896	}
1897#endif /* !OPENSSL_SYS_WINDOWS && !OPENSSL_SYS_WIN32 */
1898
1899
1900/*  Given pointers to KerberosTime and struct tm structs, convert the
1901**  KerberosTime string to struct tm.  Note that KerberosTime is a
1902**  ASN1_GENERALIZEDTIME value, constrained to GMT with no fractional
1903**  seconds as defined in RFC 1510.
1904**  Return pointer to the (partially) filled in struct tm on success,
1905**  return NULL on failure.
1906*/
1907struct tm	*k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
1908	{
1909	char 		c, *p;
1910
1911	if (!k_tm)  return NULL;
1912	if (gtime == NULL  ||  gtime->length < 14)  return NULL;
1913	if (gtime->data == NULL)  return NULL;
1914
1915	p = (char *)&gtime->data[14];
1916
1917	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_sec  = atoi(p);      *(p+2) = c;
1918	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_min  = atoi(p);      *(p+2) = c;
1919	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_hour = atoi(p);      *(p+2) = c;
1920	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_mday = atoi(p);      *(p+2) = c;
1921	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_mon  = atoi(p)-1;    *(p+2) = c;
1922	c = *p;	 *p = '\0';  p -= 4;  k_tm->tm_year = atoi(p)-1900; *(p+4) = c;
1923
1924	return k_tm;
1925	}
1926
1927
1928/*  Helper function for kssl_validate_times().
1929**  We need context->clockskew, but krb5_context is an opaque struct.
1930**  So we try to sneek the clockskew out through the replay cache.
1931**	If that fails just return a likely default (300 seconds).
1932*/
1933krb5_deltat	get_rc_clockskew(krb5_context context)
1934	{
1935	krb5_rcache 	rc;
1936	krb5_deltat 	clockskew;
1937
1938	if (krb5_rc_default(context, &rc))  return KSSL_CLOCKSKEW;
1939	if (krb5_rc_initialize(context, rc, 0))  return KSSL_CLOCKSKEW;
1940	if (krb5_rc_get_lifespan(context, rc, &clockskew))  {
1941		clockskew = KSSL_CLOCKSKEW;
1942		}
1943	(void) krb5_rc_destroy(context, rc);
1944	return clockskew;
1945	}
1946
1947
1948/*  kssl_validate_times() combines (and more importantly exposes)
1949**  the MIT KRB5 internal function krb5_validate_times() and the
1950**  in_clock_skew() macro.  The authenticator client time is checked
1951**  to be within clockskew secs of the current time and the current
1952**  time is checked to be within the ticket start and expire times.
1953**  Either check may be omitted by supplying a NULL value.
1954**  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
1955**  See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
1956**  20010420 VRS
1957*/
1958krb5_error_code  kssl_validate_times(	krb5_timestamp atime,
1959					krb5_ticket_times *ttimes)
1960	{
1961	krb5_deltat 	skew;
1962	krb5_timestamp	start, now;
1963	krb5_error_code	rc;
1964	krb5_context	context;
1965
1966	if ((rc = krb5_init_context(&context)))	 return SSL_R_KRB5_S_BAD_TICKET;
1967	skew = get_rc_clockskew(context);
1968	if ((rc = krb5_timeofday(context,&now))) return SSL_R_KRB5_S_BAD_TICKET;
1969	krb5_free_context(context);
1970
1971	if (atime  &&  labs(atime - now) >= skew)  return SSL_R_KRB5_S_TKT_SKEW;
1972
1973	if (! ttimes)  return 0;
1974
1975	start = (ttimes->starttime != 0)? ttimes->starttime: ttimes->authtime;
1976	if (start - now > skew)  return SSL_R_KRB5_S_TKT_NYV;
1977	if ((now - ttimes->endtime) > skew)  return SSL_R_KRB5_S_TKT_EXPIRED;
1978
1979#ifdef KSSL_DEBUG
1980	printf("kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
1981		start, atime, now, skew, ttimes->endtime);
1982#endif	/* KSSL_DEBUG */
1983
1984	return 0;
1985	}
1986
1987
1988/*  Decode and decrypt given DER-encoded authenticator, then pass
1989**  authenticator ctime back in *atimep (or 0 if time unavailable).
1990**  Returns krb5_error_code and kssl_err on error.  A NULL
1991**  authenticator (authentp->length == 0) is not considered an error.
1992**  Note that kssl_check_authent() makes use of the KRB5 session key;
1993**  you must call kssl_sget_tkt() to get the key before calling this routine.
1994*/
1995krb5_error_code  kssl_check_authent(
1996			/* IN     */	KSSL_CTX	*kssl_ctx,
1997                        /* IN     */   	krb5_data	*authentp,
1998			/* OUT    */	krb5_timestamp	*atimep,
1999			/* OUT    */    KSSL_ERR	*kssl_err  )
2000	{
2001        krb5_error_code		krb5rc = 0;
2002	KRB5_ENCDATA		*dec_authent = NULL;
2003	KRB5_AUTHENTBODY	*auth = NULL;
2004	krb5_enctype		enctype;
2005	EVP_CIPHER_CTX		ciph_ctx;
2006	const EVP_CIPHER	*enc = NULL;
2007	unsigned char		iv[EVP_MAX_IV_LENGTH];
2008	const unsigned char	*p;
2009	unsigned char		*unenc_authent;
2010	int 			outl, unencbufsize;
2011	struct tm		tm_time, *tm_l, *tm_g;
2012	time_t			now, tl, tg, tr, tz_offset;
2013
2014	EVP_CIPHER_CTX_init(&ciph_ctx);
2015	*atimep = 0;
2016	kssl_err_set(kssl_err, 0, "");
2017
2018#ifndef KRB5CHECKAUTH
2019	authentp = NULL;
2020#else
2021#if	KRB5CHECKAUTH == 0
2022	authentp = NULL;
2023#endif
2024#endif	/* KRB5CHECKAUTH */
2025
2026	if (authentp == NULL  ||  authentp->length == 0)  return 0;
2027
2028#ifdef KSSL_DEBUG
2029        {
2030        unsigned int ui;
2031	printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
2032	p = authentp->data;
2033	for (ui=0; ui < authentp->length; ui++)  printf("%02x ",p[ui]);
2034	printf("\n");
2035        }
2036#endif	/* KSSL_DEBUG */
2037
2038	unencbufsize = 2 * authentp->length;
2039	if ((unenc_authent = calloc(1, unencbufsize)) == NULL)
2040		{
2041		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2042			"Unable to allocate authenticator buffer.\n");
2043		krb5rc = KRB5KRB_ERR_GENERIC;
2044		goto err;
2045		}
2046
2047	p = (unsigned char *)authentp->data;
2048	if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
2049					(long) authentp->length)) == NULL)
2050		{
2051		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2052                        "Error decoding authenticator.\n");
2053		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2054		goto err;
2055		}
2056
2057	enctype = dec_authent->etype->data[0];	/* should = kssl_ctx->enctype */
2058#if !defined(KRB5_MIT_OLD11)
2059            switch ( enctype ) {
2060            case ENCTYPE_DES3_CBC_SHA1:		/*    EVP_des_ede3_cbc();  */
2061            case ENCTYPE_DES3_CBC_SHA:
2062            case ENCTYPE_DES3_CBC_RAW:
2063                krb5rc = 0;                     /* Skip, can't handle derived keys */
2064                goto err;
2065            }
2066#endif
2067	enc = kssl_map_enc(enctype);
2068	memset(iv, 0, sizeof iv);       /* per RFC 1510 */
2069
2070	if (enc == NULL)
2071		{
2072		/*  Disable kssl_check_authent for ENCTYPE_DES3_CBC_SHA1.
2073		**  This enctype indicates the authenticator was encrypted
2074		**  using key-usage derived keys which openssl cannot decrypt.
2075		*/
2076		goto err;
2077		}
2078
2079        if (!EVP_CipherInit(&ciph_ctx,enc,kssl_ctx->key,iv,0))
2080                {
2081                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2082                        "EVP_CipherInit error decrypting authenticator.\n");
2083                krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2084                goto err;
2085                }
2086        outl = dec_authent->cipher->length;
2087        if (!EVP_Cipher(&ciph_ctx,unenc_authent,dec_authent->cipher->data,outl))
2088                {
2089                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2090                        "EVP_Cipher error decrypting authenticator.\n");
2091                krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2092                goto err;
2093                }
2094        EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2095
2096#ifdef KSSL_DEBUG
2097	printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl);
2098	for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]);
2099	printf("\n");
2100#endif	/* KSSL_DEBUG */
2101
2102	if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL)
2103		{
2104		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2105                        "confounded by authenticator.\n");
2106		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2107		goto err;
2108		}
2109	outl -= p - unenc_authent;
2110
2111	if ((auth = (KRB5_AUTHENTBODY *) d2i_KRB5_AUTHENT(NULL, &p,
2112							  (long) outl))==NULL)
2113		{
2114		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2115                        "Error decoding authenticator body.\n");
2116		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2117		goto err;
2118		}
2119
2120	memset(&tm_time,0,sizeof(struct tm));
2121	if (k_gmtime(auth->ctime, &tm_time)  &&
2122		((tr = mktime(&tm_time)) != (time_t)(-1)))
2123 		{
2124 		now  = time(&now);
2125 		tm_l = localtime(&now); 	tl = mktime(tm_l);
2126 		tm_g = gmtime(&now);		tg = mktime(tm_g);
2127 		tz_offset = tg - tl;
2128
2129		*atimep = tr - tz_offset;
2130 		}
2131
2132#ifdef KSSL_DEBUG
2133	printf("kssl_check_authent: returns %d for client time ", *atimep);
2134	if (auth && auth->ctime && auth->ctime->length && auth->ctime->data)
2135		printf("%.*s\n", auth->ctime->length, auth->ctime->data);
2136	else	printf("NULL\n");
2137#endif	/* KSSL_DEBUG */
2138
2139 err:
2140	if (auth)		KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
2141	if (dec_authent)	KRB5_ENCDATA_free(dec_authent);
2142	if (unenc_authent)	free(unenc_authent);
2143	EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2144	return krb5rc;
2145	}
2146
2147
2148/*  Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
2149**  because I dont't know how to stub varargs.
2150**  Returns krb5_error_code == ENOMEM on alloc error, otherwise
2151**  passes back newly constructed principal, which should be freed by caller.
2152*/
2153krb5_error_code  kssl_build_principal_2(
2154			/* UPDATE */	krb5_context	context,
2155			/* OUT    */	krb5_principal	*princ,
2156			/* IN     */	int rlen,  const char *realm,
2157			/* IN	  */	int slen,  const char *svc,
2158			/* IN	  */	int hlen,  const char *host)
2159	{
2160	krb5_data		*p_data = NULL;
2161	krb5_principal		new_p = NULL;
2162        char			*new_r = NULL;
2163
2164	if ((p_data = (krb5_data *) calloc(2, sizeof(krb5_data))) == NULL  ||
2165	    (new_p = (krb5_principal) calloc(1, sizeof(krb5_principal_data)))
2166			== NULL)  goto err;
2167	new_p->length = 2;
2168	new_p->data = p_data;
2169
2170	if ((new_r = calloc(1, rlen + 1)) == NULL)  goto err;
2171	memcpy(new_r, realm, rlen);
2172	krb5_princ_set_realm_length(context, new_p, rlen);
2173	krb5_princ_set_realm_data(context, new_p, new_r);
2174
2175	if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL)  goto err;
2176	memcpy(new_p->data[0].data, svc, slen);
2177	new_p->data[0].length = slen;
2178
2179	if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL)  goto err;
2180	memcpy(new_p->data[1].data, host, hlen);
2181	new_p->data[1].length = hlen;
2182
2183	krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN;
2184	*princ = new_p;
2185	return 0;
2186
2187 err:
2188	if (new_p  &&  new_p[0].data)	free(new_p[0].data);
2189	if (new_p  &&  new_p[1].data)	free(new_p[1].data);
2190	if (new_p)	free(new_p);
2191	if (new_r)	free(new_r);
2192	return ENOMEM;
2193	}
2194
2195
2196#else /* !OPENSSL_NO_KRB5 */
2197
2198#if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
2199static void *dummy=&dummy;
2200#endif
2201
2202#endif	/* !OPENSSL_NO_KRB5	*/
2203
2204