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