Merge from main trunk: lets see if this works ;-)
[OpenSSL.git] / ssl / kssl.c
blobfe7f4ebe5e75494f30bcf47bea801c8654658a9d
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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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/)"
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.
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.
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/)"
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 * ====================================================================
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).
59 /* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
61 ** 19990701 VRS Started.
64 #ifndef NO_KRB5
65 #include <string.h>
66 #include <openssl/ssl.h>
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.
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.
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
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
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);
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 */
189 /* Function to Load the Kerberos 5 DLL and initialize function pointers */
190 void
191 load_krb5_dll(void)
193 HANDLE hKRB5_32;
195 krb5_loaded++;
196 hKRB5_32 = LoadLibrary("KRB5_32");
197 if (!hKRB5_32)
198 return;
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" );
232 /* Stubs for each function to be dynamicly loaded */
233 void
234 kssl_krb5_free_data_contents(krb5_context CO, krb5_data * data)
236 if (!krb5_loaded)
237 load_krb5_dll();
239 if ( p_krb5_free_data_contents )
240 p_krb5_free_data_contents(CO,data);
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)
251 if (!krb5_loaded)
252 load_krb5_dll();
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;
259 krb5_error_code
260 kssl_krb5_auth_con_init(krb5_context CO,
261 krb5_auth_context * pACO)
263 if (!krb5_loaded)
264 load_krb5_dll();
266 if ( p_krb5_auth_con_init )
267 return(p_krb5_auth_con_init(CO,pACO));
268 else
269 return KRB5KRB_ERR_GENERIC;
271 krb5_error_code
272 kssl_krb5_auth_con_free (krb5_context CO,
273 krb5_auth_context ACO)
275 if (!krb5_loaded)
276 load_krb5_dll();
278 if ( p_krb5_auth_con_free )
279 return(p_krb5_auth_con_free(CO,ACO));
280 else
281 return KRB5KRB_ERR_GENERIC;
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)
290 if (!krb5_loaded)
291 load_krb5_dll();
293 if ( p_krb5_get_credentials )
294 return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
295 else
296 return KRB5KRB_ERR_GENERIC;
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)
305 if (!krb5_loaded)
306 load_krb5_dll();
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;
314 krb5_error_code
315 kssl_krb5_cc_default(krb5_context CO,
316 krb5_ccache * pCC)
318 if (!krb5_loaded)
319 load_krb5_dll();
321 if ( p_krb5_cc_default )
322 return(p_krb5_cc_default(CO,pCC));
323 else
324 return KRB5KRB_ERR_GENERIC;
327 krb5_error_code
328 kssl_krb5_init_context(krb5_context * pCO)
330 if (!krb5_loaded)
331 load_krb5_dll();
333 if ( p_krb5_init_context )
334 return(p_krb5_init_context(pCO));
335 else
336 return KRB5KRB_ERR_GENERIC;
339 void
340 kssl_krb5_free_context(krb5_context CO)
342 if (!krb5_loaded)
343 load_krb5_dll();
345 if ( p_krb5_free_context )
346 p_krb5_free_context(CO);
349 void
350 kssl_krb5_free_principal(krb5_context c, krb5_principal p)
352 if (!krb5_loaded)
353 load_krb5_dll();
355 if ( p_krb5_free_principal )
356 p_krb5_free_principal(c,p);
359 krb5_error_code
360 kssl_krb5_kt_resolve(krb5_context con,
361 krb5_const char * sz,
362 krb5_keytab * kt)
364 if (!krb5_loaded)
365 load_krb5_dll();
367 if ( p_krb5_kt_resolve )
368 return(p_krb5_kt_resolve(con,sz,kt));
369 else
370 return KRB5KRB_ERR_GENERIC;
373 krb5_error_code
374 kssl_krb5_kt_default(krb5_context con,
375 krb5_keytab * kt)
377 if (!krb5_loaded)
378 load_krb5_dll();
380 if ( p_krb5_kt_default )
381 return(p_krb5_kt_default(con,kt));
382 else
383 return KRB5KRB_ERR_GENERIC;
386 krb5_error_code
387 kssl_krb5_free_ticket(krb5_context con,
388 krb5_ticket * kt)
390 if (!krb5_loaded)
391 load_krb5_dll();
393 if ( p_krb5_free_ticket )
394 return(p_krb5_free_ticket(con,kt));
395 else
396 return KRB5KRB_ERR_GENERIC;
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)
405 if (!krb5_loaded)
406 load_krb5_dll();
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;
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
421 typedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */
423 typedef struct _krb5_ccache
425 krb5_magic magic;
426 struct _krb5_cc_ops FAR *ops;
427 krb5_pointer data;
428 } *krb5_ccache;
430 typedef struct _krb5_cc_ops
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 */
462 krb5_error_code
463 kssl_krb5_cc_get_principal
464 (krb5_context context, krb5_ccache cache,
465 krb5_principal *principal)
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)));
472 #endif /* WINDOWS || WIN32 */
474 char
475 *kstring(char *string)
477 static char *null = "[NULL]";
479 return ((string == NULL)? null: string);
482 #define MAXKNUM 255
483 char
484 *knumber(int len, krb5_octet *contents)
486 static char buf[MAXKNUM+1];
487 int i;
489 BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
491 for (i=0; i < len && MAXKNUM > strlen(buf)+3; i++)
493 BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
496 return (buf);
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]; }
503 void
504 kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
506 if (kssl_err == NULL) return;
508 kssl_err->reason = reason;
509 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
510 return;
514 /* Display contents of krb5_data struct, for debugging
516 void
517 print_krb5_data(char *label, krb5_data *kdata)
519 int i;
521 printf("%s[%d] ", label, kdata->length);
522 for (i=0; i < kdata->length; i++)
524 if (isprint((int) kdata->data[i]))
525 printf( "%c ", kdata->data[i]);
526 else
527 printf( "%02x", kdata->data[i]);
529 printf("\n");
533 /* Display contents of krb5_authdata struct, for debugging
535 void
536 print_krb5_authdata(char *label, krb5_authdata **adata)
538 if (adata == NULL)
540 printf("%s, authdata==0\n", label);
541 return;
543 printf("%s [%p]\n", label, adata);
544 #if 0
546 int i;
547 printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
548 for (i=0; i < adata->length; i++)
550 printf((isprint(adata->contents[i]))? "%c ": "%02x",
551 adata->contents[i]);
553 printf("\n");
555 #endif
559 /* Display contents of krb5_keyblock struct, for debugging
561 void
562 print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
564 int i;
566 if (keyblk == NULL)
568 printf("%s, keyblk==0\n", label);
569 return;
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++)
575 printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
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++)
582 printf("%02x",keyblk->contents[i]);
584 printf("\n");
585 #endif
589 /* Given krb5 service (typically "kssl") and hostname in kssl_ctx,
590 ** Create Kerberos AP_REQ message for SSL Client.
592 ** 19990628 VRS Started.
594 krb5_error_code
595 kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
596 /* OUT */ krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
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;
605 kssl_err_set(kssl_err, 0, "");
606 memset((char *)&krb5creds, 0, sizeof(krb5creds));
608 if (!kssl_ctx)
610 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
611 "No kssl_ctx defined.\n");
612 goto err;
614 else if (!kssl_ctx->service_host)
616 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
617 "kssl_ctx service_host undefined.\n");
618 goto err;
621 if ((krb5rc = krb5_init_context(&krb5context)) != 0)
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;
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)
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;
642 if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
644 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
645 "krb5_cc_default fails.\n");
646 goto err;
649 if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
650 &krb5creds.client)) != 0)
652 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
653 "krb5_cc_get_principal() fails.\n");
654 goto err;
657 if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
658 &krb5creds, &krb5credsp)) != 0)
660 kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
661 "krb5_get_credentials() fails.\n");
662 goto err;
665 krb5in_data.data = NULL;
666 krb5in_data.length = 0;
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)
673 kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
674 "krb5_mk_req_extended() fails.\n");
675 goto err;
677 #ifdef KRB5_HEIMDAL
678 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
680 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
681 "kssl_ctx_setkey() fails.\n");
683 #else
684 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
686 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
687 "kssl_ctx_setkey() fails.\n");
689 #endif
690 else krb5rc = 0;
692 err:
693 #ifdef KSSL_DEBUG
694 kssl_ctx_show(kssl_ctx);
695 #endif /* KSSL_DEBUG */
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);
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.
710 ** 19990702 VRS Started.
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 )
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;
726 kssl_err_set(kssl_err, 0, "");
728 if (!kssl_ctx)
730 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
731 goto err;
734 #ifdef KSSL_DEBUG
735 printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
736 #endif /* KSSL_DEBUG */
738 if (!krb5context && (krb5rc = krb5_init_context(&krb5context)))
740 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
741 "krb5_init_context() fails.\n");
742 goto err;
744 if (krb5auth_context &&
745 (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
747 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
748 "krb5_auth_con_free() fails.\n");
749 goto err;
751 else krb5auth_context = NULL;
752 if (!krb5auth_context &&
753 (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
755 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
756 "krb5_auth_con_init() fails.\n");
757 goto err;
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)
764 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
765 "krb5_sname_to_principal() fails.\n");
766 goto err;
769 /* kssl_ctx->keytab_file == NULL ==> use Kerberos default
771 if (kssl_ctx->keytab_file)
773 krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
774 &krb5keytab);
775 if (krb5rc)
777 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
778 "krb5_kt_resolve() fails.\n");
779 goto err;
782 else
784 krb5rc = krb5_kt_default(krb5context,&krb5keytab);
785 if (krb5rc)
787 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
788 "krb5_kt_default() fails.\n");
789 goto err;
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
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)
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;
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)
816 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
817 "bad ticket from krb5_rd_req.\n");
819 else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
820 &krb5ticket->enc_part2->client->realm,
821 krb5ticket->enc_part2->client->data))
823 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
824 "kssl_ctx_setprinc() fails.\n");
826 else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
828 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
829 "kssl_ctx_setkey() fails.\n");
831 else krb5rc = 0;
833 err:
834 #ifdef KSSL_DEBUG
835 kssl_ctx_show(kssl_ctx);
836 #endif /* KSSL_DEBUG */
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);
845 /* Allocate & return a new kssl_ctx struct.
847 KSSL_CTX *
848 kssl_ctx_new(void)
850 return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
854 /* Frees a kssl_ctx struct and any allocated memory it holds.
855 ** Returns NULL.
857 KSSL_CTX *
858 kssl_ctx_free(KSSL_CTX *kssl_ctx)
860 if (kssl_ctx == NULL) return kssl_ctx;
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);
869 free(kssl_ctx);
870 return (KSSL_CTX *) NULL;
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.
878 krb5_error_code
879 kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
880 krb5_data *realm, krb5_data *entity)
882 char **princ;
883 int length;
885 if (kssl_ctx == NULL || entity == NULL) return KSSL_CTX_ERR;
887 switch (which)
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;
893 if (*princ) free(*princ);
895 length = entity->length + ((realm)? realm->length + 2: 1);
896 if ((*princ = calloc(1, length)) == NULL)
897 return KSSL_CTX_ERR;
898 else
900 strncpy(*princ, entity->data, entity->length);
901 if (realm)
903 strcat (*princ, "@");
904 (void) strncat(*princ, realm->data, realm->length);
908 return KSSL_CTX_OK;
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)
917 krb5_error_code
918 kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
920 char **string;
922 if (!kssl_ctx) return KSSL_CTX_ERR;
924 switch (which)
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;
932 if (*string) free(*string);
934 if (!text)
936 *string = '\0';
937 return KSSL_CTX_OK;
940 if ((*string = calloc(1, strlen(text) + 1)) == NULL)
941 return KSSL_CTX_ERR;
942 else
943 strcpy(*string, text);
945 return KSSL_CTX_OK;
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.
952 krb5_error_code
953 kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
955 if (!kssl_ctx) return KSSL_CTX_ERR;
957 if (kssl_ctx->key)
959 memset(kssl_ctx->key, 0, kssl_ctx->length);
960 free(kssl_ctx->key);
963 if (session)
965 kssl_ctx->enctype = session->enctype;
966 kssl_ctx->length = session->length;
968 else
970 kssl_ctx->enctype = ENCTYPE_UNKNOWN;
971 kssl_ctx->length = 0;
972 return KSSL_CTX_OK;
975 if ((kssl_ctx->key =
976 (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
978 kssl_ctx->length = 0;
979 return KSSL_CTX_ERR;
981 else
982 memcpy(kssl_ctx->key, session->contents, session->length);
984 return KSSL_CTX_OK;
988 /* Display contents of kssl_ctx struct
990 void
991 kssl_ctx_show(KSSL_CTX *kssl_ctx)
993 int i;
995 printf("kssl_ctx: ");
996 if (kssl_ctx == NULL)
998 printf("NULL\n");
999 return;
1001 else
1002 printf("%p\n", kssl_ctx);
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);
1015 for (i=0; i < kssl_ctx->length && kssl_ctx->key; i++)
1017 printf("%02x", kssl_ctx->key[i]);
1019 printf("\n");
1020 return;
1023 void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
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
1033 #else /* !NO_KRB5 */
1035 #ifdef PEDANTIC
1036 static int dummy=(int)&dummy;
1037 #endif
1039 #endif /* !NO_KRB5 */