xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/gssapi_krb5.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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