Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: inquire_cred.c,v 1.2 2017/01/28 21:31:46 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997, 2003 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "gsskrb5_locl.h"
     37 
     38 OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred
     39 (OM_uint32 * minor_status,
     40  gss_const_cred_id_t cred_handle,
     41  gss_name_t * output_name,
     42  OM_uint32 * lifetime,
     43  gss_cred_usage_t * cred_usage,
     44  gss_OID_set * mechanisms
     45     )
     46 {
     47     krb5_context context;
     48     gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL;
     49     gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL;
     50     gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
     51     gss_OID_set amechs = GSS_C_NO_OID_SET;
     52     gss_OID_set imechs = GSS_C_NO_OID_SET;
     53     OM_uint32 junk;
     54     OM_uint32 aminor;
     55     OM_uint32 ret;
     56     OM_uint32 aret;
     57     OM_uint32 alife = GSS_C_INDEFINITE;
     58     OM_uint32 ilife = GSS_C_INDEFINITE;
     59 
     60     /*
     61      * XXX This function is more complex than it has to be.  It should call
     62      * _gsskrb5_inquire_cred_by_mech() twice and merge the results in the
     63      * cred_handle == GSS_C_NO_CREDENTIAL case, but since
     64      * _gsskrb5_inquire_cred_by_mech() is implemented in terms of this
     65      * function, first we must fix _gsskrb5_inquire_cred_by_mech().
     66      */
     67 
     68     *minor_status = 0;
     69 
     70     if (output_name)
     71         *output_name = GSS_C_NO_NAME;
     72     if (cred_usage)
     73         *cred_usage = GSS_C_BOTH; /* There's no NONE */
     74     if (mechanisms)
     75         *mechanisms = GSS_C_NO_OID_SET;
     76 
     77     GSSAPI_KRB5_INIT (&context);
     78 
     79     if (cred_handle == GSS_C_NO_CREDENTIAL) {
     80         /*
     81          * From here to the end of this if we should refactor into a separate
     82          * function.
     83          */
     84         /* Get the info for the default ACCEPT credential */
     85         aret = _gsskrb5_acquire_cred(&aminor,
     86                                     GSS_C_NO_NAME,
     87                                     GSS_C_INDEFINITE,
     88                                     GSS_C_NO_OID_SET,
     89                                     GSS_C_ACCEPT,
     90                                     &aqcred_accept,
     91                                     NULL,
     92                                     NULL);
     93         if (aret == GSS_S_COMPLETE) {
     94             aret = _gsskrb5_inquire_cred(&aminor,
     95                                         aqcred_accept,
     96                                         output_name,
     97                                         &alife,
     98                                         NULL,
     99                                         &amechs);
    100             (void) _gsskrb5_release_cred(&junk, &aqcred_accept);
    101             if (aret == GSS_S_COMPLETE) {
    102                 output_name = NULL; /* Can't merge names; output only one */
    103                 if (cred_usage)
    104                     *cred_usage = GSS_C_ACCEPT;
    105                 if (lifetime)
    106                     *lifetime = alife;
    107                 if (mechanisms) {
    108                     *mechanisms = amechs;
    109                     amechs = GSS_C_NO_OID_SET;
    110                 }
    111                 (void) gss_release_oid_set(&junk, &amechs);
    112             } else if (aret != GSS_S_NO_CRED) {
    113                 *minor_status = aminor;
    114                 return aret;
    115             } else {
    116                 alife = GSS_C_INDEFINITE;
    117             }
    118         }
    119 
    120         /* Get the info for the default INITIATE credential */
    121         ret = _gsskrb5_acquire_cred(minor_status,
    122                                     GSS_C_NO_NAME,
    123                                     GSS_C_INDEFINITE,
    124                                     GSS_C_NO_OID_SET,
    125                                     GSS_C_INITIATE,
    126                                     &aqcred_init,
    127                                     NULL,
    128                                     NULL);
    129         if (ret == GSS_S_COMPLETE) {
    130             ret = _gsskrb5_inquire_cred(minor_status,
    131                                         aqcred_init,
    132                                         output_name,
    133                                         &ilife,
    134                                         NULL,
    135                                         &imechs);
    136             (void) _gsskrb5_release_cred(&junk, &aqcred_init);
    137             if (ret == GSS_S_COMPLETE) {
    138                 /*
    139                  * Merge results for INITIATE with ACCEPT if we had ACCEPT and
    140                  * for those outputs that are desired.
    141                  */
    142                 if (cred_usage) {
    143                     *cred_usage = (*cred_usage == GSS_C_ACCEPT) ?
    144                         GSS_C_BOTH : GSS_C_INITIATE;
    145                 }
    146                 if (lifetime)
    147                     *lifetime = min(alife, ilife);
    148                 if (mechanisms) {
    149                     /*
    150                      * This is just one mechanism (IAKERB and such would live
    151                      * elsewhere).  imechs will be equal to amechs, though not
    152                      * ==.
    153                      */
    154                     if (aret != GSS_S_COMPLETE) {
    155                         *mechanisms = imechs;
    156                         imechs = GSS_C_NO_OID_SET;
    157                     }
    158                 }
    159                 (void) gss_release_oid_set(&junk, &amechs);
    160             } else if (ret != GSS_S_NO_CRED) {
    161                 *minor_status = aminor;
    162                 return aret;
    163             }
    164         }
    165 
    166         if (aret != GSS_S_COMPLETE && ret != GSS_S_COMPLETE) {
    167             *minor_status = aminor;
    168             return aret;
    169         }
    170         *minor_status = 0; /* Even though 0 is not specified to be special */
    171         return GSS_S_COMPLETE;
    172     }
    173 
    174     HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
    175 
    176     if (output_name != NULL) {
    177         if (cred->principal != NULL) {
    178             gss_name_t name = (gss_name_t)cred->principal;
    179             ret = _gsskrb5_duplicate_name(minor_status, name, output_name);
    180             if (ret)
    181                 goto out;
    182         } else if (cred->usage == GSS_C_ACCEPT) {
    183             /*
    184              * Keytab case, princ may not be set (yet, ever, whatever).
    185              *
    186              * We used to unconditionally output the krb5_sname_to_principal()
    187              * of the host service for the hostname, but we didn't know if we
    188              * had keytab entries for it, so it was incorrect.  We can't be
    189              * breaking anything in tree by outputting GSS_C_NO_NAME, but we
    190              * might be breaking other callers.
    191              */
    192             *output_name = GSS_C_NO_NAME;
    193         } else {
    194             /* This shouldn't happen */
    195             *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */
    196             ret = GSS_S_NO_CRED;
    197             goto out;
    198         }
    199     }
    200     if (lifetime != NULL) {
    201         ret = _gsskrb5_lifetime_left(minor_status,
    202                                      context,
    203                                      cred->endtime,
    204                                      lifetime);
    205         if (ret)
    206             goto out;
    207     }
    208     if (cred_usage != NULL)
    209         *cred_usage = cred->usage;
    210     if (mechanisms != NULL) {
    211         ret = gss_create_empty_oid_set(minor_status, mechanisms);
    212         if (ret)
    213             goto out;
    214         ret = gss_add_oid_set_member(minor_status,
    215                                      &cred->mechanisms->elements[0],
    216                                      mechanisms);
    217         if (ret)
    218             goto out;
    219     }
    220     ret = GSS_S_COMPLETE;
    221 
    222 out:
    223     HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
    224     return ret;
    225 }
    226