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 H��gskolan 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 38OM_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 222out: 223 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 224 return ret; 225} 226