xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/gssapi_krb5.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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 /** default credential support */
192 
193 /*
194  * init_sec_context() will explicitly re-acquire default credentials,
195  * so handling the expiration/invalidation condition here isn't needed.
196  */
197 OM_uint32
kg_get_defcred(OM_uint32 * minor_status,gss_cred_id_t * cred)198 kg_get_defcred(OM_uint32 *minor_status, gss_cred_id_t *cred)
199 {
200     OM_uint32 major;
201 
202     if ((major = krb5_gss_acquire_cred(minor_status,
203                                        (gss_name_t) NULL, GSS_C_INDEFINITE,
204                                        GSS_C_NULL_OID_SET, GSS_C_INITIATE,
205                                        cred, NULL, NULL)) && GSS_ERROR(major)) {
206         return(major);
207     }
208     *minor_status = 0;
209     return(GSS_S_COMPLETE);
210 }
211 
212 OM_uint32
kg_sync_ccache_name(krb5_context context,OM_uint32 * minor_status)213 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
214 {
215     OM_uint32 err = 0;
216 
217     /*
218      * Sync up the context ccache name with the GSSAPI ccache name.
219      * If kg_ccache_name is NULL -- normal unless someone has called
220      * gss_krb5_ccache_name() -- then the system default ccache will
221      * be picked up and used by resetting the context default ccache.
222      * This is needed for platforms which support multiple ccaches.
223      */
224 
225     if (!err) {
226         /* if NULL, resets the context default ccache */
227         err = krb5_cc_set_default_name(context,
228                                        (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
229     }
230 
231     *minor_status = err;
232     return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
233 }
234 
235 /* This function returns whether or not the caller set a cccache name.  Used by
236  * gss_acquire_cred to figure out if the caller wants to only look at this
237  * ccache or search the cache collection for the desired name */
238 OM_uint32
kg_caller_provided_ccache_name(OM_uint32 * minor_status,int * out_caller_provided_name)239 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
240                                 int *out_caller_provided_name)
241 {
242     if (out_caller_provided_name) {
243         *out_caller_provided_name =
244             (k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME) != NULL);
245     }
246 
247     *minor_status = 0;
248     return GSS_S_COMPLETE;
249 }
250 
251 OM_uint32
kg_get_ccache_name(OM_uint32 * minor_status,char ** out_name)252 kg_get_ccache_name(OM_uint32 *minor_status, char **out_name)
253 {
254     char *kg_ccache_name;
255     const char *def_name;
256     OM_uint32 err;
257     krb5_context context;
258 
259     *out_name = NULL;
260 
261     kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
262     if (kg_ccache_name != NULL) {
263         *out_name = strdup(kg_ccache_name);
264         err = (*out_name == NULL) ? ENOMEM : 0;
265     } else {
266         /* Use the default ccache name. */
267         err = krb5_gss_init_context(&context);
268         if (err)
269             goto cleanup;
270         def_name = krb5_cc_default_name(context);
271         *out_name = (def_name != NULL) ? strdup(def_name) : NULL;
272         err = (*out_name == NULL) ? ENOMEM : 0;
273         krb5_free_context(context);
274     }
275 
276 cleanup:
277     *minor_status = err;
278     return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
279 }
280 
281 OM_uint32
kg_set_ccache_name(OM_uint32 * minor_status,const char * name)282 kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
283 {
284     char *new_name = NULL;
285     char *swap = NULL;
286     char *kg_ccache_name;
287     krb5_error_code kerr;
288 
289     if (name) {
290         new_name = strdup(name);
291         if (new_name == NULL) {
292             *minor_status = ENOMEM;
293             return GSS_S_FAILURE;
294         }
295     }
296 
297     kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
298     swap = kg_ccache_name;
299     kg_ccache_name = new_name;
300     new_name = swap;
301     kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
302     if (kerr != 0) {
303         /* Can't store, so free up the storage.  */
304         free(kg_ccache_name);
305         /* ??? free(new_name); */
306         *minor_status = kerr;
307         return GSS_S_FAILURE;
308     }
309 
310     free (new_name);
311     *minor_status = 0;
312     return GSS_S_COMPLETE;
313 }
314 
315 #define g_OID_prefix_equal(o1, o2)                                      \
316     (((o1)->length >= (o2)->length) &&                                  \
317      (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
318 
319 /*
320  * gss_inquire_sec_context_by_oid() methods
321  */
322 static struct {
323     gss_OID_desc oid;
324     OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
325 } krb5_gss_inquire_sec_context_by_oid_ops[] = {
326     {
327         {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
328         gss_krb5int_get_tkt_flags
329     },
330     {
331         {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
332         gss_krb5int_extract_authz_data_from_sec_context
333     },
334     {
335         {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
336         gss_krb5int_inq_sspi_session_key
337     },
338     {
339         {GSS_KRB5_INQ_ODBC_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_ODBC_SESSION_KEY_OID},
340         gss_krb5int_inq_odbc_session_key
341     },
342     {
343         {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
344         gss_krb5int_export_lucid_sec_context
345     },
346     {
347         {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
348         gss_krb5int_extract_authtime_from_sec_context
349     },
350     {
351         {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID},
352         gss_krb5int_sec_context_sasl_ssf
353     }
354 };
355 
356 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)357 krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
358                                      const gss_ctx_id_t context_handle,
359                                      const gss_OID desired_object,
360                                      gss_buffer_set_t *data_set)
361 {
362     krb5_gss_ctx_id_rec *ctx;
363     size_t i;
364 
365     if (minor_status == NULL)
366         return GSS_S_CALL_INACCESSIBLE_WRITE;
367 
368     *minor_status = 0;
369 
370     if (desired_object == GSS_C_NO_OID)
371         return GSS_S_CALL_INACCESSIBLE_READ;
372 
373     if (data_set == NULL)
374         return GSS_S_CALL_INACCESSIBLE_WRITE;
375 
376     *data_set = GSS_C_NO_BUFFER_SET;
377 
378     ctx = (krb5_gss_ctx_id_rec *) context_handle;
379 
380     if (ctx->terminated || !ctx->established)
381         return GSS_S_NO_CONTEXT;
382 
383     for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
384              sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
385         if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
386             return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
387                                                                       context_handle,
388                                                                       desired_object,
389                                                                       data_set);
390         }
391     }
392 
393     *minor_status = EINVAL;
394 
395     return GSS_S_UNAVAILABLE;
396 }
397 
398 /*
399  * gss_inquire_cred_by_oid() methods
400  */
401 
402 static struct {
403     gss_OID_desc oid;
404     OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *);
405 } krb5_gss_inquire_cred_by_oid_ops[] = {
406     {
407         {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
408         gss_krb5int_get_cred_impersonator
409     }
410 };
411 
412 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)413 krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
414                              const gss_cred_id_t cred_handle,
415                              const gss_OID desired_object,
416                              gss_buffer_set_t *data_set)
417 {
418     OM_uint32 major_status = GSS_S_FAILURE;
419     size_t i;
420 
421     if (minor_status == NULL)
422         return GSS_S_CALL_INACCESSIBLE_WRITE;
423 
424     *minor_status = 0;
425 
426     if (desired_object == GSS_C_NO_OID)
427         return GSS_S_CALL_INACCESSIBLE_READ;
428 
429     if (data_set == NULL)
430         return GSS_S_CALL_INACCESSIBLE_WRITE;
431 
432     *data_set = GSS_C_NO_BUFFER_SET;
433     if (cred_handle == GSS_C_NO_CREDENTIAL) {
434         *minor_status = (OM_uint32)KRB5_NOCREDS_SUPPLIED;
435         return GSS_S_NO_CRED;
436     }
437 
438     major_status = krb5_gss_validate_cred(minor_status, cred_handle);
439     if (GSS_ERROR(major_status))
440         return major_status;
441 
442     for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/
443              sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) {
444         if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) {
445             return (*krb5_gss_inquire_cred_by_oid_ops[i].func)(minor_status,
446                                                                cred_handle,
447                                                                desired_object,
448                                                                data_set);
449         }
450     }
451 
452     *minor_status = EINVAL;
453 
454     return GSS_S_UNAVAILABLE;
455 }
456 
457 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)458 krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
459                                  gss_ctx_id_t *context_handle,
460                                  const gss_OID desired_object,
461                                  const gss_buffer_t value)
462 {
463     if (minor_status == NULL)
464         return GSS_S_CALL_INACCESSIBLE_WRITE;
465 
466     *minor_status = 0;
467 
468     if (context_handle == NULL)
469         return GSS_S_CALL_INACCESSIBLE_READ;
470 
471     if (desired_object == GSS_C_NO_OID)
472         return GSS_S_CALL_INACCESSIBLE_READ;
473 
474     *minor_status = EINVAL;
475 
476     return GSS_S_UNAVAILABLE;
477 }
478 
479 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)480 no_ci_flags(OM_uint32 *minor_status,
481             gss_cred_id_t *cred_handle,
482             const gss_OID desired_oid,
483             const gss_buffer_t value)
484 {
485     krb5_gss_cred_id_t cred;
486 
487     cred = (krb5_gss_cred_id_t) *cred_handle;
488     cred->suppress_ci_flags = 1;
489 
490     *minor_status = 0;
491     return GSS_S_COMPLETE;
492 }
493 /*
494  * gssspi_set_cred_option() methods
495  */
496 static struct {
497     gss_OID_desc oid;
498     OM_uint32 (*func)(OM_uint32 *, gss_cred_id_t *, const gss_OID, const gss_buffer_t);
499 } krb5_gssspi_set_cred_option_ops[] = {
500     {
501         {GSS_KRB5_COPY_CCACHE_OID_LENGTH, GSS_KRB5_COPY_CCACHE_OID},
502         gss_krb5int_copy_ccache
503     },
504     {
505         {GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID},
506         gss_krb5int_set_allowable_enctypes
507     },
508     {
509         {GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID},
510         gss_krb5int_set_cred_rcache
511     },
512     {
513         {GSS_KRB5_IMPORT_CRED_OID_LENGTH, GSS_KRB5_IMPORT_CRED_OID},
514         gss_krb5int_import_cred
515     },
516     {
517         {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
518         no_ci_flags
519     },
520 };
521 
522 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)523 krb5_gssspi_set_cred_option(OM_uint32 *minor_status,
524                             gss_cred_id_t *cred_handle,
525                             const gss_OID desired_object,
526                             const gss_buffer_t value)
527 {
528     OM_uint32 major_status = GSS_S_FAILURE;
529     size_t i;
530 
531     if (minor_status == NULL)
532         return GSS_S_CALL_INACCESSIBLE_WRITE;
533 
534     if (cred_handle == NULL)
535         return GSS_S_CALL_INACCESSIBLE_WRITE;
536 
537     *minor_status = 0;
538 
539     if (desired_object == GSS_C_NO_OID)
540         return GSS_S_CALL_INACCESSIBLE_READ;
541 
542     if (*cred_handle != GSS_C_NO_CREDENTIAL) {
543         major_status = krb5_gss_validate_cred(minor_status, *cred_handle);
544         if (GSS_ERROR(major_status))
545             return major_status;
546     }
547 
548     for (i = 0; i < sizeof(krb5_gssspi_set_cred_option_ops)/
549              sizeof(krb5_gssspi_set_cred_option_ops[0]); i++) {
550         if (g_OID_prefix_equal(desired_object, &krb5_gssspi_set_cred_option_ops[i].oid)) {
551             return (*krb5_gssspi_set_cred_option_ops[i].func)(minor_status,
552                                                               cred_handle,
553                                                               desired_object,
554                                                               value);
555         }
556     }
557 
558     *minor_status = EINVAL;
559 
560     return GSS_S_UNAVAILABLE;
561 }
562 
563 /*
564  * gssspi_mech_invoke() methods
565  */
566 static struct {
567     gss_OID_desc oid;
568     OM_uint32 (*func)(OM_uint32 *, const gss_OID, const gss_OID, gss_buffer_t);
569 } krb5_gssspi_mech_invoke_ops[] = {
570     {
571         {GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID_LENGTH, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_OID},
572         gss_krb5int_register_acceptor_identity
573     },
574     {
575         {GSS_KRB5_CCACHE_NAME_OID_LENGTH, GSS_KRB5_CCACHE_NAME_OID},
576         gss_krb5int_ccache_name
577     },
578     {
579         {GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_FREE_LUCID_SEC_CONTEXT_OID},
580         gss_krb5int_free_lucid_sec_context
581     },
582 #ifndef _WIN32
583     {
584         {GSS_KRB5_USE_KDC_CONTEXT_OID_LENGTH, GSS_KRB5_USE_KDC_CONTEXT_OID},
585         krb5int_gss_use_kdc_context
586     },
587 #endif
588 };
589 
590 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)591 krb5_gssspi_mech_invoke (OM_uint32 *minor_status,
592                          const gss_OID desired_mech,
593                          const gss_OID desired_object,
594                          gss_buffer_t value)
595 {
596     size_t i;
597 
598     if (minor_status == NULL)
599         return GSS_S_CALL_INACCESSIBLE_WRITE;
600 
601     *minor_status = 0;
602 
603     if (desired_mech == GSS_C_NO_OID)
604         return GSS_S_BAD_MECH;
605 
606     if (desired_object == GSS_C_NO_OID)
607         return GSS_S_CALL_INACCESSIBLE_READ;
608 
609     for (i = 0; i < sizeof(krb5_gssspi_mech_invoke_ops)/
610              sizeof(krb5_gssspi_mech_invoke_ops[0]); i++) {
611         if (g_OID_prefix_equal(desired_object, &krb5_gssspi_mech_invoke_ops[i].oid)) {
612             return (*krb5_gssspi_mech_invoke_ops[i].func)(minor_status,
613                                                           desired_mech,
614                                                           desired_object,
615                                                           value);
616         }
617     }
618 
619     *minor_status = EINVAL;
620 
621     return GSS_S_UNAVAILABLE;
622 }
623 
624 #define GS2_KRB5_SASL_NAME        "GS2-KRB5"
625 #define GS2_KRB5_SASL_NAME_LEN    (sizeof(GS2_KRB5_SASL_NAME) - 1)
626 
627 #define GS2_IAKERB_SASL_NAME      "GS2-IAKERB"
628 #define GS2_IAKERB_SASL_NAME_LEN  (sizeof(GS2_IAKERB_SASL_NAME) - 1)
629 
630 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)631 krb5_gss_inquire_mech_for_saslname(OM_uint32 *minor_status,
632                                    const gss_buffer_t sasl_mech_name,
633                                    gss_OID *mech_type)
634 {
635     *minor_status = 0;
636 
637     if (sasl_mech_name->length == GS2_KRB5_SASL_NAME_LEN &&
638         memcmp(sasl_mech_name->value,
639                GS2_KRB5_SASL_NAME, GS2_KRB5_SASL_NAME_LEN) == 0) {
640         if (mech_type != NULL)
641             *mech_type = (gss_OID)gss_mech_krb5;
642         return GSS_S_COMPLETE;
643     } else if (sasl_mech_name->length == GS2_IAKERB_SASL_NAME_LEN &&
644                memcmp(sasl_mech_name->value,
645                       GS2_IAKERB_SASL_NAME, GS2_IAKERB_SASL_NAME_LEN) == 0) {
646         if (mech_type != NULL)
647             *mech_type = (gss_OID)gss_mech_iakerb;
648         return GSS_S_COMPLETE;
649     }
650 
651     return GSS_S_BAD_MECH;
652 }
653 
654 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)655 krb5_gss_inquire_saslname_for_mech(OM_uint32 *minor_status,
656                                    const gss_OID desired_mech,
657                                    gss_buffer_t sasl_mech_name,
658                                    gss_buffer_t mech_name,
659                                    gss_buffer_t mech_description)
660 {
661     if (g_OID_equal(desired_mech, gss_mech_iakerb)) {
662         if (!g_make_string_buffer(GS2_IAKERB_SASL_NAME, sasl_mech_name) ||
663             !g_make_string_buffer("iakerb", mech_name) ||
664             !g_make_string_buffer("Initial and Pass Through Authentication "
665                                   "Kerberos Mechanism (IAKERB)",
666                                   mech_description))
667             goto fail;
668     } else {
669         if (!g_make_string_buffer(GS2_KRB5_SASL_NAME, sasl_mech_name) ||
670             !g_make_string_buffer("krb5", mech_name) ||
671             !g_make_string_buffer("Kerberos 5 GSS-API Mechanism",
672                                   mech_description))
673             goto fail;
674     }
675 
676     *minor_status = 0;
677     return GSS_S_COMPLETE;
678 
679 fail:
680     *minor_status = ENOMEM;
681     return GSS_S_FAILURE;
682 }
683 
684 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)685 krb5_gss_inquire_attrs_for_mech(OM_uint32 *minor_status,
686                                 gss_const_OID mech,
687                                 gss_OID_set *mech_attrs,
688                                 gss_OID_set *known_mech_attrs)
689 {
690     OM_uint32 major, tmpMinor;
691 
692     if (mech_attrs == NULL) {
693         *minor_status = 0;
694         return GSS_S_COMPLETE;
695     }
696 
697     major = gss_create_empty_oid_set(minor_status, mech_attrs);
698     if (GSS_ERROR(major))
699         goto cleanup;
700 
701 #define MA_SUPPORTED(ma)    do {                                        \
702         major = gss_add_oid_set_member(minor_status, (gss_OID)ma,       \
703                                        mech_attrs);                     \
704         if (GSS_ERROR(major))                                           \
705             goto cleanup;                                               \
706     } while (0)
707 
708     MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
709     MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
710     MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
711     MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
712     MA_SUPPORTED(GSS_C_MA_DELEG_CRED);
713     MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
714     MA_SUPPORTED(GSS_C_MA_CONF_PROT);
715     MA_SUPPORTED(GSS_C_MA_MIC);
716     MA_SUPPORTED(GSS_C_MA_WRAP);
717     MA_SUPPORTED(GSS_C_MA_PROT_READY);
718     MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
719     MA_SUPPORTED(GSS_C_MA_OOS_DET);
720     MA_SUPPORTED(GSS_C_MA_CBINDINGS);
721     MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
722 
723     if (g_OID_equal(mech, gss_mech_iakerb)) {
724         MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
725         MA_SUPPORTED(GSS_C_MA_NOT_DFLT_MECH);
726     } else if (!g_OID_equal(mech, gss_mech_krb5)) {
727         MA_SUPPORTED(GSS_C_MA_DEPRECATED);
728     }
729 
730 cleanup:
731     if (GSS_ERROR(major))
732         gss_release_oid_set(&tmpMinor, mech_attrs);
733 
734     return major;
735 }
736 
737 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)738 krb5_gss_localname(OM_uint32 *minor,
739                    const gss_name_t pname,
740                    const gss_const_OID mech_type,
741                    gss_buffer_t localname)
742 {
743     krb5_context context;
744     krb5_error_code code;
745     krb5_gss_name_t kname;
746     char lname[BUFSIZ];
747 
748     code = krb5_gss_init_context(&context);
749     if (code != 0) {
750         *minor = code;
751         return GSS_S_FAILURE;
752     }
753 
754     kname = (krb5_gss_name_t)pname;
755 
756     code = krb5_aname_to_localname(context, kname->princ,
757                                    sizeof(lname), lname);
758     if (code != 0) {
759         *minor = KRB5_NO_LOCALNAME;
760         krb5_free_context(context);
761         return GSS_S_FAILURE;
762     }
763 
764 
765     krb5_free_context(context);
766     localname->value = gssalloc_strdup(lname);
767     localname->length = strlen(lname);
768 
769     return GSS_S_COMPLETE;
770 }
771 
772 
773 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)774 krb5_gss_authorize_localname(OM_uint32 *minor,
775                              const gss_name_t pname,
776                              gss_const_buffer_t local_user,
777                              gss_const_OID name_type)
778 {
779     krb5_context context;
780     krb5_error_code code;
781     krb5_gss_name_t kname;
782     char *user;
783     int user_ok;
784 
785     if (name_type != GSS_C_NO_OID &&
786         !g_OID_equal(name_type, GSS_C_NT_USER_NAME)) {
787         return GSS_S_BAD_NAMETYPE;
788     }
789 
790     kname = (krb5_gss_name_t)pname;
791 
792     code = krb5_gss_init_context(&context);
793     if (code != 0) {
794         *minor = code;
795         return GSS_S_FAILURE;
796     }
797 
798     user = k5memdup0(local_user->value, local_user->length, &code);
799     if (user == NULL) {
800         *minor = code;
801         krb5_free_context(context);
802         return GSS_S_FAILURE;
803     }
804 
805     user_ok = krb5_kuserok(context, kname->princ, user);
806 
807     free(user);
808     krb5_free_context(context);
809 
810     *minor = 0;
811     return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED;
812 }
813 
814 static struct gss_config krb5_mechanism = {
815     { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
816     NULL,
817     krb5_gss_acquire_cred,
818     krb5_gss_release_cred,
819     krb5_gss_init_sec_context,
820 #ifdef LEAN_CLIENT
821     NULL,
822 #else
823     krb5_gss_accept_sec_context,
824 #endif
825     krb5_gss_process_context_token,
826     krb5_gss_delete_sec_context,
827     krb5_gss_context_time,
828     krb5_gss_get_mic,
829     krb5_gss_verify_mic,
830 #if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
831     NULL,
832 #else
833     krb5_gss_wrap,
834 #endif
835 #if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
836     NULL,
837 #else
838     krb5_gss_unwrap,
839 #endif
840     krb5_gss_display_status,
841     krb5_gss_indicate_mechs,
842     krb5_gss_compare_name,
843     krb5_gss_display_name,
844     krb5_gss_import_name,
845     krb5_gss_release_name,
846     krb5_gss_inquire_cred,
847     NULL,                /* add_cred */
848 #ifdef LEAN_CLIENT
849     NULL,
850     NULL,
851 #else
852     krb5_gss_export_sec_context,
853     krb5_gss_import_sec_context,
854 #endif
855     krb5_gss_inquire_cred_by_mech,
856     krb5_gss_inquire_names_for_mech,
857     krb5_gss_inquire_context,
858     krb5_gss_internal_release_oid,
859     krb5_gss_wrap_size_limit,
860     krb5_gss_localname,
861 
862     krb5_gss_authorize_localname,
863     krb5_gss_export_name,
864     krb5_gss_duplicate_name,
865     krb5_gss_store_cred,
866     krb5_gss_inquire_sec_context_by_oid,
867     krb5_gss_inquire_cred_by_oid,
868     krb5_gss_set_sec_context_option,
869     krb5_gssspi_set_cred_option,
870     krb5_gssspi_mech_invoke,
871     NULL,                /* wrap_aead */
872     NULL,                /* unwrap_aead */
873     krb5_gss_wrap_iov,
874     krb5_gss_unwrap_iov,
875     krb5_gss_wrap_iov_length,
876     NULL,               /* complete_auth_token */
877     krb5_gss_acquire_cred_impersonate_name,
878     NULL,               /* krb5_gss_add_cred_impersonate_name */
879     NULL,               /* display_name_ext */
880     krb5_gss_inquire_name,
881     krb5_gss_get_name_attribute,
882     krb5_gss_set_name_attribute,
883     krb5_gss_delete_name_attribute,
884     krb5_gss_export_name_composite,
885     krb5_gss_map_name_to_any,
886     krb5_gss_release_any_name_mapping,
887     krb5_gss_pseudo_random,
888     NULL,               /* set_neg_mechs */
889     krb5_gss_inquire_saslname_for_mech,
890     krb5_gss_inquire_mech_for_saslname,
891     krb5_gss_inquire_attrs_for_mech,
892     krb5_gss_acquire_cred_from,
893     krb5_gss_store_cred_into,
894     krb5_gss_acquire_cred_with_password,
895     krb5_gss_export_cred,
896     krb5_gss_import_cred,
897     NULL,               /* import_sec_context_by_mech */
898     NULL,               /* import_name_by_mech */
899     NULL,               /* import_cred_by_mech */
900     krb5_gss_get_mic_iov,
901     krb5_gss_verify_mic_iov,
902     krb5_gss_get_mic_iov_length,
903 };
904 
905 /* Functions which use security contexts or acquire creds are IAKERB-specific;
906  * other functions can borrow from the krb5 mech. */
907 static struct gss_config iakerb_mechanism = {
908     { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
909     NULL,
910     iakerb_gss_acquire_cred,
911     krb5_gss_release_cred,
912     iakerb_gss_init_sec_context,
913 #ifdef LEAN_CLIENT
914     NULL,
915 #else
916     iakerb_gss_accept_sec_context,
917 #endif
918     iakerb_gss_process_context_token,
919     iakerb_gss_delete_sec_context,
920     iakerb_gss_context_time,
921     iakerb_gss_get_mic,
922     iakerb_gss_verify_mic,
923 #if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
924     NULL,
925 #else
926     iakerb_gss_wrap,
927 #endif
928 #if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
929     NULL,
930 #else
931     iakerb_gss_unwrap,
932 #endif
933     krb5_gss_display_status,
934     krb5_gss_indicate_mechs,
935     krb5_gss_compare_name,
936     krb5_gss_display_name,
937     iakerb_gss_import_name,
938     krb5_gss_release_name,
939     krb5_gss_inquire_cred,
940     NULL,                /* add_cred */
941 #ifdef LEAN_CLIENT
942     NULL,
943     NULL,
944 #else
945     iakerb_gss_export_sec_context,
946     iakerb_gss_import_sec_context,
947 #endif
948     krb5_gss_inquire_cred_by_mech,
949     krb5_gss_inquire_names_for_mech,
950     iakerb_gss_inquire_context,
951     krb5_gss_internal_release_oid,
952     iakerb_gss_wrap_size_limit,
953     krb5_gss_localname,
954     krb5_gss_authorize_localname,
955     krb5_gss_export_name,
956     krb5_gss_duplicate_name,
957     krb5_gss_store_cred,
958     iakerb_gss_inquire_sec_context_by_oid,
959     krb5_gss_inquire_cred_by_oid,
960     iakerb_gss_set_sec_context_option,
961     krb5_gssspi_set_cred_option,
962     krb5_gssspi_mech_invoke,
963     NULL,                /* wrap_aead */
964     NULL,                /* unwrap_aead */
965     iakerb_gss_wrap_iov,
966     iakerb_gss_unwrap_iov,
967     iakerb_gss_wrap_iov_length,
968     NULL,               /* complete_auth_token */
969     NULL,               /* acquire_cred_impersonate_name */
970     NULL,               /* add_cred_impersonate_name */
971     NULL,               /* display_name_ext */
972     krb5_gss_inquire_name,
973     krb5_gss_get_name_attribute,
974     krb5_gss_set_name_attribute,
975     krb5_gss_delete_name_attribute,
976     krb5_gss_export_name_composite,
977     krb5_gss_map_name_to_any,
978     krb5_gss_release_any_name_mapping,
979     iakerb_gss_pseudo_random,
980     NULL,               /* set_neg_mechs */
981     krb5_gss_inquire_saslname_for_mech,
982     krb5_gss_inquire_mech_for_saslname,
983     krb5_gss_inquire_attrs_for_mech,
984     iakerb_gss_acquire_cred_from,
985     krb5_gss_store_cred_into,
986     iakerb_gss_acquire_cred_with_password,
987     krb5_gss_export_cred,
988     krb5_gss_import_cred,
989     NULL,               /* import_sec_context_by_mech */
990     NULL,               /* import_name_by_mech */
991     NULL,               /* import_cred_by_mech */
992     iakerb_gss_get_mic_iov,
993     iakerb_gss_verify_mic_iov,
994     iakerb_gss_get_mic_iov_length,
995 };
996 
997 #ifdef _GSS_STATIC_LINK
998 #include "mglueP.h"
gss_iakerbmechglue_init(void)999 static int gss_iakerbmechglue_init(void)
1000 {
1001     struct gss_mech_config mech_iakerb;
1002 
1003     memset(&mech_iakerb, 0, sizeof(mech_iakerb));
1004     mech_iakerb.mech = &iakerb_mechanism;
1005 
1006     mech_iakerb.mechNameStr = "iakerb";
1007     mech_iakerb.mech_type = (gss_OID)gss_mech_iakerb;
1008     gssint_register_mechinfo(&mech_iakerb);
1009 
1010     return 0;
1011 }
1012 
gss_krb5mechglue_init(void)1013 static int gss_krb5mechglue_init(void)
1014 {
1015     struct gss_mech_config mech_krb5;
1016 
1017     memset(&mech_krb5, 0, sizeof(mech_krb5));
1018     mech_krb5.mech = &krb5_mechanism;
1019 
1020     mech_krb5.mechNameStr = "kerberos_v5";
1021     mech_krb5.mech_type = (gss_OID)gss_mech_krb5;
1022     gssint_register_mechinfo(&mech_krb5);
1023 
1024     mech_krb5.mechNameStr = "kerberos_v5_old";
1025     mech_krb5.mech_type = (gss_OID)gss_mech_krb5_old;
1026     gssint_register_mechinfo(&mech_krb5);
1027 
1028     mech_krb5.mechNameStr = "mskrb";
1029     mech_krb5.mech_type = (gss_OID)gss_mech_krb5_wrong;
1030     gssint_register_mechinfo(&mech_krb5);
1031 
1032     return 0;
1033 }
1034 #else
1035 MAKE_INIT_FUNCTION(gss_krb5int_lib_init);
1036 MAKE_FINI_FUNCTION(gss_krb5int_lib_fini);
1037 
1038 gss_mechanism KRB5_CALLCONV
gss_mech_initialize(void)1039 gss_mech_initialize(void)
1040 {
1041     return &krb5_mechanism;
1042 }
1043 #endif /* _GSS_STATIC_LINK */
1044 
gss_krb5int_lib_init(void)1045 int gss_krb5int_lib_init(void)
1046 {
1047     int err;
1048 
1049 #ifdef SHOW_INITFINI_FUNCS
1050     printf("gss_krb5int_lib_init\n");
1051 #endif
1052 
1053     add_error_table(&et_k5g_error_table);
1054 
1055 #ifndef LEAN_CLIENT
1056     err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
1057     if (err)
1058         return err;
1059 #endif /* LEAN_CLIENT */
1060     err = k5_key_register(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, free);
1061     if (err)
1062         return err;
1063     err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free);
1064     if (err)
1065         return err;
1066     err = k5_key_register(K5_KEY_GSS_KRB5_ERROR_MESSAGE,
1067                           krb5_gss_delete_error_info);
1068     if (err)
1069         return err;
1070 #ifndef _WIN32
1071     err = k5_mutex_finish_init(&kg_kdc_flag_mutex);
1072     if (err)
1073         return err;
1074 #endif
1075 #ifdef _GSS_STATIC_LINK
1076     err = gss_krb5mechglue_init();
1077     if (err)
1078         return err;
1079     err = gss_iakerbmechglue_init();
1080     if (err)
1081         return err;
1082 #endif
1083 
1084     return 0;
1085 }
1086 
gss_krb5int_lib_fini(void)1087 void gss_krb5int_lib_fini(void)
1088 {
1089 #ifndef _GSS_STATIC_LINK
1090     if (!INITIALIZER_RAN(gss_krb5int_lib_init) || PROGRAM_EXITING()) {
1091 # ifdef SHOW_INITFINI_FUNCS
1092         printf("gss_krb5int_lib_fini: skipping\n");
1093 # endif
1094         return;
1095     }
1096 #endif
1097 #ifdef SHOW_INITFINI_FUNCS
1098     printf("gss_krb5int_lib_fini\n");
1099 #endif
1100     remove_error_table(&et_k5g_error_table);
1101 
1102     k5_key_delete(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
1103     k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
1104     k5_key_delete(K5_KEY_GSS_KRB5_ERROR_MESSAGE);
1105 #ifndef _WIN32
1106     k5_mutex_destroy(&kg_kdc_flag_mutex);
1107 #endif
1108 #ifndef LEAN_CLIENT
1109     k5_mutex_destroy(&gssint_krb5_keytab_lock);
1110 #endif /* LEAN_CLIENT */
1111 }
1112 
1113 #ifdef _GSS_STATIC_LINK
1114 extern OM_uint32 gssint_lib_init(void);
1115 #endif
1116 
gss_krb5int_initialize_library(void)1117 OM_uint32 gss_krb5int_initialize_library (void)
1118 {
1119 #ifdef _GSS_STATIC_LINK
1120     return gssint_mechglue_initialize_library();
1121 #else
1122     return CALL_INIT_FUNCTION(gss_krb5int_lib_init);
1123 #endif
1124 }
1125