gssapi_krb5.c revision 7934:6aeeafc994de
1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7/*
8 * Copyright 1993 by OpenVision Technologies, Inc.
9 *
10 * Permission to use, copy, modify, distribute, and sell this software
11 * and its documentation for any purpose is hereby granted without fee,
12 * provided that the above copyright notice appears in all copies and
13 * that both that copyright notice and this permission notice appear in
14 * supporting documentation, and that the name of OpenVision not be used
15 * in advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission. OpenVision makes no
17 * representations about the suitability of this software for any
18 * purpose.  It is provided "as is" without express or implied warranty.
19 *
20 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 * PERFORMANCE OF THIS SOFTWARE.
27 */
28
29/*
30 * Copyright (C) 1998 by the FundsXpress, INC.
31 *
32 * All rights reserved.
33 *
34 * Export of this software from the United States of America may require
35 * a specific license from the United States Government.  It is the
36 * responsibility of any person or organization contemplating export to
37 * obtain such a license before exporting.
38 *
39 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
40 * distribute this software and its documentation for any purpose and
41 * without fee is hereby granted, provided that the above copyright
42 * notice appear in all copies and that both that copyright notice and
43 * this permission notice appear in supporting documentation, and that
44 * the name of FundsXpress. not be used in advertising or publicity pertaining
45 * to distribution of the software without specific, written prior
46 * permission.  FundsXpress makes no representations about the suitability of
47 * this software for any purpose.  It is provided "as is" without express
48 * or implied warranty.
49 *
50 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
51 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
52 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
53 */
54
55/*
56 * $Id: gssapi_krb5.c 18343 2006-07-19 18:14:01Z lxs $
57 */
58
59
60/* For declaration of krb5_ser_context_init */
61#include "k5-int.h"
62#include "gssapiP_krb5.h"
63
64/*
65 * Solaris Kerberos
66 * Kernel kgssd module debugging aid. The global variable "krb5_log" is a bit
67 * mask which allows various types of log messages to be printed out.
68 *
69 * The log levels are defined in:
70 * usr/src/uts/common/gssapi/mechs/krb5/include/k5-int.h
71 *
72 * Note, KRB5_LOG_LVL can be assigned via the make invocation.
73 * See KRB5_DEFS in the various Makefiles.
74 */
75
76#ifdef KRB5_LOG_LVL
77/* set the log level to that specified */
78u_int krb5_log = KRB5_LOG_LVL;
79#else
80/* default log level */
81u_int krb5_log = 0;
82#endif /* KRB5_LOG_LVL */
83
84/** exported constants defined in gssapi_krb5{,_nx}.h **/
85
86/* these are bogus, but will compile */
87
88/*
89 * The OID of the draft krb5 mechanism, assigned by IETF, is:
90 * 	iso(1) org(3) dod(5) internet(1) security(5)
91 *	kerberosv5(2) = 1.3.5.1.5.2
92 * The OID of the krb5_name type is:
93 * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
94 * 	krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
95 * The OID of the krb5_principal type is:
96 * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
97 * 	krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
98 * The OID of the proposed standard krb5 mechanism is:
99 * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
100 * 	krb5(2) = 1.2.840.113554.1.2.2
101 * The OID of the proposed standard krb5 v2 mechanism is:
102 * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
103 * 	krb5v2(3) = 1.2.840.113554.1.2.3
104 *
105 */
106
107/*
108 * Encoding rules: The first two values are encoded in one byte as 40
109 * * value1 + value2.  Subsequent values are encoded base 128, most
110 * significant digit first, with the high bit (\200) set on all octets
111 * except the last in each value's encoding.
112 */
113
114const gss_OID_desc krb5_gss_oid_array[] = {
115   /* this is the official, rfc-specified OID */
116   {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
117   /* this pre-RFC mech OID */
118   {GSS_MECH_KRB5_OLD_OID_LENGTH, GSS_MECH_KRB5_OLD_OID},
119   /* this is the unofficial, incorrect mech OID emitted by MS */
120   {GSS_MECH_KRB5_WRONG_OID_LENGTH, GSS_MECH_KRB5_WRONG_OID},
121   /* this is the v2 assigned OID */
122   {9, "\052\206\110\206\367\022\001\002\003"},
123   /* these two are name type OID's */
124
125    /* 2.1.1. Kerberos Principal Name Form:  (rfc 1964)
126     * This name form shall be represented by the Object Identifier {iso(1)
127     * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
128     * krb5(2) krb5_name(1)}.  The recommended symbolic name for this type
129     * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
130   {10, "\052\206\110\206\367\022\001\002\002\001"},
131
132   /* gss_nt_krb5_principal.  Object identifier for a krb5_principal. Do not use. */
133   {10, "\052\206\110\206\367\022\001\002\002\002"},
134   { 0, 0 }
135};
136
137const gss_OID_desc * const gss_mech_krb5              = krb5_gss_oid_array+0;
138const gss_OID_desc * const gss_mech_krb5_old          = krb5_gss_oid_array+1;
139const gss_OID_desc * const gss_mech_krb5_wrong        = krb5_gss_oid_array+2;
140const gss_OID_desc * const gss_nt_krb5_name           = krb5_gss_oid_array+4;
141const gss_OID_desc * const gss_nt_krb5_principal      = krb5_gss_oid_array+5;
142const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4;
143
144static const gss_OID_set_desc oidsets[] = {
145   {1, (gss_OID) krb5_gss_oid_array+0},
146   {1, (gss_OID) krb5_gss_oid_array+1},
147   {3, (gss_OID) krb5_gss_oid_array+0},
148   {1, (gss_OID) krb5_gss_oid_array+2},
149   {3, (gss_OID) krb5_gss_oid_array+0},
150};
151
152const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+0;
153const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+1;
154const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2;
155
156g_set kg_vdb = G_SET_INIT;
157
158/** default credential support */
159
160#ifndef  _KERNEL
161
162/*
163 * init_sec_context() will explicitly re-acquire default credentials,
164 * so handling the expiration/invalidation condition here isn't needed.
165 */
166OM_uint32
167kg_get_defcred(minor_status, cred)
168     OM_uint32 *minor_status;
169     gss_cred_id_t *cred;
170{
171    OM_uint32 major;
172
173    if ((major = krb5_gss_acquire_cred(minor_status,
174				      (gss_name_t) NULL, GSS_C_INDEFINITE,
175				      GSS_C_NULL_OID_SET, GSS_C_INITIATE,
176				      cred, NULL, NULL)) && GSS_ERROR(major)) {
177      return(major);
178   }
179   *minor_status = 0;
180   return(GSS_S_COMPLETE);
181}
182
183OM_uint32
184kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
185{
186    OM_uint32 err = 0;
187
188    /*
189     * Sync up the context ccache name with the GSSAPI ccache name.
190     * If kg_ccache_name is NULL -- normal unless someone has called
191     * gss_krb5_ccache_name() -- then the system default ccache will
192     * be picked up and used by resetting the context default ccache.
193     * This is needed for platforms which support multiple ccaches.
194     */
195
196    if (!err) {
197        /* if NULL, resets the context default ccache */
198        err = krb5_cc_set_default_name(context,
199				       (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
200    }
201
202    *minor_status = err;
203    return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
204}
205
206/* This function returns whether or not the caller set a cccache name.  Used by
207 * gss_acquire_cred to figure out if the caller wants to only look at this
208 * ccache or search the cache collection for the desired name */
209OM_uint32
210kg_caller_provided_ccache_name (OM_uint32 *minor_status,
211int *out_caller_provided_name)
212{
213    if (out_caller_provided_name) {
214        *out_caller_provided_name =
215	  (k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME) != NULL);
216    }
217
218    *minor_status = 0;
219    return GSS_S_COMPLETE;
220}
221
222OM_uint32
223kg_get_ccache_name (OM_uint32 *minor_status, const char **out_name)
224{
225    const char *name = NULL;
226    OM_uint32 err = 0;
227    char *kg_ccache_name;
228
229    kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
230
231    if (kg_ccache_name != NULL) {
232	name = strdup(kg_ccache_name);
233	if (name == NULL)
234	    err = errno;
235    } else {
236	krb5_context context = NULL;
237
238	/* Reset the context default ccache (see text above), and then
239	   retrieve it.  */
240	err = krb5_gss_init_context(&context);
241	if (!err)
242	    err = krb5_cc_set_default_name (context, NULL);
243	if (!err) {
244	    name = krb5_cc_default_name(context);
245	    if (name) {
246		name = strdup(name);
247		if (name == NULL)
248		    err = errno;
249	    }
250	}
251	if (context)
252	    krb5_free_context(context);
253    }
254
255    if (!err) {
256        if (out_name) {
257            *out_name = name;
258        }
259    }
260
261    *minor_status = err;
262    return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
263}
264
265OM_uint32
266kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
267{
268    char *new_name = NULL;
269    char *swap = NULL;
270    char *kg_ccache_name;
271    krb5_error_code kerr;
272
273    if (name) {
274	new_name = malloc(strlen(name) + 1);
275	if (new_name == NULL) {
276	    *minor_status = ENOMEM;
277	    return GSS_S_FAILURE;
278	}
279	strcpy(new_name, name);
280    }
281
282    kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
283    swap = kg_ccache_name;
284    kg_ccache_name = new_name;
285    new_name = swap;
286    kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
287    if (kerr != 0) {
288	/* Can't store, so free up the storage.  */
289	free(kg_ccache_name);
290	/* ??? free(new_name); */
291	*minor_status = kerr;
292	return GSS_S_FAILURE;
293    }
294
295    free (new_name);
296    *minor_status = 0;
297    return GSS_S_COMPLETE;
298}
299#endif
300