Patches from Vern Staats <staatsvr@asc.hpc.mil> to get Kerberos 5 in
[openssl.git] / ssl / kssl.c
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 #ifndef OPENSSL_NO_KRB5
71 #include <string.h>
72 #define _XOPEN_SOURCE /* glibc2 needs this to declare strptime() */
73 #include <time.h>
74
75 #include <openssl/ssl.h>
76 #include <openssl/evp.h>
77 #include <openssl/objects.h>
78 #include <openssl/krb5_asn.h>
79
80 /* 
81  * When OpenSSL is built on Windows, we do not want to require that
82  * the Kerberos DLLs be available in order for the OpenSSL DLLs to
83  * work.  Therefore, all Kerberos routines are loaded at run time
84  * and we do not link to a .LIB file.
85  */
86
87 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
88 /* 
89  * The purpose of the following pre-processor statements is to provide
90  * compatibility with different releases of MIT Kerberos for Windows.
91  * All versions up to 1.2 used macros.  But macros do not allow for
92  * a binary compatible interface for DLLs.  Therefore, all macros are
93  * being replaced by function calls.  The following code will allow
94  * an OpenSSL DLL built on Windows to work whether or not the macro
95  * or function form of the routines are utilized.
96  */
97 #ifdef  krb5_cc_get_principal
98 #define NO_DEF_KRB5_CCACHE
99 #undef  krb5_cc_get_principal
100 #endif
101 #define krb5_cc_get_principal    kssl_krb5_cc_get_principal
102
103 #define krb5_free_data_contents  kssl_krb5_free_data_contents   
104 #define krb5_free_context        kssl_krb5_free_context         
105 #define krb5_auth_con_free       kssl_krb5_auth_con_free        
106 #define krb5_free_principal      kssl_krb5_free_principal       
107 #define krb5_mk_req_extended     kssl_krb5_mk_req_extended      
108 #define krb5_get_credentials     kssl_krb5_get_credentials      
109 #define krb5_cc_default          kssl_krb5_cc_default           
110 #define krb5_sname_to_principal  kssl_krb5_sname_to_principal   
111 #define krb5_init_context        kssl_krb5_init_context         
112 #define krb5_free_ticket         kssl_krb5_free_ticket          
113 #define krb5_rd_req              kssl_krb5_rd_req               
114 #define krb5_kt_default          kssl_krb5_kt_default           
115 #define krb5_kt_resolve          kssl_krb5_kt_resolve           
116 #define krb5_auth_con_init       kssl_krb5_auth_con_init        
117
118 #define krb5_principal_compare   kssl_krb5_principal_compare
119 /* macro  #define krb5_kt_get_entry        kssl_krb5_kt_get_entry  */
120 #define krb5_decrypt_tkt_part    kssl_krb5_decrypt_tkt_part
121 #define krb5_timeofday           kssl_krb5_timeofday
122 #define krb5_rc_default           kssl_krb5_rc_default
123 #define krb5_krb5_rc_initialize   kssl_krb5_rc_initialize
124 #define krb5_krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
125 #define krb5_krb5_rc_destroy      kssl_krb5_rc_destroy
126
127 /* Prototypes for built in stubs */
128 void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
129 void kssl_krb5_free_principal(krb5_context, krb5_principal );
130 krb5_error_code kssl_krb5_kt_resolve(krb5_context,
131                                      krb5_const char *,
132                                      krb5_keytab *);
133 krb5_error_code kssl_krb5_kt_default(krb5_context,
134                                      krb5_keytab *);
135 krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
136 krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *, 
137                                  krb5_const krb5_data *,
138                                  krb5_const_principal, krb5_keytab, 
139                                  krb5_flags *,krb5_ticket **);
140
141 krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
142                                          krb5_const_principal);
143 krb5_error_code krb5_decrypt_tkt_part(krb5_context, krb5_const krb5_keyblock *,
144                                       krb5_ticket *);
145 krb5_error_code krb5_timeofday(krb5_context context, krb5_int32 *timeret);
146 krb5_error_code krb5_rc_default(krb5_context context, krb5_rcache *rc);
147 krb5_error_code krb5_rc_initialize(krb5_context context, krb5_rcache rc,
148                                      krb5_deltat lifespan);
149 krb5_error_code krb5_rc_get_lifespan(krb5_context context, krb5_rcache rc,
150                                      krb5_deltat *lifespan);
151 krb5_error_code krb5_rc_destroy(krb5_context context, krb5_rcache rc);
152
153 krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
154                                           krb5_auth_context  *,
155                                           krb5_const krb5_flags,
156                                           krb5_data  *,
157                                           krb5_creds  *,
158                                           krb5_data  * );
159 krb5_error_code kssl_krb5_init_context(krb5_context *);
160 void kssl_krb5_free_context(krb5_context);
161 krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache  *);
162 krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
163                                              krb5_const char  *,
164                                              krb5_const char  *,
165                                              krb5_int32,
166                                              krb5_principal  *);
167 krb5_error_code kssl_krb5_get_credentials(krb5_context,
168                                           krb5_const krb5_flags,
169                                           krb5_ccache,
170                                           krb5_creds  *,
171                                           krb5_creds  *  *);
172 krb5_error_code kssl_krb5_auth_con_init(krb5_context,
173                                         krb5_auth_context  *);
174 krb5_error_code kssl_krb5_cc_get_principal(krb5_context context, 
175                                            krb5_ccache cache,
176                                            krb5_principal *principal);
177 krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
178
179 /* Function pointers (almost all Kerberos functions are _stdcall) */
180 static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)
181         =NULL;
182 static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )
183         =NULL;
184 static krb5_error_code(_stdcall *p_krb5_kt_resolve)
185                         (krb5_context, krb5_const char *, krb5_keytab *)=NULL;
186 static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
187                                                      krb5_keytab *)=NULL;
188 static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context, 
189                                                       krb5_ticket *)=NULL;
190 static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context, 
191                                                  krb5_auth_context *, 
192                                                  krb5_const krb5_data *,
193                                                  krb5_const_principal, 
194                                                  krb5_keytab, krb5_flags *,
195                                                  krb5_ticket **)=NULL;
196 static krb5_error_code (_stdcall *p_krb5_mk_req_extended)
197                         (krb5_context, krb5_auth_context *,
198                          krb5_const krb5_flags, krb5_data *, krb5_creds *,
199                          krb5_data * )=NULL;
200 static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
201 static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
202 static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
203                                                      krb5_ccache  *)=NULL;
204 static krb5_error_code (_stdcall *p_krb5_sname_to_principal)
205                         (krb5_context, krb5_const char *, krb5_const char *,
206                          krb5_int32, krb5_principal *)=NULL;
207 static krb5_error_code (_stdcall *p_krb5_get_credentials)
208                         (krb5_context, krb5_const krb5_flags, krb5_ccache,
209                          krb5_creds *, krb5_creds **)=NULL;
210 static krb5_error_code (_stdcall *p_krb5_auth_con_init)
211                         (krb5_context, krb5_auth_context *)=NULL;
212 static krb5_error_code (_stdcall *p_krb5_cc_get_principal)
213                         (krb5_context context, krb5_ccache cache,
214                          krb5_principal *principal)=NULL;
215 static krb5_error_code (_stdcall *p_krb5_auth_con_free)
216                         (krb5_context, krb5_auth_context)=NULL;
217 static int krb5_loaded = 0;     /* only attempt to initialize func ptrs once */
218
219 /* Function to Load the Kerberos 5 DLL and initialize function pointers */
220 void
221 load_krb5_dll(void)
222         {
223         HANDLE hKRB5_32;
224     
225         krb5_loaded++;
226         hKRB5_32 = LoadLibrary("KRB5_32");
227         if (!hKRB5_32)
228                 return;
229
230         (FARPROC) p_krb5_free_data_contents =
231                 GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
232         (FARPROC) p_krb5_free_context =
233                 GetProcAddress( hKRB5_32, "krb5_free_context" );
234         (FARPROC) p_krb5_auth_con_free =
235                 GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
236         (FARPROC) p_krb5_free_principal =
237                 GetProcAddress( hKRB5_32, "krb5_free_principal" );
238         (FARPROC) p_krb5_mk_req_extended =
239                 GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
240         (FARPROC) p_krb5_get_credentials =
241                 GetProcAddress( hKRB5_32, "krb5_get_credentials" );
242         (FARPROC) p_krb5_cc_get_principal =
243                 GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
244         (FARPROC) p_krb5_cc_default =
245                 GetProcAddress( hKRB5_32, "krb5_cc_default" );
246         (FARPROC) p_krb5_sname_to_principal =
247                 GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
248         (FARPROC) p_krb5_init_context =
249                 GetProcAddress( hKRB5_32, "krb5_init_context" );
250         (FARPROC) p_krb5_free_ticket =
251                 GetProcAddress( hKRB5_32, "krb5_free_ticket" );
252         (FARPROC) p_krb5_rd_req =
253                 GetProcAddress( hKRB5_32, "krb5_rd_req" );
254         (FARPROC) p_krb5_principal_compare =
255                 GetProcAddress( hKRB5_32, "krb5_principal_compare" );
256         (FARPROC) p_krb5_decrypt_tkt_part =
257                 GetProcAddress( hKRB5_32, "krb5_decrypt_tkt_part" );
258         (FARPROC) p_krb5_timeofday =
259                 GetProcAddress( hKRB5_32, "krb5_timeofday" );
260         (FARPROC) p_krb5_rc_default =
261                 GetProcAddress( hKRB5_32, "krb5_rc_default" );
262         (FARPROC) p_krb5_rc_initialize =
263                 GetProcAddress( hKRB5_32, "krb5_rc_initialize" );
264         (FARPROC) p_krb5_rc_get_lifespan =
265                 GetProcAddress( hKRB5_32, "krb5_rc_get_lifespan" );
266         (FARPROC) p_krb5_rc_destroy =
267                 GetProcAddress( hKRB5_32, "krb5_rc_destroy" );
268         (FARPROC) p_krb5_kt_default =
269                 GetProcAddress( hKRB5_32, "krb5_kt_default" );
270         (FARPROC) p_krb5_kt_resolve =
271                 GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
272         (FARPROC) p_krb5_auth_con_init =
273                 GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
274         }
275
276 /* Stubs for each function to be dynamicly loaded */
277 void
278 kssl_krb5_free_data_contents(krb5_context CO, krb5_data  * data)
279         {
280         if (!krb5_loaded)
281                 load_krb5_dll();
282
283         if ( p_krb5_free_data_contents )
284                 p_krb5_free_data_contents(CO,data);
285         }
286
287 krb5_error_code
288 kssl_krb5_mk_req_extended (krb5_context CO,
289                           krb5_auth_context  * pACO,
290                           krb5_const krb5_flags F,
291                           krb5_data  * pD1,
292                           krb5_creds  * pC,
293                           krb5_data  * pD2)
294         {
295         if (!krb5_loaded)
296                 load_krb5_dll();
297
298         if ( p_krb5_mk_req_extended )
299                 return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
300         else
301                 return KRB5KRB_ERR_GENERIC;
302         }
303 krb5_error_code
304 kssl_krb5_auth_con_init(krb5_context CO,
305                        krb5_auth_context  * pACO)
306         {
307         if (!krb5_loaded)
308                 load_krb5_dll();
309
310         if ( p_krb5_auth_con_init )
311                 return(p_krb5_auth_con_init(CO,pACO));
312         else
313                 return KRB5KRB_ERR_GENERIC;
314         }
315 krb5_error_code
316 kssl_krb5_auth_con_free (krb5_context CO,
317                         krb5_auth_context ACO)
318         {
319         if (!krb5_loaded)
320                 load_krb5_dll();
321
322         if ( p_krb5_auth_con_free )
323                 return(p_krb5_auth_con_free(CO,ACO));
324         else
325                 return KRB5KRB_ERR_GENERIC;
326         }
327 krb5_error_code
328 kssl_krb5_get_credentials(krb5_context CO,
329                          krb5_const krb5_flags F,
330                          krb5_ccache CC,
331                          krb5_creds  * pCR,
332                          krb5_creds  ** ppCR)
333         {
334         if (!krb5_loaded)
335                 load_krb5_dll();
336
337         if ( p_krb5_get_credentials )
338                 return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
339         else
340                 return KRB5KRB_ERR_GENERIC;
341         }
342 krb5_error_code
343 kssl_krb5_sname_to_principal(krb5_context CO,
344                             krb5_const char  * pC1,
345                             krb5_const char  * pC2,
346                             krb5_int32 I,
347                             krb5_principal  * pPR)
348         {
349         if (!krb5_loaded)
350                 load_krb5_dll();
351
352         if ( p_krb5_sname_to_principal )
353                 return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
354         else
355                 return KRB5KRB_ERR_GENERIC;
356         }
357
358 krb5_error_code
359 kssl_krb5_cc_default(krb5_context CO,
360                     krb5_ccache  * pCC)
361         {
362         if (!krb5_loaded)
363                 load_krb5_dll();
364
365         if ( p_krb5_cc_default )
366                 return(p_krb5_cc_default(CO,pCC));
367         else
368                 return KRB5KRB_ERR_GENERIC;
369         }
370
371 krb5_error_code
372 kssl_krb5_init_context(krb5_context * pCO)
373         {
374         if (!krb5_loaded)
375                 load_krb5_dll();
376
377         if ( p_krb5_init_context )
378                 return(p_krb5_init_context(pCO));
379         else
380                 return KRB5KRB_ERR_GENERIC;
381         }
382
383 void
384 kssl_krb5_free_context(krb5_context CO)
385         {
386         if (!krb5_loaded)
387                 load_krb5_dll();
388
389         if ( p_krb5_free_context )
390                 p_krb5_free_context(CO);
391         }
392
393 void
394 kssl_krb5_free_principal(krb5_context c, krb5_principal p)
395         {
396         if (!krb5_loaded)
397                 load_krb5_dll();
398
399         if ( p_krb5_free_principal )
400                 p_krb5_free_principal(c,p);
401         }
402
403 krb5_error_code
404 kssl_krb5_kt_resolve(krb5_context con,
405                     krb5_const char * sz,
406                     krb5_keytab * kt)
407         {
408         if (!krb5_loaded)
409                 load_krb5_dll();
410
411         if ( p_krb5_kt_resolve )
412                 return(p_krb5_kt_resolve(con,sz,kt));
413         else
414                 return KRB5KRB_ERR_GENERIC;
415         }
416
417 krb5_error_code
418 kssl_krb5_kt_default(krb5_context con,
419                     krb5_keytab * kt)
420         {
421         if (!krb5_loaded)
422                 load_krb5_dll();
423
424         if ( p_krb5_kt_default )
425                 return(p_krb5_kt_default(con,kt));
426         else
427                 return KRB5KRB_ERR_GENERIC;
428         }
429
430 krb5_error_code
431 kssl_krb5_free_ticket(krb5_context con,
432                      krb5_ticket * kt)
433         {
434         if (!krb5_loaded)
435                 load_krb5_dll();
436
437         if ( p_krb5_free_ticket )
438                 return(p_krb5_free_ticket(con,kt));
439         else
440                 return KRB5KRB_ERR_GENERIC;
441         }
442
443 krb5_error_code
444 kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
445                 krb5_const krb5_data * data,
446                 krb5_const_principal princ, krb5_keytab keytab,
447                 krb5_flags * flags, krb5_ticket ** pptkt)
448         {
449         if (!krb5_loaded)
450                 load_krb5_dll();
451
452         if ( p_krb5_rd_req )
453                 return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
454         else
455                 return KRB5KRB_ERR_GENERIC;
456         }
457
458 krb5_boolean
459 krb5_principal_compare(krb5_context con, krb5_const_principal princ1,
460                 krb5_const_principal princ2)
461         {
462         if (!krb5_loaded)
463                 load_krb5_dll();
464
465         if ( p_krb5_principal_compare )
466                 return(p_krb5_principal_compare(con,princ1,princ2);
467         else
468                 return KRB5KRB_ERR_GENERIC;
469         }
470
471 krb5_error_code
472 krb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys,
473                 krb5_ticket *ticket)
474         {
475         if (!krb5_loaded)
476                 load_krb5_dll();
477
478         if ( p_krb5_decrypt_tkt_part )
479                 return(p_krb5_decrypt_tkt_part(con,keys,ticket);
480         else
481                 return KRB5KRB_ERR_GENERIC;
482         }
483
484 krb5_error_code
485 krb5_timeofday(krb5_context con, krb5_int32 *timeret)
486         {
487         if (!krb5_loaded)
488                 load_krb5_dll();
489
490         if ( p_krb5_timeofday )
491                 return(p_krb5_timeofday(con,timeret);
492         else
493                 return KRB5KRB_ERR_GENERIC;
494         }
495
496 krb5_error_code
497 krb5_rc_default(krb5_context con, krb5_rcache *rc)
498         {
499         if (!krb5_loaded)
500                 load_krb5_dll();
501
502         if ( p_krb5_rc_default )
503                 return(p_krb5_rc_default(con,rc);
504         else
505                 return KRB5KRB_ERR_GENERIC;
506         }
507
508 krb5_error_code
509 krb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan)
510         {
511         if (!krb5_loaded)
512                 load_krb5_dll();
513
514         if ( p_krb5_rc_initialize )
515                 return(p_krb5_rc_initialize(con, rc, lifespan);
516         else
517                 return KRB5KRB_ERR_GENERIC;
518         }
519
520 krb5_error_code
521 krb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp)
522         {
523         if (!krb5_loaded)
524                 load_krb5_dll();
525
526         if ( p_krb5_rc_get_lifespan )
527                 return(p_krb5_rc_get_lifespan(con, rc, lifespanp);
528         else
529                 return KRB5KRB_ERR_GENERIC;
530         }
531
532 krb5_error_code
533 krb5_rc_destroy(krb5_context con, krb5_rcache rc)
534         {
535         if (!krb5_loaded)
536                 load_krb5_dll();
537
538         if ( p_krb5_rc_destroy )
539                 return(p_krb5_rc_destroy(con, rc);
540         else
541                 return KRB5KRB_ERR_GENERIC;
542         }
543
544 /* Structure definitions  */
545 #ifndef NO_DEF_KRB5_CCACHE
546 #ifndef krb5_x
547 #define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
548 #define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
549 #endif 
550
551 typedef krb5_pointer    krb5_cc_cursor; /* cursor for sequential lookup */
552
553 typedef struct _krb5_ccache
554         {
555         krb5_magic magic;
556         struct _krb5_cc_ops FAR *ops;
557         krb5_pointer data;
558         } *krb5_ccache;
559
560 typedef struct _krb5_cc_ops
561         {
562         krb5_magic magic;
563         char  *prefix;
564         char  * (KRB5_CALLCONV *get_name)
565                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
566         krb5_error_code (KRB5_CALLCONV *resolve)
567                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache  *, const char  *));
568         krb5_error_code (KRB5_CALLCONV *gen_new)
569                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache  *));
570         krb5_error_code (KRB5_CALLCONV *init)
571                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal));
572         krb5_error_code (KRB5_CALLCONV *destroy)
573                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
574         krb5_error_code (KRB5_CALLCONV *close)
575                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
576         krb5_error_code (KRB5_CALLCONV *store)
577                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_creds  *));
578         krb5_error_code (KRB5_CALLCONV *retrieve)
579                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
580                 krb5_flags, krb5_creds  *, krb5_creds  *));
581         krb5_error_code (KRB5_CALLCONV *get_princ)
582                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal  *));
583         krb5_error_code (KRB5_CALLCONV *get_first)
584                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor  *));
585         krb5_error_code (KRB5_CALLCONV *get_next)
586                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
587                 krb5_cc_cursor  *, krb5_creds  *));
588         krb5_error_code (KRB5_CALLCONV *end_get)
589                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor  *));
590         krb5_error_code (KRB5_CALLCONV *remove_cred)
591                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
592                 krb5_flags, krb5_creds  *));
593         krb5_error_code (KRB5_CALLCONV *set_flags)
594                 KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_flags));
595         } krb5_cc_ops;
596 #endif /* NO_DEF_KRB5_CCACHE */
597
598 krb5_error_code 
599 kssl_krb5_cc_get_principal
600     (krb5_context context, krb5_ccache cache,
601       krb5_principal *principal)
602         {
603         if ( p_krb5_cc_get_principal )
604                 return(p_krb5_cc_get_principal(context,cache,principal));
605         else
606                 return(krb5_x
607                         ((cache)->ops->get_princ,(context, cache, principal)));
608         }
609 #else
610 #endif  /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
611
612 char
613 *kstring(char *string)
614         {
615         static char     *null = "[NULL]";
616
617         return ((string == NULL)? null: string);
618         }
619
620 #define MAXKNUM 255
621 char
622 *knumber(int len, krb5_octet *contents)
623         {
624         static char     buf[MAXKNUM+1];
625         int             i;
626
627         BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
628
629         for (i=0; i < len  &&  MAXKNUM > strlen(buf)+3; i++)
630                 {
631                 BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
632                 }
633
634         return (buf);
635         }
636
637
638 /*      Given KRB5 enctype (basically DES or 3DES), return
639 */
640 EVP_CIPHER *
641 kssl_map_enc(krb5_enctype enctype)
642         {
643         switch (enctype)
644                 {
645         case ENCTYPE_DES_CBC_CRC:
646         case ENCTYPE_DES_CBC_MD4:
647         case ENCTYPE_DES_CBC_MD5:
648         case ENCTYPE_DES_CBC_RAW:
649 #if ! defined(KRB5_MIT_OLD11)
650         case ENCTYPE_DES_HMAC_SHA1:
651 #endif
652                                 return (EVP_CIPHER *) EVP_des_cbc();
653                                 break;
654         case ENCTYPE_DES3_CBC_SHA:
655         case ENCTYPE_DES3_CBC_RAW:
656 #if ! defined(KRB5_MIT_OLD11)
657         case ENCTYPE_DES3_CBC_SHA1:
658 #endif
659                                 return (EVP_CIPHER *) EVP_des_ede3_cbc();
660                                 break;
661         default:                return (EVP_CIPHER *) NULL;
662                                 break;
663                 }
664         }
665
666
667 /*      Return true:1 if p "looks like" the start of the real authenticator
668 **      described in kssl_skip_confound() below.  The ASN.1 pattern is
669 **      "62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
670 **      xx and yy are possibly multi-byte length fields.
671 */
672 int     kssl_test_confound(unsigned char *p)
673         {
674         int     len = 2;
675         int     xx = 0, yy = 0;
676
677         if (*p++ != 0x62)  return 0;
678         if (*p > 0x82)  return 0;
679         switch(*p)  {
680                 case 0x82:  p++;          xx = (*p++ << 8);  xx += *p++;  break;
681                 case 0x81:  p++;          xx =  *p++;  break;
682                 case 0x80:  return 0;
683                 default:    xx = *p++;  break;
684                 }
685         if (*p++ != 0x30)  return 0;
686         if (*p > 0x82)  return 0;
687         switch(*p)  {
688                 case 0x82:  p++; len+=2;  yy = (*p++ << 8);  yy += *p++;  break;
689                 case 0x81:  p++; len++;   yy =  *p++;  break;
690                 case 0x80:  return 0;
691                 default:    yy = *p++;  break;
692                 }
693
694         return (xx - len == yy)? 1: 0;
695         }
696
697 /*      Allocate, fill, and return cksumlens array of checksum lengths.
698 **      This array holds just the unique elements from the krb5_cksumarray[].
699 **      array[n] == 0 signals end of data.
700 */
701 int     *populate_cksumlens(void)
702         {
703         int             i, j, n = krb5_max_cksum+1;
704         static int      *cklens = NULL;
705
706 #ifdef KRB5CHECKAUTH
707         if (!cklens && !(cklens = (int *) calloc(sizeof(int), n)))  return NULL;
708
709         for (i=0; i < krb5_max_cksum; i++)  {
710                 if (!krb5_cksumarray[i])  continue;     /*  array has holes  */
711                 for (j=0; j < krb5_max_cksum; j++)  {
712                         if (cklens[j] == 0)  {
713                                 cklens[j] = krb5_cksumarray[i]->checksum_length;
714                                 break;          /*  krb5 elem was new: add   */
715                                 }
716                         if (cklens[j] == krb5_cksumarray[i]->checksum_length)  {
717                                 break;          /*  ignore duplicate elements */
718                                 }
719                         }
720                 }
721 #endif  /* KRB5CHECKAUTH */
722
723         return cklens;
724         }
725
726 /*      Return pointer to start of real authenticator within authenticator, or
727 **      return NULL on error.
728 **      Decrypted authenticator looks like this:
729 **              [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
730 **      This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
731 **      krb5_auth_con_getcksumtype() function advertised in its krb5.h.
732 */
733 unsigned char   *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
734         {
735         int             i, cklen, conlen;
736         static int      *cksumlens = NULL;
737         unsigned char   *test_auth;
738
739         conlen = (etype)? 8: 0;
740
741         if (!cksumlens  &&  !(cksumlens = populate_cksumlens()))  return NULL;
742         for (i=0; (cklen = cksumlens[i]) != 0; i++)
743                 {
744                 test_auth = a + conlen + cklen;
745                 if (kssl_test_confound(test_auth))  return test_auth;
746                 }
747
748         return NULL;
749         }
750
751
752 /*      Set kssl_err error info when reason text is a simple string
753 **              kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
754 */
755 void
756 kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
757         {
758         if (kssl_err == NULL)  return;
759
760         kssl_err->reason = reason;
761         BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
762         return;
763         }
764
765
766 /*      Display contents of krb5_data struct, for debugging
767 */
768 void
769 print_krb5_data(char *label, krb5_data *kdata)
770         {
771         int     i;
772
773         printf("%s[%d] ", label, kdata->length);
774         for (i=0; i < kdata->length; i++)
775                 {
776                 if (0 &&  isprint((int) kdata->data[i]))
777                         printf( "%c ",  kdata->data[i]);
778                 else
779                         printf( "%02x ", (unsigned char) kdata->data[i]);
780                 }
781         printf("\n");
782         }
783
784
785 /*      Display contents of krb5_authdata struct, for debugging
786 */
787 void
788 print_krb5_authdata(char *label, krb5_authdata **adata)
789         {
790         if (adata == NULL)
791                 {
792                 printf("%s, authdata==0\n", label);
793                 return;
794                 }
795         printf("%s [%p]\n", label, adata);
796 #if 0
797         {
798         int     i;
799         printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
800         for (i=0; i < adata->length; i++)
801                 {
802                 printf((isprint(adata->contents[i]))? "%c ": "%02x",
803                         adata->contents[i]);
804                 }
805         printf("\n");
806         }
807 #endif
808         }
809
810
811 /*      Display contents of krb5_keyblock struct, for debugging
812 */
813 void
814 print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
815         {
816         int     i;
817
818         if (keyblk == NULL)
819                 {
820                 printf("%s, keyblk==0\n", label);
821                 return;
822                 }
823 #ifdef KRB5_HEIMDAL
824         printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
825                                            keyblk->keyvalue->length);
826         for (i=0; i < keyblk->keyvalue->length; i++)
827                 {
828                 printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
829                 }
830         printf("\n");
831 #else
832         printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
833         for (i=0; i < keyblk->length; i++)
834                 {
835                 printf("%02x",keyblk->contents[i]);
836                 }
837         printf("\n");
838 #endif
839         }
840
841
842 /*      Display contents of krb5_principal_data struct, for debugging
843 **      (krb5_principal is typedef'd == krb5_principal_data *)
844 */
845 void
846 print_krb5_princ(char *label, krb5_principal_data *princ)
847         {
848         int     i, j;
849
850         printf("%s principal Realm: ", label);
851         if (princ == NULL)  return;
852         for (i=0; i < princ->realm.length; i++)  putchar(princ->realm.data[i]);
853         printf(" (nametype %d) has %d strings:\n", princ->type,princ->length);
854         for (i=0; i < princ->length; i++)
855                 {
856                 printf("\t%d [%d]: ", i, princ->data[i].length);
857                 for (j=0; j < princ->data[i].length; j++)  {
858                         putchar(princ->data[i].data[j]);
859                         }
860                 printf("\n");
861                 }
862         return;
863         }
864
865
866 /*      Given krb5 service (typically "kssl") and hostname in kssl_ctx,
867 **      Return encrypted Kerberos ticket for service @ hostname.
868 **      If authenp is non-NULL, also return encrypted authenticator,
869 **      whose data should be freed by caller.
870 **      (Originally was: Create Kerberos AP_REQ message for SSL Client.)
871 **
872 **      19990628        VRS     Started; Returns Kerberos AP_REQ message.
873 **      20010409        VRS     Modified for RFC2712; Returns enc tkt.
874 **      20010606        VRS     May also return optional authenticator.
875 */
876 krb5_error_code
877 kssl_cget_tkt(  /* UPDATE */    KSSL_CTX *kssl_ctx,
878                 /* OUT    */    krb5_data **enc_ticketp,
879                 /* UPDATE */    krb5_data *authenp,
880                 /* OUT    */    KSSL_ERR *kssl_err)
881         {
882         krb5_error_code         krb5rc = KRB5KRB_ERR_GENERIC;
883         krb5_context            krb5context = NULL;
884         krb5_auth_context       krb5auth_context = NULL;
885         krb5_ccache             krb5ccdef = NULL;
886         krb5_creds              krb5creds, *krb5credsp = NULL;
887         krb5_data               krb5_app_req;
888
889         kssl_err_set(kssl_err, 0, "");
890         memset((char *)&krb5creds, 0, sizeof(krb5creds));
891
892         if (!kssl_ctx)
893                 {
894                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
895                         "No kssl_ctx defined.\n");
896                 goto err;
897                 }
898         else if (!kssl_ctx->service_host)
899                 {
900                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
901                         "kssl_ctx service_host undefined.\n");
902                 goto err;
903                 }
904
905         if ((krb5rc = krb5_init_context(&krb5context)) != 0)
906                 {
907                 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
908                         "krb5_init_context() fails: %d\n", krb5rc);
909                 kssl_err->reason = SSL_R_KRB5_C_INIT;
910                 goto err;
911                 }
912
913         if ((krb5rc = krb5_sname_to_principal(krb5context,
914                 kssl_ctx->service_host,
915                 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
916                 KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
917                 {
918                 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
919                         "krb5_sname_to_principal() fails for %s/%s\n",
920                         kssl_ctx->service_host,
921                         (kssl_ctx->service_name)? kssl_ctx->service_name:
922                                                   KRB5SVC);
923                 kssl_err->reason = SSL_R_KRB5_C_INIT;
924                 goto err;
925                 }
926
927         if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
928                 {
929                 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
930                         "krb5_cc_default fails.\n");
931                 goto err;
932                 }
933
934         if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
935                 &krb5creds.client)) != 0)
936                 {
937                 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
938                         "krb5_cc_get_principal() fails.\n");
939                 goto err;
940                 }
941
942         if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
943                 &krb5creds, &krb5credsp)) != 0)
944                 {
945                 kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
946                         "krb5_get_credentials() fails.\n");
947                 goto err;
948                 }
949
950         *enc_ticketp = &krb5credsp->ticket;
951 #ifdef KRB5_HEIMDAL
952         kssl_ctx->enctype = krb5credsp->session.keytype;
953 #else
954         kssl_ctx->enctype = krb5credsp->keyblock.enctype;
955 #endif
956
957         krb5rc = KRB5KRB_ERR_GENERIC;
958         /*      caller should free data of krb5_app_req  */
959         /*  20010406 VRS deleted for real KerberosWrapper
960         **  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
961         */
962         krb5_app_req.length = 0;
963         if (authenp)
964                 {
965                 krb5_data       krb5in_data;
966                 unsigned char   *p;
967                 long            arlen;
968                 KRB5_APREQBODY  *ap_req;
969
970                 authenp->length = 0;
971                 krb5in_data.data = NULL;
972                 krb5in_data.length = 0;
973                 if ((krb5rc = krb5_mk_req_extended(krb5context,
974                         &krb5auth_context, 0, &krb5in_data, krb5credsp,
975                         &krb5_app_req)) != 0)
976                         {
977                         kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
978                                 "krb5_mk_req_extended() fails.\n");
979                         goto err;
980                         }
981
982                 arlen = krb5_app_req.length;
983                 p = krb5_app_req.data;
984                 ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
985                 if (ap_req)
986                         {
987                         authenp->length = i2d_KRB5_ENCDATA(
988                                         ap_req->authenticator, NULL);
989                         if (authenp->length  && 
990                                 (authenp->data = malloc(authenp->length)))
991                                 {
992                                 unsigned char   *p = authenp->data;
993                                 authenp->length = i2d_KRB5_ENCDATA(
994                                                 ap_req->authenticator, &p);
995                                 }
996                         }
997
998                 if (ap_req)  KRB5_APREQ_free((KRB5_APREQ *) ap_req);
999                 if (krb5_app_req.length)  krb5_xfree(krb5_app_req.data);
1000                 }
1001 #ifdef KRB5_HEIMDAL
1002         if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
1003                 {
1004                 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1005                         "kssl_ctx_setkey() fails.\n");
1006                 }
1007 #else
1008         if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
1009                 {
1010                 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1011                         "kssl_ctx_setkey() fails.\n");
1012                 }
1013 #endif
1014         else    krb5rc = 0;
1015
1016  err:
1017 #ifdef KSSL_DEBUG
1018         kssl_ctx_show(kssl_ctx);
1019 #endif  /* KSSL_DEBUG */
1020
1021         if (krb5creds.client)   krb5_free_principal(krb5context,
1022                                                         krb5creds.client);
1023         if (krb5creds.server)   krb5_free_principal(krb5context,
1024                                                         krb5creds.server);
1025         if (krb5auth_context)   krb5_auth_con_free(krb5context,
1026                                                         krb5auth_context);
1027         if (krb5context)        krb5_free_context(krb5context);
1028         return (krb5rc);
1029         }
1030
1031
1032 /*  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
1033 **  Return Kerberos error code and kssl_err struct on error.
1034 **  Allocates krb5_ticket and krb5_principal; caller should free these.
1035 **
1036 **      20010410        VRS     Implemented krb5_decode_ticket() as
1037 **                              old_krb5_decode_ticket(). Missing from MIT1.0.6.
1038 **      20010615        VRS     Re-cast as openssl/asn1 d2i_*() functions.
1039 **                              Re-used some of the old krb5_decode_ticket()
1040 **                              code here.  This tkt should alloc/free just
1041 **                              like the real thing.
1042 */
1043 krb5_error_code
1044 kssl_TKT2tkt(   /* IN     */    krb5_context    krb5context,
1045                 /* IN     */    KRB5_TKTBODY    *asn1ticket,
1046                 /* OUT    */    krb5_ticket     **krb5ticket,
1047                 /* OUT    */    KSSL_ERR *kssl_err  )
1048         {
1049         krb5_error_code                 krb5rc = KRB5KRB_ERR_GENERIC;
1050         krb5_ticket                     *new5ticket = NULL;
1051         ASN1_GENERALSTRING              *gstr_svc, *gstr_host;
1052
1053         *krb5ticket = NULL;
1054
1055         if (asn1ticket == NULL  ||  asn1ticket->realm == NULL  ||
1056                 asn1ticket->sname == NULL  || 
1057                 asn1ticket->sname->namestring == NULL  ||
1058                 asn1ticket->sname->namestring->num < 2)
1059                 {
1060                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1061                         "Null field in asn1ticket.\n");
1062                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1063                 return KRB5KRB_ERR_GENERIC;
1064                 }
1065
1066         if ((new5ticket = (krb5_ticket *) calloc(1, sizeof(krb5_ticket)))==NULL)
1067                 {
1068                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1069                         "Unable to allocate new krb5_ticket.\n");
1070                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1071                 return ENOMEM;          /*  or  KRB5KRB_ERR_GENERIC;    */
1072                 }
1073
1074         gstr_svc  = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[0];
1075         gstr_host = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[1];
1076
1077         if ((krb5rc = kssl_build_principal_2(krb5context,
1078                         &new5ticket->server,
1079                         asn1ticket->realm->length, asn1ticket->realm->data,
1080                         gstr_svc->length,  gstr_svc->data,
1081                         gstr_host->length, gstr_host->data)) != 0)
1082                 {
1083                 free(new5ticket);
1084                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1085                         "Error building ticket server principal.\n");
1086                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1087                 return krb5rc;          /*  or  KRB5KRB_ERR_GENERIC;    */
1088                 }
1089
1090         krb5_princ_type(krb5context, new5ticket->server) =
1091                         asn1ticket->sname->nametype->data[0];
1092         new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0];
1093         new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0];
1094         new5ticket->enc_part.ciphertext.length =
1095                         asn1ticket->encdata->cipher->length;
1096         if ((new5ticket->enc_part.ciphertext.data =
1097                 calloc(1, asn1ticket->encdata->cipher->length)) == NULL)
1098                 {
1099                 free(new5ticket);
1100                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1101                         "Error allocating cipher in krb5ticket.\n");
1102                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1103                 return KRB5KRB_ERR_GENERIC;
1104                 }
1105         else
1106                 {
1107                 memcpy(new5ticket->enc_part.ciphertext.data,
1108                         asn1ticket->encdata->cipher->data,
1109                         asn1ticket->encdata->cipher->length);
1110                 }
1111
1112         *krb5ticket = new5ticket;
1113         return 0;
1114         }
1115
1116
1117 /*      Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
1118 **              and krb5 AP_REQ message & message length,
1119 **      Return Kerberos session key and client principle
1120 **              to SSL Server in KSSL_CTX *kssl_ctx.
1121 **
1122 **      19990702        VRS     Started.
1123 */
1124 krb5_error_code
1125 kssl_sget_tkt(  /* UPDATE */    KSSL_CTX                *kssl_ctx,
1126                 /* IN     */    krb5_data               *indata,
1127                 /* OUT    */    krb5_ticket_times       *ttimes,
1128                 /* OUT    */    KSSL_ERR                *kssl_err  )
1129         {
1130         krb5_error_code                 krb5rc = KRB5KRB_ERR_GENERIC;
1131         static krb5_context             krb5context = NULL;
1132         static krb5_auth_context        krb5auth_context = NULL;
1133         krb5_ticket                     *krb5ticket = NULL;
1134         KRB5_TKTBODY                    *asn1ticket = NULL;
1135         unsigned char                   *p;
1136         krb5_keytab                     krb5keytab = NULL;
1137         krb5_keytab_entry               kt_entry;
1138         krb5_principal                  krb5server;
1139
1140         kssl_err_set(kssl_err, 0, "");
1141
1142         if (!kssl_ctx)
1143                 {
1144                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1145                                         "No kssl_ctx defined.\n");
1146                 goto err;
1147                 }
1148
1149 #ifdef KSSL_DEBUG
1150         printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
1151 #endif  /* KSSL_DEBUG */
1152
1153         if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
1154                 {
1155                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1156                         "krb5_init_context() fails.\n");
1157                 goto err;
1158                 }
1159         if (krb5auth_context  &&
1160                 (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
1161                 {
1162                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1163                         "krb5_auth_con_free() fails.\n");
1164                 goto err;
1165                 }
1166         else  krb5auth_context = NULL;
1167         if (!krb5auth_context  &&
1168                 (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
1169                 {
1170                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1171                         "krb5_auth_con_init() fails.\n");
1172                 goto err;
1173                 }
1174
1175         if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
1176                 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1177                 KRB5_NT_SRV_HST, &krb5server)) != 0)
1178                 {
1179                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1180                         "krb5_sname_to_principal() fails.\n");
1181                 goto err;
1182                 }
1183
1184         /*      kssl_ctx->keytab_file == NULL ==> use Kerberos default
1185         */
1186         if (kssl_ctx->keytab_file)
1187                 {
1188                 krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1189                         &krb5keytab);
1190                 if (krb5rc)
1191                         {
1192                         kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1193                                 "krb5_kt_resolve() fails.\n");
1194                         goto err;
1195                         }
1196                 }
1197         else
1198                 {
1199                 krb5rc = krb5_kt_default(krb5context,&krb5keytab);
1200                 if (krb5rc)
1201                         {
1202                         kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, 
1203                                 "krb5_kt_default() fails.\n");
1204                         goto err;
1205                         }
1206                 }
1207
1208         /*      Actual Kerberos5 krb5_recvauth() has initial conversation here
1209         **      o       check KRB5_SENDAUTH_BADAUTHVERS
1210         **              unless KRB5_RECVAUTH_SKIP_VERSION
1211         **      o       check KRB5_SENDAUTH_BADAPPLVERS
1212         **      o       send "0" msg if all OK
1213         */
1214
1215         /*  20010411 was using AP_REQ instead of true KerberosWrapper
1216         **
1217         **  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
1218         **                      &krb5in_data, krb5server, krb5keytab,
1219         **                      &ap_option, &krb5ticket)) != 0)  { Error }
1220         */
1221
1222         p = indata->data;
1223         if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
1224                                                 (long) indata->length)) == NULL)
1225                 {
1226                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1227                         "d2i_KRB5_TICKET() ASN.1 decode failure.\n");
1228                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1229                 goto err;
1230                 }
1231         
1232         /* Was:  krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
1233         if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
1234                                         kssl_err)) != 0)
1235                 {
1236                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1237                         "Error converting ASN.1 ticket to krb5_ticket.\n");
1238                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1239                 goto err;
1240                 }
1241
1242         if (! krb5_principal_compare(krb5context, krb5server,
1243                                                   krb5ticket->server))  {
1244                 krb5rc = KRB5_PRINC_NOMATCH;
1245                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1246                         "server principal != ticket principal\n");
1247                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1248                 goto err;
1249                 }
1250         if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1251                         krb5ticket->server, krb5ticket->enc_part.kvno,
1252                         krb5ticket->enc_part.enctype, &kt_entry)) != 0)  {
1253                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1254                         "krb5_kt_get_entry() fails with %x.\n", krb5rc);
1255                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1256                 goto err;
1257                 }
1258         if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
1259                         krb5ticket)) != 0)  {
1260                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1261                         "krb5_decrypt_tkt_part() failed.\n");
1262                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1263                 goto err;
1264                 }
1265         else  {
1266                 krb5_kt_free_entry(krb5context, &kt_entry);
1267 #ifdef KSSL_DEBUG
1268                 {
1269                 int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
1270                 printf("Decrypted ticket fields:\n");
1271                 printf("\tflags: %X, transit-type: %X",
1272                         krb5ticket->enc_part2->flags,
1273                         krb5ticket->enc_part2->transited.tr_type);
1274                 print_krb5_data("\ttransit-data: ",
1275                         &(krb5ticket->enc_part2->transited.tr_contents));
1276                 printf("\tcaddrs: %p, authdata: %p\n",
1277                         krb5ticket->enc_part2->caddrs,
1278                         krb5ticket->enc_part2->authorization_data);
1279                 printf("\tcaddrs:\n");
1280                 for (i=0; paddr[i] != NULL; i++)
1281                         {  krb5_data d;
1282                         d.length=paddr[i]->length; d.data=paddr[i]->contents;
1283                         print_krb5_data("\t\tIP: ", &d);
1284                         }
1285                 printf("\tstart/auth/end times: %d / %d / %d\n",
1286                         krb5ticket->enc_part2->times.starttime,
1287                         krb5ticket->enc_part2->times.authtime,
1288                         krb5ticket->enc_part2->times.endtime);
1289                 }
1290 #endif  /* KSSL_DEBUG */
1291                 }
1292
1293         krb5rc = KRB5_NO_TKT_SUPPLIED;
1294         if (!krb5ticket  ||     !krb5ticket->enc_part2  ||
1295                 !krb5ticket->enc_part2->client  ||
1296                 !krb5ticket->enc_part2->client->data  ||
1297                 !krb5ticket->enc_part2->session)
1298                 {
1299                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1300                         "bad ticket from krb5_rd_req.\n");
1301                 }
1302         else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
1303                 &krb5ticket->enc_part2->client->realm,
1304                 krb5ticket->enc_part2->client->data))
1305                 {
1306                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1307                         "kssl_ctx_setprinc() fails.\n");
1308                 }
1309         else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
1310                 {
1311                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1312                         "kssl_ctx_setkey() fails.\n");
1313                 }
1314         else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID)
1315                 {
1316                 krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
1317                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1318                         "invalid ticket from krb5_rd_req.\n");
1319                 }
1320         else    krb5rc = 0;
1321
1322         kssl_ctx->enctype       = krb5ticket->enc_part.enctype;
1323         ttimes->authtime        = krb5ticket->enc_part2->times.authtime;
1324         ttimes->starttime       = krb5ticket->enc_part2->times.starttime;
1325         ttimes->endtime         = krb5ticket->enc_part2->times.endtime;
1326         ttimes->renew_till      = krb5ticket->enc_part2->times.renew_till;
1327
1328  err:
1329 #ifdef KSSL_DEBUG
1330         kssl_ctx_show(kssl_ctx);
1331 #endif  /* KSSL_DEBUG */
1332
1333         if (asn1ticket)         KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
1334         if (krb5keytab)         krb5_kt_close(krb5context, krb5keytab);
1335         if (krb5ticket)         krb5_free_ticket(krb5context, krb5ticket);
1336         if (krb5server)         krb5_free_principal(krb5context, krb5server);
1337         return (krb5rc);
1338         }
1339
1340
1341 /*      Allocate & return a new kssl_ctx struct.
1342 */
1343 KSSL_CTX        *
1344 kssl_ctx_new(void)
1345         {
1346         return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
1347         }
1348
1349
1350 /*      Frees a kssl_ctx struct and any allocated memory it holds.
1351 **      Returns NULL.
1352 */
1353 KSSL_CTX        *
1354 kssl_ctx_free(KSSL_CTX *kssl_ctx)
1355         {
1356         if (kssl_ctx == NULL)  return kssl_ctx;
1357
1358         if (kssl_ctx->key)              memset(kssl_ctx->key, 0,
1359                                                               kssl_ctx->length);
1360         if (kssl_ctx->key)              free(kssl_ctx->key);
1361         if (kssl_ctx->client_princ)     free(kssl_ctx->client_princ);
1362         if (kssl_ctx->service_host)     free(kssl_ctx->service_host);
1363         if (kssl_ctx->service_name)     free(kssl_ctx->service_name);
1364         if (kssl_ctx->keytab_file)      free(kssl_ctx->keytab_file);
1365
1366         free(kssl_ctx);
1367         return (KSSL_CTX *) NULL;
1368         }
1369
1370
1371 /*      Given a (krb5_data *) entity (and optional realm),
1372 **      set the plain (char *) client_princ or service_host member
1373 **      of the kssl_ctx struct.
1374 */
1375 krb5_error_code
1376 kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
1377         krb5_data *realm, krb5_data *entity)
1378         {
1379         char    **princ;
1380         int     length;
1381
1382         if (kssl_ctx == NULL  ||  entity == NULL)  return KSSL_CTX_ERR;
1383
1384         switch (which)
1385                 {
1386         case KSSL_CLIENT:       princ = &kssl_ctx->client_princ;        break;
1387         case KSSL_SERVER:       princ = &kssl_ctx->service_host;        break;
1388         default:                return KSSL_CTX_ERR;                    break;
1389                 }
1390         if (*princ)  free(*princ);
1391
1392         length = entity->length + ((realm)? realm->length + 2: 1);
1393         if ((*princ = calloc(1, length)) == NULL)
1394                 return KSSL_CTX_ERR;
1395         else
1396                 {
1397                 strncpy(*princ, entity->data, entity->length);
1398                 if (realm)
1399                         {
1400                         strcat (*princ, "@");
1401                         (void) strncat(*princ, realm->data, realm->length);
1402                         }
1403                 }
1404
1405         return KSSL_CTX_OK;
1406         }
1407
1408
1409 /*      Set one of the plain (char *) string members of the kssl_ctx struct.
1410 **      Default values should be:
1411 **              which == KSSL_SERVICE   =>      "khost" (KRB5SVC)
1412 **              which == KSSL_KEYTAB    =>      "/etc/krb5.keytab" (KRB5KEYTAB)
1413 */
1414 krb5_error_code
1415 kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
1416         {
1417         char    **string;
1418
1419         if (!kssl_ctx)  return KSSL_CTX_ERR;
1420
1421         switch (which)
1422                 {
1423         case KSSL_SERVICE:      string = &kssl_ctx->service_name;       break;
1424         case KSSL_SERVER:       string = &kssl_ctx->service_host;       break;
1425         case KSSL_CLIENT:       string = &kssl_ctx->client_princ;       break;
1426         case KSSL_KEYTAB:       string = &kssl_ctx->keytab_file;        break;
1427         default:                return KSSL_CTX_ERR;                    break;
1428                 }
1429         if (*string)  free(*string);
1430
1431         if (!text)
1432                 {
1433                 *string = '\0';
1434                 return KSSL_CTX_OK;
1435                 }
1436
1437         if ((*string = calloc(1, strlen(text) + 1)) == NULL)
1438                 return KSSL_CTX_ERR;
1439         else
1440                 strcpy(*string, text);
1441
1442         return KSSL_CTX_OK;
1443         }
1444
1445
1446 /*      Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
1447 **      struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
1448 */
1449 krb5_error_code
1450 kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
1451         {
1452         int             length;
1453         krb5_enctype    enctype;
1454         krb5_octet FAR  *contents = NULL;
1455
1456         if (!kssl_ctx)  return KSSL_CTX_ERR;
1457
1458         if (kssl_ctx->key)
1459                 {
1460                 memset(kssl_ctx->key, 0, kssl_ctx->length);
1461                 free(kssl_ctx->key);
1462                 }
1463
1464         if (session)
1465                 {
1466
1467 #ifdef KRB5_HEIMDAL
1468                 length = session->keyvalue->length;
1469                 enctype = session->keytype;
1470                 contents = session->keyvalue->contents;
1471 #else
1472                 length = session->length;
1473                 enctype = session->enctype;
1474                 contents = session->contents;
1475 #endif
1476                 kssl_ctx->enctype = enctype;
1477                 kssl_ctx->length  = length;
1478                 }
1479         else
1480                 {
1481                 kssl_ctx->enctype = ENCTYPE_UNKNOWN;
1482                 kssl_ctx->length  = 0;
1483                 return KSSL_CTX_OK;
1484                 }
1485
1486         if ((kssl_ctx->key =
1487                 (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
1488                 {
1489                 kssl_ctx->length  = 0;
1490                 return KSSL_CTX_ERR;
1491                 }
1492         else
1493                 memcpy(kssl_ctx->key, contents, length);
1494
1495         return KSSL_CTX_OK;
1496         }
1497
1498
1499 /*      Display contents of kssl_ctx struct
1500 */
1501 void
1502 kssl_ctx_show(KSSL_CTX *kssl_ctx)
1503         {
1504         int     i;
1505
1506         printf("kssl_ctx: ");
1507         if (kssl_ctx == NULL)
1508                 {
1509                 printf("NULL\n");
1510                 return;
1511                 }
1512         else
1513                 printf("%p\n", kssl_ctx);
1514
1515         printf("\tservice:\t%s\n",
1516                 (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1517         printf("\tclient:\t%s\n",
1518                 (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1519         printf("\tserver:\t%s\n",
1520                 (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1521         printf("\tkeytab:\t%s\n",
1522                 (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1523         printf("\tkey [%d:%d]:\t",
1524                 kssl_ctx->enctype, kssl_ctx->length);
1525
1526         for (i=0; i < kssl_ctx->length  &&  kssl_ctx->key; i++)
1527                 {
1528                 printf("%02x", kssl_ctx->key[i]);
1529                 }
1530         printf("\n");
1531         return;
1532         }
1533
1534 void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1535         {
1536 #ifdef KRB5_HEIMDAL
1537         data->length = 0;
1538         free(data->if (data->data) data);
1539 #elif defined(KRB5_MIT_OLD11)
1540         if (data->data)  {
1541                 krb5_xfree(data->data);
1542                 data->data = 0;
1543                 }
1544 #else
1545         krb5_free_data_contents(NULL, data);
1546 #endif
1547         }
1548
1549
1550 /*  Helper function for kssl_validate_times().
1551 **  We need context->clockskew, but krb5_context is an opaque struct.
1552 **  So we try to sneek the clockskew out through the replay cache.
1553 **      If that fails just return a likely default (300 seconds).
1554 */
1555 krb5_deltat     get_rc_clockskew(krb5_context context)
1556         {
1557         krb5_rcache     rc;
1558         krb5_deltat     clockskew;
1559
1560         if (krb5_rc_default(context, &rc))  return KSSL_CLOCKSKEW;
1561         if (krb5_rc_initialize(context, rc, 0))  return KSSL_CLOCKSKEW;
1562         if (krb5_rc_get_lifespan(context, rc, &clockskew))  {
1563                 clockskew = KSSL_CLOCKSKEW;
1564                 }
1565         (void) krb5_rc_destroy(context, rc);
1566         return clockskew;
1567         }
1568
1569
1570 /*  kssl_validate_times() combines (and more importantly exposes)
1571 **  the MIT KRB5 internal function krb5_validate_times() and the
1572 **  in_clock_skew() macro.  The authenticator client time is checked
1573 **  to be within clockskew secs of the current time and the current
1574 **  time is checked to be within the ticket start and expire times.
1575 **  Either check may be omitted by supplying a NULL value.
1576 **  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
1577 **  See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
1578 **  20010420 VRS
1579 */
1580 krb5_error_code  kssl_validate_times(   krb5_timestamp atime,
1581                                         krb5_ticket_times *ttimes)
1582         {
1583         krb5_deltat     skew;
1584         krb5_timestamp  start, now;
1585         krb5_error_code rc;
1586         krb5_context    context;
1587
1588         if ((rc = krb5_init_context(&context)))  return SSL_R_KRB5_S_BAD_TICKET;
1589         skew = get_rc_clockskew(context); 
1590         if ((rc = krb5_timeofday(context,&now))) return SSL_R_KRB5_S_BAD_TICKET;
1591         krb5_free_context(context);
1592
1593         if (atime  &&  labs(atime - now) >= skew)  return SSL_R_KRB5_S_TKT_SKEW;
1594
1595         if (! ttimes)  return 0;
1596
1597         start = (ttimes->starttime != 0)? ttimes->starttime: ttimes->authtime;
1598         if (start - now > skew)  return SSL_R_KRB5_S_TKT_NYV;
1599         if ((now - ttimes->endtime) > skew)  return SSL_R_KRB5_S_TKT_EXPIRED;
1600
1601 #ifdef KSSL_DEBUG
1602         printf("kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
1603                 start, atime, now, skew, ttimes->endtime);
1604 #endif  /* KSSL_DEBUG */
1605
1606         return 0;
1607         }
1608
1609
1610 /*  Decode and decrypt given DER-encoded authenticator, then pass
1611 **  authenticator ctime back in *atimep (or 0 if time unavailable).
1612 **  Returns krb5_error_code and kssl_err on error.  A NULL 
1613 **  authenticator (authentp->length == 0) is not considered an error.
1614 **  Note that kssl_check_authent() makes use of the KRB5 session key;
1615 **  you must call kssl_sget_tkt() to get the key before calling this routine.
1616 */
1617 krb5_error_code  kssl_check_authent(
1618                         /* IN     */    KSSL_CTX        *kssl_ctx,
1619                         /* IN     */    krb5_data       *authentp,
1620                         /* OUT    */    krb5_timestamp  *atimep,
1621                         /* OUT    */    KSSL_ERR        *kssl_err  )
1622         {
1623         krb5_error_code         krb5rc = 0;
1624         KRB5_ENCDATA            *dec_authent = NULL;
1625         KRB5_AUTHENTBODY        *auth = NULL;
1626         krb5_enctype            enctype;
1627         EVP_CIPHER_CTX          ciph_ctx;
1628         EVP_CIPHER              *enc = NULL;
1629         unsigned char           iv[EVP_MAX_IV_LENGTH];
1630         unsigned char           *p, *unenc_authent, *tbuf = NULL;
1631         int                     padl, outl, unencbufsize;
1632         struct tm               tm_time, *tm_l, *tm_g;
1633         time_t                  now, tl, tg, tz_offset;
1634
1635         *atimep = 0;
1636         kssl_err_set(kssl_err, 0, "");
1637
1638 #ifndef KRB5CHECKAUTH
1639         authentp = NULL;
1640 #else
1641 #if     KRB5CHECKAUTH == 0
1642         authentp = NULL;
1643 #endif
1644 #endif  /* KRB5CHECKAUTH */
1645
1646         if (authentp == NULL  ||  authentp->length == 0)  return 0;
1647
1648 #ifdef KSSL_DEBUG
1649         printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
1650         p = authentp->data; 
1651         for (padl=0; padl < authentp->length; padl++)  printf("%02x ",p[padl]);
1652         printf("\n");
1653 #endif  /* KSSL_DEBUG */
1654
1655         unencbufsize = 2 * authentp->length;
1656         if ((unenc_authent = calloc(1, unencbufsize)) == NULL)
1657                 {
1658                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1659                         "Unable to allocate authenticator buffer.\n");
1660                 krb5rc = KRB5KRB_ERR_GENERIC;
1661                 goto err;
1662                 }
1663
1664         p = authentp->data;
1665         if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
1666                                         (long) authentp->length)) == NULL) 
1667                 {
1668                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1669                         "Error decoding authenticator.\n");
1670                 krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1671                 goto err;
1672                 }
1673
1674         enctype = dec_authent->etype->data[0];  /* should = kssl_ctx->enctype */
1675         enc = kssl_map_enc(enctype);
1676         memset(iv, 0, EVP_MAX_IV_LENGTH);       /* per RFC 1510 */
1677
1678         EVP_DecryptInit(&ciph_ctx, enc, kssl_ctx->key, iv);
1679         EVP_DecryptUpdate(&ciph_ctx, unenc_authent, &outl,
1680                         dec_authent->cipher->data, dec_authent->cipher->length);
1681         if (outl > unencbufsize)
1682                 {
1683                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1684                         "Buffer overflow decrypting authenticator.\n");
1685                 krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1686                 goto err;
1687                 }
1688         EVP_DecryptFinal(&ciph_ctx, &(unenc_authent[outl]), &padl);
1689         outl += padl;
1690         if (outl > unencbufsize)
1691                 {
1692                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1693                         "Buffer overflow decrypting authenticator.\n");
1694                 krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1695                 goto err;
1696                 }
1697         EVP_CIPHER_CTX_cleanup(&ciph_ctx);
1698
1699 #ifdef KSSL_DEBUG
1700         printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl);
1701         for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]);
1702         printf("\n");
1703 #endif  /* KSSL_DEBUG */
1704
1705         if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL)
1706                 {
1707                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1708                         "confounded by authenticator.\n");
1709                 krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1710                 goto err;
1711                 }
1712         outl -= p - unenc_authent;
1713
1714         if ((auth = (KRB5_AUTHENTBODY *) d2i_KRB5_AUTHENT(NULL, &p,
1715                                                           (long) outl))==NULL)
1716                 {
1717                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1718                         "Error decoding authenticator body.\n");
1719                 krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1720                 goto err;
1721                 }
1722         if ((tbuf = calloc(1, auth->ctime->length + 1)) == NULL)
1723                 {
1724                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1725                         "Unable to allocate atime buffer.\n");
1726                 krb5rc = KRB5KRB_ERR_GENERIC;
1727                 goto err;
1728                 }
1729         else    strncpy(tbuf, auth->ctime->data, auth->ctime->length);
1730         
1731         if (strptime(tbuf, "%Y%m%d%H%M%S", &tm_time) != NULL)
1732                 {
1733                 now  = time(&now);
1734                 tm_l = localtime(&now);         tl = mktime(tm_l);
1735                 tm_g = gmtime(&now);            tg = mktime(tm_g);
1736                 tz_offset = tg - tl;
1737
1738                 *atimep = mktime(&tm_time) - tz_offset;
1739                 }
1740
1741 #ifdef KSSL_DEBUG
1742         printf("kssl_check_authent: client time %s = %d\n", tbuf, *atimep);
1743 #endif  /* KSSL_DEBUG */
1744
1745  err:
1746         if (tbuf)               free(tbuf);
1747         if (auth)               KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
1748         if (dec_authent)        KRB5_ENCDATA_free(dec_authent);
1749         if (unenc_authent)      free(unenc_authent);
1750         return krb5rc;
1751         }
1752
1753
1754 /*  Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
1755 **  because I dont't know how to stub varargs.
1756 **  Returns krb5_error_code == ENOMEM on alloc error, otherwise
1757 **  passes back newly constructed principal, which should be freed by caller.
1758 */
1759 krb5_error_code  kssl_build_principal_2(
1760                         /* UPDATE */    krb5_context    context,
1761                         /* OUT    */    krb5_principal  *princ,
1762                         /* IN     */    int rlen,  const char *realm,
1763                         /* IN     */    int slen,  const char *svc,
1764                         /* IN     */    int hlen,  const char *host)
1765         {
1766         krb5_data               *p_data = NULL;
1767         krb5_principal          new_p = NULL;
1768         char                    *new_r = NULL;
1769
1770         if ((p_data = (krb5_data *) calloc(2, sizeof(krb5_data))) == NULL  ||
1771             (new_p = (krb5_principal) calloc(1, sizeof(krb5_principal_data)))
1772                         == NULL)  goto err;
1773         new_p->length = 2;
1774         new_p->data = p_data;
1775
1776         if ((new_r = calloc(1, rlen + 1)) == NULL)  goto err;
1777         memcpy(new_r, realm, rlen);
1778         krb5_princ_set_realm_length(context, new_p, rlen);
1779         krb5_princ_set_realm_data(context, new_p, new_r);
1780
1781         if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL)  goto err;
1782         memcpy(new_p->data[0].data, svc, slen);
1783         new_p->data[0].length = slen;
1784
1785         if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL)  goto err;
1786         memcpy(new_p->data[1].data, host, hlen);
1787         new_p->data[1].length = hlen;
1788         
1789         krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN;
1790         *princ = new_p;
1791         return 0;
1792
1793  err:
1794         if (new_p  &&  new_p[0].data)   free(new_p[0].data);
1795         if (new_p  &&  new_p[1].data)   free(new_p[1].data);
1796         if (new_p)      free(new_p);
1797         if (new_r)      free(new_r);
1798         return ENOMEM;
1799         }
1800
1801
1802 #else /* !OPENSSL_NO_KRB5 */
1803
1804 #if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
1805 static int dummy=(int)&dummy;
1806 #endif
1807
1808 #endif  /* !OPENSSL_NO_KRB5     */
1809