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