Home | History | Annotate | Download | only in mech
      1 /*
      2  * Copyright 2009 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 */
     78 u_int krb5_log = KRB5_LOG_LVL;
     79 #else
     80 /* default log level */
     81 u_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 
    114 const 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 
    137 const gss_OID_desc * const gss_mech_krb5              = krb5_gss_oid_array+0;
    138 const gss_OID_desc * const gss_mech_krb5_old          = krb5_gss_oid_array+1;
    139 const gss_OID_desc * const gss_mech_krb5_wrong        = krb5_gss_oid_array+2;
    140 const gss_OID_desc * const gss_nt_krb5_name           = krb5_gss_oid_array+4;
    141 const gss_OID_desc * const gss_nt_krb5_principal      = krb5_gss_oid_array+5;
    142 const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+4;
    143 
    144 static 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 
    152 const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+0;
    153 const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+1;
    154 const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2;
    155 
    156 g_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  */
    166 OM_uint32
    167 kg_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 
    183 OM_uint32
    184 kg_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 */
    209 OM_uint32
    210 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
    211 int *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 
    222 OM_uint32
    223 kg_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 
    265 OM_uint32
    266 kg_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 
    300 #define g_OID_prefix_equal(o1, o2) \
    301         (((o1)->length >= (o2)->length) && \
    302         (memcmp((o1)->elements, (o2)->elements, (o2)->length) == 0))
    303 
    304 /*
    305  * gss_inquire_sec_context_by_oid() methods
    306  */
    307 static struct {
    308     gss_OID_desc oid;
    309     OM_uint32 (*func)(OM_uint32 *, const gss_ctx_id_t, const gss_OID, gss_buffer_set_t *);
    310 } krb5_gss_inquire_sec_context_by_oid_ops[] = {
    311     {
    312         {GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID},
    313         gss_krb5int_get_tkt_flags
    314     },
    315     {
    316         {GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID},
    317         gss_krb5int_extract_authz_data_from_sec_context
    318     },
    319     {
    320         {GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH, GSS_KRB5_INQ_SSPI_SESSION_KEY_OID},
    321         gss_krb5int_inq_session_key
    322     },
    323     {
    324         {GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID},
    325         gss_krb5int_export_lucid_sec_context
    326     },
    327     {
    328         {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
    329         gss_krb5int_extract_authtime_from_sec_context
    330     }
    331 };
    332 
    333 OM_uint32
    334 krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
    335                                      const gss_ctx_id_t context_handle,
    336                                      const gss_OID desired_object,
    337                                      gss_buffer_set_t *data_set)
    338 {
    339     krb5_gss_ctx_id_rec *ctx;
    340     size_t i;
    341 
    342     if (minor_status == NULL)
    343         return GSS_S_CALL_INACCESSIBLE_WRITE;
    344 
    345     *minor_status = 0;
    346 
    347     if (desired_object == GSS_C_NO_OID)
    348         return GSS_S_CALL_INACCESSIBLE_READ;
    349 
    350     if (data_set == NULL)
    351         return GSS_S_CALL_INACCESSIBLE_WRITE;
    352 
    353     *data_set = GSS_C_NO_BUFFER_SET;
    354 
    355     if (!kg_validate_ctx_id(context_handle))
    356         return GSS_S_NO_CONTEXT;
    357 
    358     ctx = (krb5_gss_ctx_id_rec *) context_handle;
    359 
    360     if (!ctx->established)
    361         return GSS_S_NO_CONTEXT;
    362 
    363     for (i = 0; i < sizeof(krb5_gss_inquire_sec_context_by_oid_ops)/
    364                     sizeof(krb5_gss_inquire_sec_context_by_oid_ops[0]); i++) {
    365         if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_sec_context_by_oid_ops[i].oid)) {
    366             return (*krb5_gss_inquire_sec_context_by_oid_ops[i].func)(minor_status,
    367                                                                       context_handle,
    368                                                                       desired_object,
    369                                                                       data_set);
    370         }
    371     }
    372 
    373     *minor_status = EINVAL;
    374 
    375     return GSS_S_UNAVAILABLE;
    376 }
    377 
    378 #endif
    379