Fix an oversight - when checking a potential session ID for conflicts with
[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 */
63
64 #include <openssl/opensslconf.h>
65 #ifndef OPENSSL_NO_KRB5
66 #include <string.h>
67 #include <openssl/ssl.h>
68
69 /* 
70  * When OpenSSL is built on Windows, we do not want to require that
71  * the Kerberos DLLs be available in order for the OpenSSL DLLs to
72  * work.  Therefore, all Kerberos routines are loaded at run time
73  * and we do not link to a .LIB file.
74  */
75
76 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
77 /* 
78  * The purpose of the following pre-processor statements is to provide
79  * compatibility with different releases of MIT Kerberos for Windows.
80  * All versions up to 1.2 used macros.  But macros do not allow for
81  * a binary compatible interface for DLLs.  Therefore, all macros are
82  * being replaced by function calls.  The following code will allow
83  * an OpenSSL DLL built on Windows to work whether or not the macro
84  * or function form of the routines are utilized.
85  */
86 #ifdef  krb5_cc_get_principal
87 #define NO_DEF_KRB5_CCACHE
88 #undef  krb5_cc_get_principal
89 #endif
90 #define krb5_cc_get_principal    kssl_krb5_cc_get_principal
91
92 #define krb5_free_data_contents  kssl_krb5_free_data_contents   
93 #define krb5_free_context        kssl_krb5_free_context         
94 #define krb5_auth_con_free       kssl_krb5_auth_con_free        
95 #define krb5_free_principal      kssl_krb5_free_principal       
96 #define krb5_mk_req_extended     kssl_krb5_mk_req_extended      
97 #define krb5_get_credentials     kssl_krb5_get_credentials      
98 #define krb5_cc_default          kssl_krb5_cc_default           
99 #define krb5_sname_to_principal  kssl_krb5_sname_to_principal   
100 #define krb5_init_context        kssl_krb5_init_context         
101 #define krb5_free_ticket         kssl_krb5_free_ticket          
102 #define krb5_rd_req              kssl_krb5_rd_req               
103 #define krb5_kt_default          kssl_krb5_kt_default           
104 #define krb5_kt_resolve          kssl_krb5_kt_resolve           
105 #define krb5_auth_con_init       kssl_krb5_auth_con_init        
106
107 /* Prototypes for built in stubs */
108 void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
109 void kssl_krb5_free_principal(krb5_context, krb5_principal );
110 krb5_error_code kssl_krb5_kt_resolve(krb5_context,
111                                      krb5_const char *,
112                                      krb5_keytab *);
113 krb5_error_code kssl_krb5_kt_default(krb5_context,
114                                      krb5_keytab *);
115 krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
116 krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *, 
117                                  krb5_const krb5_data *,
118                                  krb5_const_principal, krb5_keytab, 
119                                  krb5_flags *,krb5_ticket **);
120 krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
121                                           krb5_auth_context  *,
122                                           krb5_const krb5_flags,
123                                           krb5_data  *,
124                                           krb5_creds  *,
125                                           krb5_data  * );
126 krb5_error_code kssl_krb5_init_context(krb5_context *);
127 void kssl_krb5_free_context(krb5_context);
128 krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache  *);
129 krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
130                                              krb5_const char  *,
131                                              krb5_const char  *,
132                                              krb5_int32,
133                                              krb5_principal  *);
134 krb5_error_code kssl_krb5_get_credentials(krb5_context,
135                                           krb5_const krb5_flags,
136                                           krb5_ccache,
137                                           krb5_creds  *,
138                                           krb5_creds  *  *);
139 krb5_error_code kssl_krb5_auth_con_init(krb5_context,
140                                         krb5_auth_context  *);
141 krb5_error_code kssl_krb5_cc_get_principal(krb5_context context, 
142                                            krb5_ccache cache,
143                                            krb5_principal *principal);
144 krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
145
146 /* Function pointers (almost all Kerberos functions are _stdcall) */
147 static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)=NULL;
148 static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )=NULL;
149 static krb5_error_code(_stdcall *p_krb5_kt_resolve)(krb5_context, krb5_const char *,
150                                                     krb5_keytab *)=NULL;
151 static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
152                                                      krb5_keytab *)=NULL;
153 static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context, 
154                                                       krb5_ticket *)=NULL;
155 static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context, 
156                                                  krb5_auth_context *, 
157                                                  krb5_const krb5_data *,
158                                                  krb5_const_principal, 
159                                                  krb5_keytab, krb5_flags *,
160                                                  krb5_ticket **)=NULL;
161 static krb5_error_code (_stdcall *p_krb5_mk_req_extended) (krb5_context,
162                                                            krb5_auth_context  *,
163                                                            krb5_const krb5_flags,
164                                                            krb5_data  *,
165                                                            krb5_creds  *,
166                                                            krb5_data  * )=NULL;
167 static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
168 static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
169 static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
170                                                      krb5_ccache  *)=NULL;
171 static krb5_error_code (_stdcall *p_krb5_sname_to_principal)(krb5_context,
172                                                              krb5_const char  *,
173                                                              krb5_const char  *,
174                                                              krb5_int32,
175                                                              krb5_principal  *)=NULL;
176 static krb5_error_code (_stdcall *p_krb5_get_credentials)(krb5_context,
177                                                           krb5_const krb5_flags,
178                                                           krb5_ccache,
179                                                           krb5_creds  *,
180                                                           krb5_creds  *  *)=NULL;
181 static krb5_error_code (_stdcall *p_krb5_auth_con_init)(krb5_context,
182                                                         krb5_auth_context  *)=NULL;
183 static krb5_error_code (_stdcall *p_krb5_cc_get_principal)(krb5_context context, 
184                                                            krb5_ccache cache,
185                                                            krb5_principal *principal)=NULL;
186 static krb5_error_code (_stdcall *p_krb5_auth_con_free)(krb5_context,
187                                                         krb5_auth_context)=NULL;
188 static int krb5_loaded = 0;     /* only attempt to initialize func ptrs once */
189
190 /* Function to Load the Kerberos 5 DLL and initialize function pointers */
191 void
192 load_krb5_dll(void)
193         {
194         HANDLE hKRB5_32;
195     
196         krb5_loaded++;
197         hKRB5_32 = LoadLibrary("KRB5_32");
198         if (!hKRB5_32)
199                 return;
200
201         (FARPROC) p_krb5_free_data_contents =
202                 GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
203         (FARPROC) p_krb5_free_context =
204                 GetProcAddress( hKRB5_32, "krb5_free_context" );
205         (FARPROC) p_krb5_auth_con_free =
206                 GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
207         (FARPROC) p_krb5_free_principal =
208                 GetProcAddress( hKRB5_32, "krb5_free_principal" );
209         (FARPROC) p_krb5_mk_req_extended =
210                 GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
211         (FARPROC) p_krb5_get_credentials =
212                 GetProcAddress( hKRB5_32, "krb5_get_credentials" );
213         (FARPROC) p_krb5_cc_get_principal =
214                 GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
215         (FARPROC) p_krb5_cc_default =
216                 GetProcAddress( hKRB5_32, "krb5_cc_default" );
217         (FARPROC) p_krb5_sname_to_principal =
218                 GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
219         (FARPROC) p_krb5_init_context =
220                 GetProcAddress( hKRB5_32, "krb5_init_context" );
221         (FARPROC) p_krb5_free_ticket =
222                 GetProcAddress( hKRB5_32, "krb5_free_ticket" );
223         (FARPROC) p_krb5_rd_req =
224                 GetProcAddress( hKRB5_32, "krb5_rd_req" );
225         (FARPROC) p_krb5_kt_default =
226                 GetProcAddress( hKRB5_32, "krb5_kt_default" );
227         (FARPROC) p_krb5_kt_resolve =
228                 GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
229         (FARPROC) p_krb5_auth_con_init =
230                 GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
231         }
232
233 /* Stubs for each function to be dynamicly loaded */
234 void
235 kssl_krb5_free_data_contents(krb5_context CO, krb5_data  * data)
236         {
237         if (!krb5_loaded)
238                 load_krb5_dll();
239
240         if ( p_krb5_free_data_contents )
241                 p_krb5_free_data_contents(CO,data);
242         }
243
244 krb5_error_code
245 kssl_krb5_mk_req_extended (krb5_context CO,
246                           krb5_auth_context  * pACO,
247                           krb5_const krb5_flags F,
248                           krb5_data  * pD1,
249                           krb5_creds  * pC,
250                           krb5_data  * pD2)
251         {
252         if (!krb5_loaded)
253                 load_krb5_dll();
254
255         if ( p_krb5_mk_req_extended )
256                 return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
257         else
258                 return KRB5KRB_ERR_GENERIC;
259         }
260 krb5_error_code
261 kssl_krb5_auth_con_init(krb5_context CO,
262                        krb5_auth_context  * pACO)
263         {
264         if (!krb5_loaded)
265                 load_krb5_dll();
266
267         if ( p_krb5_auth_con_init )
268                 return(p_krb5_auth_con_init(CO,pACO));
269         else
270                 return KRB5KRB_ERR_GENERIC;
271         }
272 krb5_error_code
273 kssl_krb5_auth_con_free (krb5_context CO,
274                         krb5_auth_context ACO)
275         {
276         if (!krb5_loaded)
277                 load_krb5_dll();
278
279         if ( p_krb5_auth_con_free )
280                 return(p_krb5_auth_con_free(CO,ACO));
281         else
282                 return KRB5KRB_ERR_GENERIC;
283         }
284 krb5_error_code
285 kssl_krb5_get_credentials(krb5_context CO,
286                          krb5_const krb5_flags F,
287                          krb5_ccache CC,
288                          krb5_creds  * pCR,
289                          krb5_creds  ** ppCR)
290         {
291         if (!krb5_loaded)
292                 load_krb5_dll();
293
294         if ( p_krb5_get_credentials )
295                 return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
296         else
297                 return KRB5KRB_ERR_GENERIC;
298         }
299 krb5_error_code
300 kssl_krb5_sname_to_principal(krb5_context CO,
301                             krb5_const char  * pC1,
302                             krb5_const char  * pC2,
303                             krb5_int32 I,
304                             krb5_principal  * pPR)
305         {
306         if (!krb5_loaded)
307                 load_krb5_dll();
308
309         if ( p_krb5_sname_to_principal )
310                 return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
311         else
312                 return KRB5KRB_ERR_GENERIC;
313         }
314
315 krb5_error_code
316 kssl_krb5_cc_default(krb5_context CO,
317                     krb5_ccache  * pCC)
318         {
319         if (!krb5_loaded)
320                 load_krb5_dll();
321
322         if ( p_krb5_cc_default )
323                 return(p_krb5_cc_default(CO,pCC));
324         else
325                 return KRB5KRB_ERR_GENERIC;
326         }
327
328 krb5_error_code
329 kssl_krb5_init_context(krb5_context * pCO)
330         {
331         if (!krb5_loaded)
332                 load_krb5_dll();
333
334         if ( p_krb5_init_context )
335                 return(p_krb5_init_context(pCO));
336         else
337                 return KRB5KRB_ERR_GENERIC;
338         }
339
340 void
341 kssl_krb5_free_context(krb5_context CO)
342         {
343         if (!krb5_loaded)
344                 load_krb5_dll();
345
346         if ( p_krb5_free_context )
347                 p_krb5_free_context(CO);
348         }
349
350 void
351 kssl_krb5_free_principal(krb5_context c, krb5_principal p)
352         {
353         if (!krb5_loaded)
354                 load_krb5_dll();
355
356         if ( p_krb5_free_principal )
357                 p_krb5_free_principal(c,p);
358         }
359
360 krb5_error_code
361 kssl_krb5_kt_resolve(krb5_context con,
362                     krb5_const char * sz,
363                     krb5_keytab * kt)
364         {
365         if (!krb5_loaded)
366                 load_krb5_dll();
367
368         if ( p_krb5_kt_resolve )
369                 return(p_krb5_kt_resolve(con,sz,kt));
370         else
371                 return KRB5KRB_ERR_GENERIC;
372         }
373
374 krb5_error_code
375 kssl_krb5_kt_default(krb5_context con,
376                     krb5_keytab * kt)
377         {
378         if (!krb5_loaded)
379                 load_krb5_dll();
380
381         if ( p_krb5_kt_default )
382                 return(p_krb5_kt_default(con,kt));
383         else
384                 return KRB5KRB_ERR_GENERIC;
385         }
386
387 krb5_error_code
388 kssl_krb5_free_ticket(krb5_context con,
389                      krb5_ticket * kt)
390         {
391         if (!krb5_loaded)
392                 load_krb5_dll();
393
394         if ( p_krb5_free_ticket )
395                 return(p_krb5_free_ticket(con,kt));
396         else
397                 return KRB5KRB_ERR_GENERIC;
398         }
399
400 krb5_error_code
401 kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
402                 krb5_const krb5_data * data,
403                 krb5_const_principal princ, krb5_keytab keytab,
404                 krb5_flags * flags, krb5_ticket ** pptkt)
405         {
406         if (!krb5_loaded)
407                 load_krb5_dll();
408
409         if ( p_krb5_rd_req )
410                 return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
411         else
412                 return KRB5KRB_ERR_GENERIC;
413         }
414
415 /* Structure definitions  */
416 #ifndef NO_DEF_KRB5_CCACHE
417 #ifndef krb5_x
418 #define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
419 #define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
420 #endif 
421
422 typedef krb5_pointer    krb5_cc_cursor; /* cursor for sequential lookup */
423
424 typedef struct _krb5_ccache
425         {
426         krb5_magic magic;
427         struct _krb5_cc_ops FAR *ops;
428         krb5_pointer data;
429         } *krb5_ccache;
430
431 typedef struct _krb5_cc_ops
432         {
433         krb5_magic magic;
434         char  *prefix;
435         char  * (KRB5_CALLCONV *get_name) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
436         krb5_error_code (KRB5_CALLCONV *resolve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache  *,
437                 const char  *));
438         krb5_error_code (KRB5_CALLCONV *gen_new) KRB5_NPROTOTYPE((krb5_context, krb5_ccache  *));
439         krb5_error_code (KRB5_CALLCONV *init) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
440                 krb5_principal));
441         krb5_error_code (KRB5_CALLCONV *destroy) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
442         krb5_error_code (KRB5_CALLCONV *close) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
443         krb5_error_code (KRB5_CALLCONV *store) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
444                 krb5_creds  *));
445         krb5_error_code (KRB5_CALLCONV *retrieve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
446                 krb5_flags, krb5_creds  *,
447                 krb5_creds  *));
448         krb5_error_code (KRB5_CALLCONV *get_princ) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
449                 krb5_principal  *));
450         krb5_error_code (KRB5_CALLCONV *get_first) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
451                 krb5_cc_cursor  *));
452         krb5_error_code (KRB5_CALLCONV *get_next) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
453                 krb5_cc_cursor  *, krb5_creds  *));
454         krb5_error_code (KRB5_CALLCONV *end_get) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
455                 krb5_cc_cursor  *));
456         krb5_error_code (KRB5_CALLCONV *remove_cred) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
457                 krb5_flags, krb5_creds  *));
458         krb5_error_code (KRB5_CALLCONV *set_flags) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
459                 krb5_flags));
460         } krb5_cc_ops;
461 #endif /* NO_DEF_KRB5_CCACHE */
462
463 krb5_error_code 
464 kssl_krb5_cc_get_principal
465     (krb5_context context, krb5_ccache cache,
466       krb5_principal *principal)
467         {
468         if ( p_krb5_cc_get_principal )
469                 return(p_krb5_cc_get_principal(context,cache,principal));
470         else
471                 return(krb5_x ((cache)->ops->get_princ,(context, cache, principal)));
472         }
473 #endif  /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
474
475 char
476 *kstring(char *string)
477         {
478         static char     *null = "[NULL]";
479
480         return ((string == NULL)? null: string);
481         }
482
483 #define MAXKNUM 255
484 char
485 *knumber(int len, krb5_octet *contents)
486         {
487         static char     buf[MAXKNUM+1];
488         int             i;
489
490         BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
491
492         for (i=0; i < len  &&  MAXKNUM > strlen(buf)+3; i++)
493                 {
494                 BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
495                 }
496
497         return (buf);
498         }
499
500
501 /*      Set kssl_err error info when reason text is a simple string
502 **              kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
503 */
504 void
505 kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
506         {
507         if (kssl_err == NULL)  return;
508
509         kssl_err->reason = reason;
510         BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
511         return;
512         }
513
514
515 /*      Display contents of krb5_data struct, for debugging
516 */
517 void
518 print_krb5_data(char *label, krb5_data *kdata)
519         {
520         int     i;
521
522         printf("%s[%d] ", label, kdata->length);
523         for (i=0; i < kdata->length; i++)
524                 {
525                 if (isprint((int) kdata->data[i]))
526                         printf( "%c ",  kdata->data[i]);
527                 else
528                         printf( "%02x", kdata->data[i]);
529                 }
530         printf("\n");
531         }
532
533
534 /*      Display contents of krb5_authdata struct, for debugging
535 */
536 void
537 print_krb5_authdata(char *label, krb5_authdata **adata)
538         {
539         if (adata == NULL)
540                 {
541                 printf("%s, authdata==0\n", label);
542                 return;
543                 }
544         printf("%s [%p]\n", label, adata);
545 #if 0
546         {
547         int     i;
548         printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
549         for (i=0; i < adata->length; i++)
550                 {
551                 printf((isprint(adata->contents[i]))? "%c ": "%02x",
552                         adata->contents[i]);
553                 }
554         printf("\n");
555         }
556 #endif
557         }
558
559
560 /*      Display contents of krb5_keyblock struct, for debugging
561 */
562 void
563 print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
564         {
565         int     i;
566
567         if (keyblk == NULL)
568                 {
569                 printf("%s, keyblk==0\n", label);
570                 return;
571                 }
572 #ifdef KRB5_HEIMDAL
573         printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, keyblk->keyvalue->length);
574         for (i=0; i < keyblk->keyvalue->length; i++)
575                 {
576                 printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
577                 }
578         printf("\n");
579 #else
580         printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
581         for (i=0; i < keyblk->length; i++)
582                 {
583                 printf("%02x",keyblk->contents[i]);
584                 }
585         printf("\n");
586 #endif
587         }
588
589
590 /*      Given krb5 service (typically "kssl") and hostname in kssl_ctx,
591 **      Create Kerberos AP_REQ message for SSL Client.
592 **
593 **      19990628        VRS     Started.
594 */
595 krb5_error_code
596 kssl_cget_tkt(  /* UPDATE */    KSSL_CTX *kssl_ctx,
597                 /* OUT    */    krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
598         {
599         krb5_error_code         krb5rc = KRB5KRB_ERR_GENERIC;
600         krb5_context            krb5context = NULL;
601         krb5_auth_context       krb5auth_context = NULL;
602         krb5_ccache             krb5ccdef = NULL;
603         krb5_creds              krb5creds, *krb5credsp = NULL;
604         krb5_data               krb5in_data;
605
606         kssl_err_set(kssl_err, 0, "");
607         memset((char *)&krb5creds, 0, sizeof(krb5creds));
608
609         if (!kssl_ctx)
610                 {
611                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
612                         "No kssl_ctx defined.\n");
613                 goto err;
614                 }
615         else if (!kssl_ctx->service_host)
616                 {
617                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
618                         "kssl_ctx service_host undefined.\n");
619                 goto err;
620                 }
621
622         if ((krb5rc = krb5_init_context(&krb5context)) != 0)
623                 {
624                 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
625                         "krb5_init_context() fails: %d\n", krb5rc);
626                 kssl_err->reason = SSL_R_KRB5_C_INIT;
627                 goto err;
628                 }
629
630         if ((krb5rc = krb5_sname_to_principal(krb5context,
631                 kssl_ctx->service_host,
632                 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
633                 KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
634                 {
635                 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
636                         "krb5_sname_to_principal() fails for %s/%s\n",
637                         kssl_ctx->service_host,
638                         (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
639                 kssl_err->reason = SSL_R_KRB5_C_INIT;
640                 goto err;
641                 }
642
643         if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
644                 {
645                 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
646                         "krb5_cc_default fails.\n");
647                 goto err;
648                 }
649
650         if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
651                 &krb5creds.client)) != 0)
652                 {
653                 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
654                         "krb5_cc_get_principal() fails.\n");
655                 goto err;
656                 }
657
658         if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
659                 &krb5creds, &krb5credsp)) != 0)
660                 {
661                 kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
662                         "krb5_get_credentials() fails.\n");
663                 goto err;
664                 }
665
666         krb5in_data.data = NULL;
667         krb5in_data.length = 0;
668
669         krb5rc = KRB5KRB_ERR_GENERIC;
670         /*      caller should free data of krb5_app_req  */
671         if ((krb5rc = krb5_mk_req_extended(krb5context, &krb5auth_context,
672                 0, &krb5in_data, krb5credsp, krb5_app_req)) != 0)
673                 {
674                 kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
675                         "krb5_mk_req_extended() fails.\n");
676                 goto err;
677                 }
678 #ifdef KRB5_HEIMDAL
679         else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
680                 {
681                 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
682                         "kssl_ctx_setkey() fails.\n");
683                 }
684 #else
685         else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
686                 {
687                 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
688                         "kssl_ctx_setkey() fails.\n");
689                 }
690 #endif
691         else    krb5rc = 0;
692
693  err:
694 #ifdef KSSL_DEBUG
695         kssl_ctx_show(kssl_ctx);
696 #endif  /* KSSL_DEBUG */
697
698         if (krb5creds.client)   krb5_free_principal(krb5context, krb5creds.client);
699         if (krb5creds.server)   krb5_free_principal(krb5context, krb5creds.server);
700         if (krb5auth_context)   krb5_auth_con_free(krb5context, krb5auth_context);
701         if (krb5context)        krb5_free_context(krb5context);
702         return (krb5rc);
703         }
704
705
706 /*      Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
707 **              and krb5 AP_REQ message & message length,
708 **      Return Kerberos session key and client principle
709 **              to SSL Server in KSSL_CTX *kssl_ctx.
710 **
711 **      19990702        VRS     Started.
712 */
713 krb5_error_code
714 kssl_sget_tkt(  /* UPDATE */    KSSL_CTX *kssl_ctx,
715                 /* IN     */    char *msg, int msglen,
716                 /* OUT    */    KSSL_ERR *kssl_err  )
717         {
718         krb5_error_code                 krb5rc = KRB5KRB_ERR_GENERIC;
719         static krb5_context             krb5context = NULL;
720         static krb5_auth_context        krb5auth_context = NULL;
721         krb5_ticket                     *krb5ticket = NULL;
722         krb5_keytab                     krb5keytab = NULL;
723         krb5_principal                  krb5server;
724         krb5_data                       krb5in_data;
725         krb5_flags                      ap_option;
726
727         kssl_err_set(kssl_err, 0, "");
728
729         if (!kssl_ctx)
730                 {
731                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
732                 goto err;
733                 }
734
735 #ifdef KSSL_DEBUG
736         printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
737 #endif  /* KSSL_DEBUG */
738
739         if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
740                 {
741                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
742                         "krb5_init_context() fails.\n");
743                 goto err;
744                 }
745         if (krb5auth_context  &&
746                 (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
747                 {
748                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
749                         "krb5_auth_con_free() fails.\n");
750                 goto err;
751                 }
752         else  krb5auth_context = NULL;
753         if (!krb5auth_context  &&
754                 (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
755                 {
756                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
757                         "krb5_auth_con_init() fails.\n");
758                 goto err;
759                 }
760
761         if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
762                 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
763                 KRB5_NT_SRV_HST, &krb5server)) != 0)
764                 {
765                 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
766                         "krb5_sname_to_principal() fails.\n");
767                 goto err;
768                 }
769
770         /*      kssl_ctx->keytab_file == NULL ==> use Kerberos default
771         */
772         if (kssl_ctx->keytab_file)
773                 {
774                 krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
775                         &krb5keytab);
776                 if (krb5rc)
777                         {
778                         kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
779                                 "krb5_kt_resolve() fails.\n");
780                         goto err;
781                         }
782                 }
783         else
784                 {
785                 krb5rc = krb5_kt_default(krb5context,&krb5keytab);
786                 if (krb5rc)
787                         {
788                         kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, 
789                                 "krb5_kt_default() fails.\n");
790                         goto err;
791                         }
792                 }
793
794         /*      Actual Kerberos5 krb5_recvauth() has initial conversation here
795         **      o       check KRB5_SENDAUTH_BADAUTHVERS unless KRB5_RECVAUTH_SKIP_VERSION
796         **      o       check KRB5_SENDAUTH_BADAPPLVERS
797         **      o       send "0" msg if all OK
798         */
799
800         krb5in_data.data = msg;
801         krb5in_data.length = msglen;
802         if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, &krb5in_data,
803                 krb5server, krb5keytab, &ap_option, &krb5ticket)) != 0)
804                 {
805                 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
806                         "krb5_rd_req() fails with %x.\n", krb5rc);
807                 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
808                 goto err;
809                 }
810
811         krb5rc = KRB5_NO_TKT_SUPPLIED;
812         if (!krb5ticket  ||     !krb5ticket->enc_part2  ||
813                 !krb5ticket->enc_part2->client  ||
814                 !krb5ticket->enc_part2->client->data  ||
815                 !krb5ticket->enc_part2->session)
816                 {
817                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
818                         "bad ticket from krb5_rd_req.\n");
819                 }
820         else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
821                 &krb5ticket->enc_part2->client->realm,
822                 krb5ticket->enc_part2->client->data))
823                 {
824                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
825                         "kssl_ctx_setprinc() fails.\n");
826                 }
827         else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
828                 {
829                 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
830                         "kssl_ctx_setkey() fails.\n");
831                 }
832         else    krb5rc = 0;
833
834  err:
835 #ifdef KSSL_DEBUG
836         kssl_ctx_show(kssl_ctx);
837 #endif  /* KSSL_DEBUG */
838
839         if (krb5keytab)         krb5_kt_close(krb5context, krb5keytab);
840         if (krb5ticket)         krb5_free_ticket(krb5context, krb5ticket);
841         if (krb5server)         krb5_free_principal(krb5context, krb5server);
842         return (krb5rc);
843         }
844
845
846 /*      Allocate & return a new kssl_ctx struct.
847 */
848 KSSL_CTX        *
849 kssl_ctx_new(void)
850         {
851         return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
852         }
853
854
855 /*      Frees a kssl_ctx struct and any allocated memory it holds.
856 **      Returns NULL.
857 */
858 KSSL_CTX        *
859 kssl_ctx_free(KSSL_CTX *kssl_ctx)
860         {
861         if (kssl_ctx == NULL)  return kssl_ctx;
862
863         if (kssl_ctx->key)              memset(kssl_ctx->key, 0, kssl_ctx->length);
864         if (kssl_ctx->key)              free(kssl_ctx->key);
865         if (kssl_ctx->client_princ)     free(kssl_ctx->client_princ);
866         if (kssl_ctx->service_host)     free(kssl_ctx->service_host);
867         if (kssl_ctx->service_name)     free(kssl_ctx->service_name);
868         if (kssl_ctx->keytab_file)      free(kssl_ctx->keytab_file);
869
870         free(kssl_ctx);
871         return (KSSL_CTX *) NULL;
872         }
873
874
875 /*      Given a (krb5_data *) entity (and optional realm),
876 **      set the plain (char *) client_princ or service_host member
877 **      of the kssl_ctx struct.
878 */
879 krb5_error_code
880 kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
881         krb5_data *realm, krb5_data *entity)
882         {
883         char    **princ;
884         int     length;
885
886         if (kssl_ctx == NULL  ||  entity == NULL)  return KSSL_CTX_ERR;
887
888         switch (which)
889                 {
890         case KSSL_CLIENT:       princ = &kssl_ctx->client_princ;        break;
891         case KSSL_SERVER:       princ = &kssl_ctx->service_host;        break;
892         default:                return KSSL_CTX_ERR;                    break;
893                 }
894         if (*princ)  free(*princ);
895
896         length = entity->length + ((realm)? realm->length + 2: 1);
897         if ((*princ = calloc(1, length)) == NULL)
898                 return KSSL_CTX_ERR;
899         else
900                 {
901                 strncpy(*princ, entity->data, entity->length);
902                 if (realm)
903                         {
904                         strcat (*princ, "@");
905                         (void) strncat(*princ, realm->data, realm->length);
906                         }
907                 }
908
909         return KSSL_CTX_OK;
910         }
911
912
913 /*      Set one of the plain (char *) string members of the kssl_ctx struct.
914 **      Default values should be:
915 **              which == KSSL_SERVICE   =>      "khost" (KRB5SVC)
916 **              which == KSSL_KEYTAB    =>      "/etc/krb5.keytab" (KRB5KEYTAB)
917 */
918 krb5_error_code
919 kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
920         {
921         char    **string;
922
923         if (!kssl_ctx)  return KSSL_CTX_ERR;
924
925         switch (which)
926                 {
927         case KSSL_SERVICE:      string = &kssl_ctx->service_name;       break;
928         case KSSL_SERVER:       string = &kssl_ctx->service_host;       break;
929         case KSSL_CLIENT:       string = &kssl_ctx->client_princ;       break;
930         case KSSL_KEYTAB:       string = &kssl_ctx->keytab_file;        break;
931         default:                return KSSL_CTX_ERR;                    break;
932                 }
933         if (*string)  free(*string);
934
935         if (!text)
936                 {
937                 *string = '\0';
938                 return KSSL_CTX_OK;
939                 }
940
941         if ((*string = calloc(1, strlen(text) + 1)) == NULL)
942                 return KSSL_CTX_ERR;
943         else
944                 strcpy(*string, text);
945
946         return KSSL_CTX_OK;
947         }
948
949
950 /*      Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
951 **      struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
952 */
953 krb5_error_code
954 kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
955         {
956         if (!kssl_ctx)  return KSSL_CTX_ERR;
957
958         if (kssl_ctx->key)
959                 {
960                 memset(kssl_ctx->key, 0, kssl_ctx->length);
961                 free(kssl_ctx->key);
962                 }
963
964         if (session)
965                 {
966                 kssl_ctx->enctype = session->enctype;
967                 kssl_ctx->length  = session->length;
968                 }
969         else
970                 {
971                 kssl_ctx->enctype = ENCTYPE_UNKNOWN;
972                 kssl_ctx->length  = 0;
973                 return KSSL_CTX_OK;
974                 }
975
976         if ((kssl_ctx->key =
977                 (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
978                 {
979                 kssl_ctx->length  = 0;
980                 return KSSL_CTX_ERR;
981                 }
982         else
983                 memcpy(kssl_ctx->key, session->contents, session->length);
984
985         return KSSL_CTX_OK;
986         }
987
988
989 /*      Display contents of kssl_ctx struct
990 */
991 void
992 kssl_ctx_show(KSSL_CTX *kssl_ctx)
993         {
994         int     i;
995
996         printf("kssl_ctx: ");
997         if (kssl_ctx == NULL)
998                 {
999                 printf("NULL\n");
1000                 return;
1001                 }
1002         else
1003                 printf("%p\n", kssl_ctx);
1004
1005         printf("\tservice:\t%s\n",
1006                 (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1007         printf("\tclient:\t%s\n",
1008                 (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1009         printf("\tserver:\t%s\n",
1010                 (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1011         printf("\tkeytab:\t%s\n",
1012                 (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1013         printf("\tkey [%d:%d]:\t",
1014                 kssl_ctx->enctype, kssl_ctx->length);
1015
1016         for (i=0; i < kssl_ctx->length  &&  kssl_ctx->key; i++)
1017                 {
1018                 printf("%02x", kssl_ctx->key[i]);
1019                 }
1020         printf("\n");
1021         return;
1022         }
1023
1024 void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1025         {
1026 #ifdef KRB5_HEIMDAL
1027         data->length = 0;
1028         free(data->if (data->data) data);
1029 #else
1030         krb5_free_data_contents(NULL, data);
1031 #endif
1032         }
1033
1034 #else /* !OPENSSL_NO_KRB5 */
1035
1036 #if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
1037 static int dummy=(int)&dummy;
1038 #endif
1039
1040 #endif  /* !OPENSSL_NO_KRB5     */
1041