1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 by OpenVision Technologies, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name of OpenVision not be used
10 * in advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. OpenVision makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
20 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 /*
25 * Copyright (C) 1998 by the FundsXpress, INC.
26 *
27 * All rights reserved.
28 *
29 * Export of this software from the United States of America may require
30 * a specific license from the United States Government. It is the
31 * responsibility of any person or organization contemplating export to
32 * obtain such a license before exporting.
33 *
34 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
35 * distribute this software and its documentation for any purpose and
36 * without fee is hereby granted, provided that the above copyright
37 * notice appear in all copies and that both that copyright notice and
38 * this permission notice appear in supporting documentation, and that
39 * the name of FundsXpress. not be used in advertising or publicity pertaining
40 * to distribution of the software without specific, written prior
41 * permission. FundsXpress makes no representations about the suitability of
42 * this software for any purpose. It is provided "as is" without express
43 * or implied warranty.
44 *
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
47 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
48 */
49 /*
50 * Copyright (c) 2006-2008, Novell, Inc.
51 * All rights reserved.
52 *
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions are met:
55 *
56 * * Redistributions of source code must retain the above copyright notice,
57 * this list of conditions and the following disclaimer.
58 * * Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * * The copyright holder's name is not used to endorse or promote products
62 * derived from this software without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
65 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
68 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
69 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
70 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
71 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
72 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
73 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
74 * POSSIBILITY OF SUCH DAMAGE.
75 */
76
77 /*
78 * $Id$
79 */
80
81
82 #include "gssapiP_krb5.h"
83 #include "mglueP.h"
84
85 #ifndef NO_PASSWORD
86 #include <pwd.h>
87 #endif
88
89 /** exported constants defined in gssapi_krb5{,_nx}.h **/
90
91 /* these are bogus, but will compile */
92
93 /*
94 * The OID of the draft krb5 mechanism, assigned by IETF, is:
95 * iso(1) org(3) dod(5) internet(1) security(5)
96 * kerberosv5(2) = 1.3.5.1.5.2
97 * The OID of the krb5_name type is:
98 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
99 * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
100 * The OID of the krb5_principal type is:
101 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
102 * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
103 * The OID of the proposed standard krb5 mechanism is:
104 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
105 * krb5(2) = 1.2.840.113554.1.2.2
106 * The OID of the proposed standard krb5 v2 mechanism is:
107 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
108 * krb5v2(3) = 1.2.840.113554.1.2.3
109 * Provisionally reserved for Kerberos session key algorithm
110 * identifiers is:
111 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
112 * krb5(2) krb5_enctype(4) = 1.2.840.113554.1.2.2.4
113 * Provisionally reserved for Kerberos mechanism-specific APIs:
114 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
115 * krb5(2) krb5_gssapi_ext(5) = 1.2.840.113554.1.2.2.5
116 */
117
118 /*
119 * Encoding rules: The first two values are encoded in one byte as 40
120 * * value1 + value2. Subsequent values are encoded base 128, most
121 * significant digit first, with the high bit (\200) set on all octets
122 * except the last in each value's encoding.
123 */
124
125 #define NO_CI_FLAGS_X_OID_LENGTH 6
126 #define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d"
127 #define GET_CRED_IMPERSONATOR_OID_LENGTH 11
128 #define GET_CRED_IMPERSONATOR_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e"
129
130 const gss_OID_desc krb5_gss_oid_array[] = {
131 /* this is the official, rfc-specified OID */
132 {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
133 /* this pre-RFC mech OID */
134 {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
135 /* this is the unofficial, incorrect mech OID emitted by MS */
136 {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
137 /* IAKERB OID */
138 {GSS_MECH_IAKERB_OID_LENGTH, GSS_MECH_IAKERB_OID},
139 /* this is the v2 assigned OID */
140 {9, "\052\206\110\206\367\022\001\002\003"},
141 /* these two are name type OID's */
142 /* 2.1.1. Kerberos Principal Name Form: (rfc 1964)
143 * This name form shall be represented by the Object Identifier {iso(1)
144 * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
145 * krb5(2) krb5_name(1)}. The recommended symbolic name for this type
146 * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
147 {10, "\052\206\110\206\367\022\001\002\002\001"},
148 /* gss_nt_krb5_principal. Object identifier for a krb5_principal. Do not use. */
149 {10, "\052\206\110\206\367\022\001\002\002\002"},
150 {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
151 /* this is an inquire cred OID */
152 {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
153 /* GSS_KRB5_NT_ENTERPRISE_NAME */
154 {10, "\052\206\110\206\367\022\001\002\002\006"},
155 /* GSS_KRB5_NT_X509_CERT */
156 {10, "\052\206\110\206\367\022\001\002\002\007"},
157 { 0, 0 }
158 };
159
160 #define kg_oids ((gss_OID)krb5_gss_oid_array)
161
162 const gss_OID gss_mech_krb5 = &kg_oids[0];
163 const gss_OID gss_mech_krb5_old = &kg_oids[1];
164 const gss_OID gss_mech_krb5_wrong = &kg_oids[2];
165 const gss_OID gss_mech_iakerb = &kg_oids[3];
166
167
168 const gss_OID gss_nt_krb5_name = &kg_oids[5];
169 const gss_OID gss_nt_krb5_principal = &kg_oids[6];
170 const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &kg_oids[5];
171
172 const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X = &kg_oids[7];
173 const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR = &kg_oids[8];
174 const gss_OID GSS_KRB5_NT_ENTERPRISE_NAME = &kg_oids[9];
175 const gss_OID GSS_KRB5_NT_X509_CERT = &kg_oids[10];
176
177 static const gss_OID_set_desc oidsets[] = {
178 {1, &kg_oids[0]}, /* RFC OID */
179 {1, &kg_oids[1]}, /* pre-RFC OID */
180 {3, &kg_oids[0]}, /* all names for krb5 mech */
181 {4, &kg_oids[0]}, /* all krb5 names and IAKERB */
182 };
183
184 #define kg_oidsets ((gss_OID_set)oidsets)
185
186 const gss_OID_set gss_mech_set_krb5 = &kg_oidsets[0];
187 const gss_OID_set gss_mech_set_krb5_old = &kg_oidsets[1];
188 const gss_OID_set gss_mech_set_krb5_both = &kg_oidsets[2];
189 const gss_OID_set kg_all_mechs = &kg_oidsets[3];
190
191 g_set kg_vdb = G_SET_INIT;
192
193 /** default credential support */
194
195 /*
196 * init_sec_context() will explicitly re-acquire default credentials,
197 * so handling the expiration/invalidation condition here isn't needed.
198 */
199 OM_uint32
kg_get_defcred(minor_status,cred)200 kg_get_defcred(minor_status, cred)
201 OM_uint32 *minor_status;
202 gss_cred_id_t *cred;
203 {
204 OM_uint32 major;
205
206 if ((major = krb5_gss_acquire_cred(minor_status,
207 (gss_name_t) NULL, GSS_C_INDEFINITE,
208 GSS_C_NULL_OID_SET, GSS_C_INITIATE,
209 cred, NULL, NULL)) && GSS_ERROR(major)) {
210 return(major);
211 }
212 *minor_status = 0;
213 return(GSS_S_COMPLETE);
214 }
215
216 OM_uint32
kg_sync_ccache_name(krb5_context context,OM_uint32 * minor_status)217 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
218 {
219 OM_uint32 err = 0;
220
221 /*
222 * Sync up the context ccache name with the GSSAPI ccache name.
223 * If kg_ccache_name is NULL -- normal unless someone has called
224 * gss_krb5_ccache_name() -- then the system default ccache will
225 * be picked up and used by resetting the context default ccache.
226 * This is needed for platforms which support multiple ccaches.
227 */
228
229 if (!err) {
230 /* if NULL, resets the context default ccache */
231 err = krb5_cc_set_default_name(context,
232 (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
233 }
234
235 *minor_status = err;
236 return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
237 }
238
239 /* This function returns whether or not the caller set a cccache name. Used by
240 * gss_acquire_cred to figure out if the caller wants to only look at this
241 * ccache or search the cache collection for the desired name */
242 OM_uint32
kg_caller_provided_ccache_name(OM_uint32 * minor_status,int * out_caller_provided_name)243 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
244 int *out_caller_provided_name)
245 {
246 if (out_caller_provided_name) {
247 *out_caller_provided_name =
248 (k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME) != NULL);
249 }
250
251 *minor_status = 0;
252 return GSS_S_COMPLETE;
253 }
254
255 OM_uint32
kg_get_ccache_name(OM_uint32 * minor_status,char ** out_name)256 kg_get_ccache_name(OM_uint32 *minor_status, char **out_name)
257 {
258 char *kg_ccache_name;
259 const char *def_name;
260 OM_uint32 err;
261 krb5_context context;
262
263 *out_name = NULL;
264
265 kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
266 if (kg_ccache_name != NULL) {
267 *out_name = strdup(kg_ccache_name);
268 err = (*out_name == NULL) ? ENOMEM : 0;
269 } else {
270 /* Use the default ccache name. */
271 err = krb5_gss_init_context(&context);
272 if (err)
273 goto cleanup;
274 def_name = krb5_cc_default_name(context);
275 *out_name = (def_name != NULL) ? strdup(def_name) : NULL;
276 err = (*out_name == NULL) ? ENOMEM : 0;
277 krb5_free_context(context);
278 }
279
280 cleanup:
281 *minor_status = err;
282 return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
283 }
284
285 OM_uint32
kg_set_ccache_name(OM_uint32 * minor_status,const char * name)286 kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
287 {
288 char *new_name = NULL;
289 char *swap = NULL;
290 char *kg_ccache_name;
291 krb5_error_code kerr;
292
293 if (name) {
294 new_name = strdup(name);
295 if (new_name == NULL) {
296 *minor_status = ENOMEM;
297 return GSS_S_FAILURE;
298 }
299 }
300
301 kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
302 swap = kg_ccache_name;
303 kg_ccache_name = new_name;
304 new_name = swap;
305 kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
306 if (kerr != 0) {
307 /* Can't store, so free up the storage. */
308 free(kg_ccache_name);
309 /* ??? free(new_name); */
310 *minor_status = kerr;
311 return GSS_S_FAILURE;
312 }
313
314 free (new_name);
315 *minor_status = 0;
316 return GSS_S_COMPLETE;
317 }
318
319 #define g_OID_prefix_equal(o1, o2) \
320 (((o1)->length >= (o2)->length) && \
321 (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
322
323 /*
324 * gss_inquire_sec_context_by_oid() methods
325 */
326 static struct {
327 gss_OID_desc oid;
328 OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
329 } krb5_gss_inquire_sec_context_by_oid_ops[] = {
330 {
331 {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
332 gss_krb5int_get_tkt_flags
333 },
334 {
335 {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
336 gss_krb5int_extract_authz_data_from_sec_context
337 },
338 {
339 {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
340 gss_krb5int_inq_sspi_session_key
341 },
342 {
343 {GSS_KRB5_INQ_ODBC_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_ODBC_SESSION_KEY_OID},
344 gss_krb5int_inq_odbc_session_key
345 },
346 {
347 {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
348 gss_krb5int_export_lucid_sec_context
349 },
350 {
351 {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
352 gss_krb5int_extract_authtime_from_sec_context
353 },
354 {
355 {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID},
356 gss_krb5int_sec_context_sasl_ssf
357 }
358 };
359
360 OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_sec_context_by_oid(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)361 krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
362 const gss_ctx_id_t context_handle,
363 const gss_OID desired_object,
364 gss_buffer_set_t *data_set)
365 {
366 krb5_gss_ctx_id_rec *ctx;
367 size_t i;
368
369 if (minor_status == NULL)
370 return GSS_S_CALL_INACCESSIBLE_WRITE;
371
372 *minor_status = 0;
373
374 if (desired_object == GSS_C_NO_OID)
375 return GSS_S_CALL_INACCESSIBLE_READ;
376
377 if (data_set == NULL)
378 return GSS_S_CALL_INACCESSIBLE_WRITE;
379
380 *data_set = GSS_C_NO_BUFFER_SET;
381
382 ctx = (krb5_gss_ctx_id_rec *) context_handle;
383
384 if (ctx->terminated || !ctx->established)
385 return GSS_S_NO_CONTEXT;
386
387 for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
388 sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
389 if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
390 return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
391 context_handle,
392 desired_object,
393 data_set);
394 }
395 }
396
397 *minor_status = EINVAL;
398
399 return GSS_S_UNAVAILABLE;
400 }
401
402 /*
403 * gss_inquire_cred_by_oid() methods
404 */
405
406 static struct {
407 gss_OID_desc oid;
408 OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *);
409 } krb5_gss_inquire_cred_by_oid_ops[] = {
410 {
411 {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
412 gss_krb5int_get_cred_impersonator
413 }
414 };
415
416 static OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_cred_by_oid(OM_uint32 * minor_status,const gss_cred_id_t cred_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)417 krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
418 const gss_cred_id_t cred_handle,
419 const gss_OID desired_object,
420 gss_buffer_set_t *data_set)
421 {
422 OM_uint32 major_status = GSS_S_FAILURE;
423 size_t i;
424
425 if (minor_status == NULL)
426 return GSS_S_CALL_INACCESSIBLE_WRITE;
427
428 *minor_status = 0;
429
430 if (desired_object == GSS_C_NO_OID)
431 return GSS_S_CALL_INACCESSIBLE_READ;
432
433 if (data_set == NULL)
434 return GSS_S_CALL_INACCESSIBLE_WRITE;
435
436 *data_set = GSS_C_NO_BUFFER_SET;
437 if (cred_handle == GSS_C_NO_CREDENTIAL) {
438 *minor_status = (OM_uint32)KRB5_NOCREDS_SUPPLIED;
439 return GSS_S_NO_CRED;
440 }
441
442 major_status = krb5_gss_validate_cred(minor_status, cred_handle);
443 if (GSS_ERROR(major_status))
444 return major_status;
445
446 for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/
447 sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) {
448 if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) {
449 return (*krb5_gss_inquire_cred_by_oid_ops[i].func)(minor_status,
450 cred_handle,
451 desired_object,
452 data_set);
453 }
454 }
455
456 *minor_status = EINVAL;
457
458 return GSS_S_UNAVAILABLE;
459 }
460
461 OM_uint32 KRB5_CALLCONV
krb5_gss_set_sec_context_option(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_OID desired_object,const gss_buffer_t value)462 krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
463 gss_ctx_id_t *context_handle,
464 const gss_OID desired_object,
465 const gss_buffer_t value)
466 {
467 if (minor_status == NULL)
468 return GSS_S_CALL_INACCESSIBLE_WRITE;
469
470 *minor_status = 0;
471
472 if (context_handle == NULL)
473 return GSS_S_CALL_INACCESSIBLE_READ;
474
475 if (desired_object == GSS_C_NO_OID)
476 return GSS_S_CALL_INACCESSIBLE_READ;
477
478 *minor_status = EINVAL;
479
480 return GSS_S_UNAVAILABLE;
481 }
482
483 static OM_uint32
no_ci_flags(OM_uint32 * minor_status,gss_cred_id_t * cred_handle,const gss_OID desired_oid,const gss_buffer_t value)484 no_ci_flags(OM_uint32 *minor_status,
485 gss_cred_id_t *cred_handle,
486 const gss_OID desired_oid,
487 const gss_buffer_t value)
488 {
489 krb5_gss_cred_id_t cred;
490
491 cred = (krb5_gss_cred_id_t) *cred_handle;
492 cred->suppress_ci_flags = 1;
493
494 *minor_status = 0;
495 return GSS_S_COMPLETE;
496 }
497 /*
498 * gssspi_set_cred_option() methods
499 */
500 static struct {
501 gss_OID_desc oid;
502 OM_uint32 (*func)(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
503 } krb5_gssspi_set_cred_option_ops[] = {
504 {
505 {GSS_KRB5_COPY_CCACHE_OID_LENGTH, GSS_KRB5_COPY_CCACHE_OID},
506 gss_krb5int_copy_ccache
507 },
508 {
509 {GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID},
510 gss_krb5int_set_allowable_enctypes
511 },
512 {
513 {GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
514 gss_krb5int_set_cred_rcache
515 },
516 {
517 {GSS_KRB5_IMPORT_CRED_OID_LENGTH, GSS_KRB5_IMPORT_CRED_OID},
518 gss_krb5int_import_cred
519 },
520 {
521 {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
522 no_ci_flags
523 },
524 };
525
526 static OM_uint32 KRB5_CALLCONV
krb5_gssspi_set_cred_option(OM_uint32 * minor_status,gss_cred_id_t * cred_handle,const gss_OID desired_object,const gss_buffer_t value)527 krb5_gssspi_set_cred_option(OM_uint32 *minor_status,
528 gss_cred_id_t *cred_handle,
529 const gss_OID desired_object,
530 const gss_buffer_t value)
531 {
532 OM_uint32 major_status = GSS_S_FAILURE;
533 size_t i;
534
535 if (minor_status == NULL)
536 return GSS_S_CALL_INACCESSIBLE_WRITE;
537
538 if (cred_handle == NULL)
539 return GSS_S_CALL_INACCESSIBLE_WRITE;
540
541 *minor_status = 0;
542
543 if (desired_object == GSS_C_NO_OID)
544 return GSS_S_CALL_INACCESSIBLE_READ;
545
546 if (*cred_handle != GSS_C_NO_CREDENTIAL) {
547 major_status = krb5_gss_validate_cred(minor_status, *cred_handle);
548 if (GSS_ERROR(major_status))
549 return major_status;
550 }
551
552 for (i = 0; i < sizeof(krb5_gssspi_set_cred_option_ops)/
553 sizeof(krb5_gssspi_set_cred_option_ops[0]); i++) {
554 if (g_OID_prefix_equal(desired_object, &krb5_gssspi_set_cred_option_ops[i].oid)) {
555 return (*krb5_gssspi_set_cred_option_ops[i].func)(minor_status,
556 cred_handle,
557 desired_object,
558 value);
559 }
560 }
561
562 *minor_status = EINVAL;
563
564 return GSS_S_UNAVAILABLE;
565 }
566
567 /*
568 * gssspi_mech_invoke() methods
569 */
570 static struct {
571 gss_OID_desc oid;
572 OM_uint32 (*func)(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
573 } krb5_gssspi_mech_invoke_ops[] = {
574 {
575 {GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID},
576 gss_krb5int_register_acceptor_identity
577 },
578 {
579 {GSS_KRB5_CCACHE_NAME_OID_LENGTH, GSS_KRB5_CCACHE_NAME_OID},
580 gss_krb5int_ccache_name
581 },
582 {
583 {GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID},
584 gss_krb5int_free_lucid_sec_context
585 },
586 #ifndef _WIN32
587 {
588 {GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
589 krb5int_gss_use_kdc_context
590 },
591 #endif
592 };
593
594 static OM_uint32 KRB5_CALLCONV
krb5_gssspi_mech_invoke(OM_uint32 * minor_status,const gss_OID desired_mech,const gss_OID desired_object,gss_buffer_t value)595 krb5_gssspi_mech_invoke (OM_uint32 *minor_status,
596 const gss_OID desired_mech,
597 const gss_OID desired_object,
598 gss_buffer_t value)
599 {
600 size_t i;
601
602 if (minor_status == NULL)
603 return GSS_S_CALL_INACCESSIBLE_WRITE;
604
605 *minor_status = 0;
606
607 if (desired_mech == GSS_C_NO_OID)
608 return GSS_S_BAD_MECH;
609
610 if (desired_object == GSS_C_NO_OID)
611 return GSS_S_CALL_INACCESSIBLE_READ;
612
613 for (i = 0; i < sizeof(krb5_gssspi_mech_invoke_ops)/
614 sizeof(krb5_gssspi_mech_invoke_ops[0]); i++) {
615 if (g_OID_prefix_equal(desired_object, &krb5_gssspi_mech_invoke_ops[i].oid)) {
616 return (*krb5_gssspi_mech_invoke_ops[i].func)(minor_status,
617 desired_mech,
618 desired_object,
619 value);
620 }
621 }
622
623 *minor_status = EINVAL;
624
625 return GSS_S_UNAVAILABLE;
626 }
627
628 #define GS2_KRB5_SASL_NAME "GS2-KRB5"
629 #define GS2_KRB5_SASL_NAME_LEN (sizeof(GS2_KRB5_SASL_NAME) - 1)
630
631 #define GS2_IAKERB_SASL_NAME "GS2-IAKERB"
632 #define GS2_IAKERB_SASL_NAME_LEN (sizeof(GS2_IAKERB_SASL_NAME) - 1)
633
634 static OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_mech_for_saslname(OM_uint32 * minor_status,const gss_buffer_t sasl_mech_name,gss_OID * mech_type)635 krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
636 const gss_buffer_t sasl_mech_name,
637 gss_OID *mech_type)
638 {
639 *minor_status = 0;
640
641 if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN &&
642 memcmp(sasl_mech_name->value,
643 GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) {
644 if (mech_type != NULL)
645 *mech_type = (gss_OID)gss_mech_krb5;
646 return GSS_S_COMPLETE;
647 } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN &&
648 memcmp(sasl_mech_name->value,
649 GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) {
650 if (mech_type != NULL)
651 *mech_type = (gss_OID)gss_mech_iakerb;
652 return GSS_S_COMPLETE;
653 }
654
655 return GSS_S_BAD_MECH;
656 }
657
658 static OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_saslname_for_mech(OM_uint32 * minor_status,const gss_OID desired_mech,gss_buffer_t sasl_mech_name,gss_buffer_t mech_name,gss_buffer_t mech_description)659 krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
660 const gss_OID desired_mech,
661 gss_buffer_t sasl_mech_name,
662 gss_buffer_t mech_name,
663 gss_buffer_t mech_description)
664 {
665 if (g_OID_equal(desired_mech, gss_mech_iakerb)) {
666 if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) ||
667 !g_make_string_buffer("iakerb", mech_name) ||
668 !g_make_string_buffer("Initial and Pass Through Authentication "
669 "Kerberos Mechanism (IAKERB)",
670 mech_description))
671 goto fail;
672 } else {
673 if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) ||
674 !g_make_string_buffer("krb5", mech_name) ||
675 !g_make_string_buffer("Kerberos 5 GSS-API Mechanism",
676 mech_description))
677 goto fail;
678 }
679
680 *minor_status = 0;
681 return GSS_S_COMPLETE;
682
683 fail:
684 *minor_status = ENOMEM;
685 return GSS_S_FAILURE;
686 }
687
688 static OM_uint32 KRB5_CALLCONV
krb5_gss_inquire_attrs_for_mech(OM_uint32 * minor_status,gss_const_OID mech,gss_OID_set * mech_attrs,gss_OID_set * known_mech_attrs)689 krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
690 gss_const_OID mech,
691 gss_OID_set *mech_attrs,
692 gss_OID_set *known_mech_attrs)
693 {
694 OM_uint32 major, tmpMinor;
695
696 if (mech_attrs == NULL) {
697 *minor_status = 0;
698 return GSS_S_COMPLETE;
699 }
700
701 major = gss_create_empty_oid_set(minor_status, mech_attrs);
702 if (GSS_ERROR(major))
703 goto cleanup;
704
705 #define MA_SUPPORTED(ma) do { \
706 major = gss_add_oid_set_member(minor_status, (gss_OID)ma, \
707 mech_attrs); \
708 if (GSS_ERROR(major)) \
709 goto cleanup; \
710 } while (0)
711
712 MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
713 MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
714 MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
715 MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
716 MA_SUPPORTED(GSS_C_MA_DELEG_CRED);
717 MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
718 MA_SUPPORTED(GSS_C_MA_CONF_PROT);
719 MA_SUPPORTED(GSS_C_MA_MIC);
720 MA_SUPPORTED(GSS_C_MA_WRAP);
721 MA_SUPPORTED(GSS_C_MA_PROT_READY);
722 MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
723 MA_SUPPORTED(GSS_C_MA_OOS_DET);
724 MA_SUPPORTED(GSS_C_MA_CBINDINGS);
725 MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
726
727 if (g_OID_equal(mech, gss_mech_iakerb)) {
728 MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
729 MA_SUPPORTED(GSS_C_MA_NOT_DFLT_MECH);
730 } else if (!g_OID_equal(mech, gss_mech_krb5)) {
731 MA_SUPPORTED(GSS_C_MA_DEPRECATED);
732 }
733
734 cleanup:
735 if (GSS_ERROR(major))
736 gss_release_oid_set(&tmpMinor, mech_attrs);
737
738 return major;
739 }
740
741 static OM_uint32 KRB5_CALLCONV
krb5_gss_localname(OM_uint32 * minor,const gss_name_t pname,const gss_const_OID mech_type,gss_buffer_t localname)742 krb5_gss_localname(OM_uint32 *minor,
743 const gss_name_t pname,
744 const gss_const_OID mech_type,
745 gss_buffer_t localname)
746 {
747 krb5_context context;
748 krb5_error_code code;
749 krb5_gss_name_t kname;
750 char lname[BUFSIZ];
751
752 code = krb5_gss_init_context(&context);
753 if (code != 0) {
754 *minor = code;
755 return GSS_S_FAILURE;
756 }
757
758 kname = (krb5_gss_name_t)pname;
759
760 code = krb5_aname_to_localname(context, kname->princ,
761 sizeof(lname), lname);
762 if (code != 0) {
763 *minor = KRB5_NO_LOCALNAME;
764 krb5_free_context(context);
765 return GSS_S_FAILURE;
766 }
767
768
769 krb5_free_context(context);
770 localname->value = gssalloc_strdup(lname);
771 localname->length = strlen(lname);
772
773 return GSS_S_COMPLETE;
774 }
775
776
777 static OM_uint32 KRB5_CALLCONV
krb5_gss_authorize_localname(OM_uint32 * minor,const gss_name_t pname,gss_const_buffer_t local_user,gss_const_OID name_type)778 krb5_gss_authorize_localname(OM_uint32 *minor,
779 const gss_name_t pname,
780 gss_const_buffer_t local_user,
781 gss_const_OID name_type)
782 {
783 krb5_context context;
784 krb5_error_code code;
785 krb5_gss_name_t kname;
786 char *user;
787 int user_ok;
788
789 if (name_type != GSS_C_NO_OID &&
790 !g_OID_equal(name_type, GSS_C_NT_USER_NAME)) {
791 return GSS_S_BAD_NAMETYPE;
792 }
793
794 kname = (krb5_gss_name_t)pname;
795
796 code = krb5_gss_init_context(&context);
797 if (code != 0) {
798 *minor = code;
799 return GSS_S_FAILURE;
800 }
801
802 user = k5memdup0(local_user->value, local_user->length, &code);
803 if (user == NULL) {
804 *minor = code;
805 krb5_free_context(context);
806 return GSS_S_FAILURE;
807 }
808
809 user_ok = krb5_kuserok(context, kname->princ, user);
810
811 free(user);
812 krb5_free_context(context);
813
814 *minor = 0;
815 return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED;
816 }
817
818 static struct gss_config krb5_mechanism = {
819 { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
820 NULL,
821 krb5_gss_acquire_cred,
822 krb5_gss_release_cred,
823 krb5_gss_init_sec_context,
824 #ifdef LEAN_CLIENT
825 NULL,
826 #else
827 krb5_gss_accept_sec_context,
828 #endif
829 krb5_gss_process_context_token,
830 krb5_gss_delete_sec_context,
831 krb5_gss_context_time,
832 krb5_gss_get_mic,
833 krb5_gss_verify_mic,
834 #if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
835 NULL,
836 #else
837 krb5_gss_wrap,
838 #endif
839 #if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
840 NULL,
841 #else
842 krb5_gss_unwrap,
843 #endif
844 krb5_gss_display_status,
845 krb5_gss_indicate_mechs,
846 krb5_gss_compare_name,
847 krb5_gss_display_name,
848 krb5_gss_import_name,
849 krb5_gss_release_name,
850 krb5_gss_inquire_cred,
851 NULL, /* add_cred */
852 #ifdef LEAN_CLIENT
853 NULL,
854 NULL,
855 #else
856 krb5_gss_export_sec_context,
857 krb5_gss_import_sec_context,
858 #endif
859 krb5_gss_inquire_cred_by_mech,
860 krb5_gss_inquire_names_for_mech,
861 krb5_gss_inquire_context,
862 krb5_gss_internal_release_oid,
863 krb5_gss_wrap_size_limit,
864 krb5_gss_localname,
865
866 krb5_gss_authorize_localname,
867 krb5_gss_export_name,
868 krb5_gss_duplicate_name,
869 krb5_gss_store_cred,
870 krb5_gss_inquire_sec_context_by_oid,
871 krb5_gss_inquire_cred_by_oid,
872 krb5_gss_set_sec_context_option,
873 krb5_gssspi_set_cred_option,
874 krb5_gssspi_mech_invoke,
875 NULL, /* wrap_aead */
876 NULL, /* unwrap_aead */
877 krb5_gss_wrap_iov,
878 krb5_gss_unwrap_iov,
879 krb5_gss_wrap_iov_length,
880 NULL, /* complete_auth_token */
881 krb5_gss_acquire_cred_impersonate_name,
882 NULL, /* krb5_gss_add_cred_impersonate_name */
883 NULL, /* display_name_ext */
884 krb5_gss_inquire_name,
885 krb5_gss_get_name_attribute,
886 krb5_gss_set_name_attribute,
887 krb5_gss_delete_name_attribute,
888 krb5_gss_export_name_composite,
889 krb5_gss_map_name_to_any,
890 krb5_gss_release_any_name_mapping,
891 krb5_gss_pseudo_random,
892 NULL, /* set_neg_mechs */
893 krb5_gss_inquire_saslname_for_mech,
894 krb5_gss_inquire_mech_for_saslname,
895 krb5_gss_inquire_attrs_for_mech,
896 krb5_gss_acquire_cred_from,
897 krb5_gss_store_cred_into,
898 krb5_gss_acquire_cred_with_password,
899 krb5_gss_export_cred,
900 krb5_gss_import_cred,
901 NULL, /* import_sec_context_by_mech */
902 NULL, /* import_name_by_mech */
903 NULL, /* import_cred_by_mech */
904 krb5_gss_get_mic_iov,
905 krb5_gss_verify_mic_iov,
906 krb5_gss_get_mic_iov_length,
907 };
908
909 /* Functions which use security contexts or acquire creds are IAKERB-specific;
910 * other functions can borrow from the krb5 mech. */
911 static struct gss_config iakerb_mechanism = {
912 { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
913 NULL,
914 iakerb_gss_acquire_cred,
915 krb5_gss_release_cred,
916 iakerb_gss_init_sec_context,
917 #ifdef LEAN_CLIENT
918 NULL,
919 #else
920 iakerb_gss_accept_sec_context,
921 #endif
922 iakerb_gss_process_context_token,
923 iakerb_gss_delete_sec_context,
924 iakerb_gss_context_time,
925 iakerb_gss_get_mic,
926 iakerb_gss_verify_mic,
927 #if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
928 NULL,
929 #else
930 iakerb_gss_wrap,
931 #endif
932 #if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
933 NULL,
934 #else
935 iakerb_gss_unwrap,
936 #endif
937 krb5_gss_display_status,
938 krb5_gss_indicate_mechs,
939 krb5_gss_compare_name,
940 krb5_gss_display_name,
941 krb5_gss_import_name,
942 krb5_gss_release_name,
943 krb5_gss_inquire_cred,
944 NULL, /* add_cred */
945 #ifdef LEAN_CLIENT
946 NULL,
947 NULL,
948 #else
949 iakerb_gss_export_sec_context,
950 iakerb_gss_import_sec_context,
951 #endif
952 krb5_gss_inquire_cred_by_mech,
953 krb5_gss_inquire_names_for_mech,
954 iakerb_gss_inquire_context,
955 krb5_gss_internal_release_oid,
956 iakerb_gss_wrap_size_limit,
957 krb5_gss_localname,
958 krb5_gss_authorize_localname,
959 krb5_gss_export_name,
960 krb5_gss_duplicate_name,
961 krb5_gss_store_cred,
962 iakerb_gss_inquire_sec_context_by_oid,
963 krb5_gss_inquire_cred_by_oid,
964 iakerb_gss_set_sec_context_option,
965 krb5_gssspi_set_cred_option,
966 krb5_gssspi_mech_invoke,
967 NULL, /* wrap_aead */
968 NULL, /* unwrap_aead */
969 iakerb_gss_wrap_iov,
970 iakerb_gss_unwrap_iov,
971 iakerb_gss_wrap_iov_length,
972 NULL, /* complete_auth_token */
973 NULL, /* acquire_cred_impersonate_name */
974 NULL, /* add_cred_impersonate_name */
975 NULL, /* display_name_ext */
976 krb5_gss_inquire_name,
977 krb5_gss_get_name_attribute,
978 krb5_gss_set_name_attribute,
979 krb5_gss_delete_name_attribute,
980 krb5_gss_export_name_composite,
981 krb5_gss_map_name_to_any,
982 krb5_gss_release_any_name_mapping,
983 iakerb_gss_pseudo_random,
984 NULL, /* set_neg_mechs */
985 krb5_gss_inquire_saslname_for_mech,
986 krb5_gss_inquire_mech_for_saslname,
987 krb5_gss_inquire_attrs_for_mech,
988 iakerb_gss_acquire_cred_from,
989 krb5_gss_store_cred_into,
990 iakerb_gss_acquire_cred_with_password,
991 krb5_gss_export_cred,
992 krb5_gss_import_cred,
993 NULL, /* import_sec_context_by_mech */
994 NULL, /* import_name_by_mech */
995 NULL, /* import_cred_by_mech */
996 iakerb_gss_get_mic_iov,
997 iakerb_gss_verify_mic_iov,
998 iakerb_gss_get_mic_iov_length,
999 };
1000
1001 #ifdef _GSS_STATIC_LINK
1002 #include "mglueP.h"
gss_iakerbmechglue_init(void)1003 static int gss_iakerbmechglue_init(void)
1004 {
1005 struct gss_mech_config mech_iakerb;
1006
1007 memset(&mech_iakerb, 0, sizeof(mech_iakerb));
1008 mech_iakerb.mech = &iakerb_mechanism;
1009
1010 mech_iakerb.mechNameStr = "iakerb";
1011 mech_iakerb.mech_type = (gss_OID)gss_mech_iakerb;
1012 gssint_register_mechinfo(&mech_iakerb);
1013
1014 return 0;
1015 }
1016
gss_krb5mechglue_init(void)1017 static int gss_krb5mechglue_init(void)
1018 {
1019 struct gss_mech_config mech_krb5;
1020
1021 memset(&mech_krb5, 0, sizeof(mech_krb5));
1022 mech_krb5.mech = &krb5_mechanism;
1023
1024 mech_krb5.mechNameStr = "kerberos_v5";
1025 mech_krb5.mech_type = (gss_OID)gss_mech_krb5;
1026 gssint_register_mechinfo(&mech_krb5);
1027
1028 mech_krb5.mechNameStr = "kerberos_v5_old";
1029 mech_krb5.mech_type = (gss_OID)gss_mech_krb5_old;
1030 gssint_register_mechinfo(&mech_krb5);
1031
1032 mech_krb5.mechNameStr = "mskrb";
1033 mech_krb5.mech_type = (gss_OID)gss_mech_krb5_wrong;
1034 gssint_register_mechinfo(&mech_krb5);
1035
1036 return 0;
1037 }
1038 #else
1039 MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
1040 MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
1041
1042 gss_mechanism KRB5_CALLCONV
gss_mech_initialize(void)1043 gss_mech_initialize(void)
1044 {
1045 return &krb5_mechanism;
1046 }
1047 #endif /* _GSS_STATIC_LINK */
1048
gss_krb5int_lib_init(void)1049 int gss_krb5int_lib_init(void)
1050 {
1051 int err;
1052
1053 #ifdef SHOW_INITFINI_FUNCS
1054 printf("gss_krb5int_lib_init\n");
1055 #endif
1056
1057 add_error_table(&et_k5g_error_table);
1058
1059 #ifndef LEAN_CLIENT
1060 err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
1061 if (err)
1062 return err;
1063 #endif /* LEAN_CLIENT */
1064 err = k5_key_register(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, free);
1065 if (err)
1066 return err;
1067 err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free);
1068 if (err)
1069 return err;
1070 err = k5_key_register(K5_KEY_GSS_KRB5_ERROR_MESSAGE,
1071 krb5_gss_delete_error_info);
1072 if (err)
1073 return err;
1074 #ifndef _WIN32
1075 err = k5_mutex_finish_init(&kg_kdc_flag_mutex);
1076 if (err)
1077 return err;
1078 err = k5_mutex_finish_init(&kg_vdb.mutex);
1079 if (err)
1080 return err;
1081 #endif
1082 #ifdef _GSS_STATIC_LINK
1083 err = gss_krb5mechglue_init();
1084 if (err)
1085 return err;
1086 err = gss_iakerbmechglue_init();
1087 if (err)
1088 return err;
1089 #endif
1090
1091 return 0;
1092 }
1093
gss_krb5int_lib_fini(void)1094 void gss_krb5int_lib_fini(void)
1095 {
1096 #ifndef _GSS_STATIC_LINK
1097 if (!INITIALIZER_RAN(gss_krb5int_lib_init) || PROGRAM_EXITING()) {
1098 # ifdef SHOW_INITFINI_FUNCS
1099 printf("gss_krb5int_lib_fini: skipping\n");
1100 # endif
1101 return;
1102 }
1103 #endif
1104 #ifdef SHOW_INITFINI_FUNCS
1105 printf("gss_krb5int_lib_fini\n");
1106 #endif
1107 remove_error_table(&et_k5g_error_table);
1108
1109 k5_key_delete(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
1110 k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
1111 k5_key_delete(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
1112 k5_mutex_destroy(&kg_vdb.mutex);
1113 #ifndef _WIN32
1114 k5_mutex_destroy(&kg_kdc_flag_mutex);
1115 #endif
1116 #ifndef LEAN_CLIENT
1117 k5_mutex_destroy(&gssint_krb5_keytab_lock);
1118 #endif /* LEAN_CLIENT */
1119 }
1120
1121 #ifdef _GSS_STATIC_LINK
1122 extern OM_uint32 gssint_lib_init(void);
1123 #endif
1124
gss_krb5int_initialize_library(void)1125 OM_uint32 gss_krb5int_initialize_library (void)
1126 {
1127 #ifdef _GSS_STATIC_LINK
1128 return gssint_mechglue_initialize_library();
1129 #else
1130 return CALL_INIT_FUNCTION(gss_krb5int_lib_init);
1131 #endif
1132 }
1133