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