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