2 * Copyright (c) 2011, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * Utility routines for credential handles.
37 #include "gssapiP_eap.h"
42 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
47 *pCred = GSS_C_NO_CREDENTIAL;
49 cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
55 if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
57 gssEapReleaseCred(&tmpMinor, &cred);
64 return GSS_S_COMPLETE;
68 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
71 gss_cred_id_t cred = *pCred;
72 krb5_context krbContext = NULL;
74 if (cred == GSS_C_NO_CREDENTIAL) {
75 return GSS_S_COMPLETE;
78 GSSEAP_KRB_INIT(&krbContext);
80 gssEapReleaseName(&tmpMinor, &cred->name);
82 if (cred->password.value != NULL) {
83 memset(cred->password.value, 0, cred->password.length);
84 GSSEAP_FREE(cred->password.value);
87 if (cred->radiusConfigFile != NULL)
88 GSSEAP_FREE(cred->radiusConfigFile);
89 if (cred->radiusConfigStanza != NULL)
90 GSSEAP_FREE(cred->radiusConfigStanza);
92 #ifdef GSSEAP_ENABLE_REAUTH
93 if (cred->krbCredCache != NULL) {
94 if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
95 krb5_cc_close(krbContext, cred->krbCredCache);
97 krb5_cc_destroy(krbContext, cred->krbCredCache);
99 if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
100 gssReleaseCred(&tmpMinor, &cred->reauthCred);
103 GSSEAP_MUTEX_DESTROY(&cred->mutex);
104 memset(cred, 0, sizeof(*cred));
109 return GSS_S_COMPLETE;
113 readDefaultIdentityAndCreds(OM_uint32 *minor,
114 gss_buffer_t defaultIdentity,
115 gss_buffer_t defaultCreds)
117 OM_uint32 major, tmpMinor;
119 char pwbuf[BUFSIZ], buf[BUFSIZ];
121 struct passwd *pw = NULL, pwd;
123 defaultIdentity->length = 0;
124 defaultIdentity->value = NULL;
126 defaultCreds->length = 0;
127 defaultCreds->value = NULL;
129 ccacheName = getenv("GSSEAP_IDENTITY");
130 if (ccacheName == NULL) {
131 if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
132 pw == NULL || pw->pw_dir == NULL) {
133 major = GSS_S_CRED_UNAVAIL;
138 snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
142 fp = fopen(ccacheName, "r");
144 major = GSS_S_CRED_UNAVAIL;
145 *minor = GSSEAP_NO_DEFAULT_CRED;
149 while (fgets(buf, sizeof(buf), fp) != NULL) {
150 gss_buffer_desc src, *dst;
152 src.length = strlen(buf);
158 if (buf[src.length - 1] == '\n') {
159 buf[src.length - 1] = '\0';
160 if (--src.length == 0)
164 if (defaultIdentity->value == NULL)
165 dst = defaultIdentity;
166 else if (defaultCreds->value == NULL)
171 major = duplicateBuffer(minor, &src, dst);
172 if (GSS_ERROR(major))
176 if (defaultIdentity->length == 0) {
177 major = GSS_S_CRED_UNAVAIL;
178 *minor = GSSEAP_NO_DEFAULT_CRED;
182 major = GSS_S_COMPLETE;
189 if (GSS_ERROR(major)) {
190 gss_release_buffer(&tmpMinor, defaultIdentity);
191 gss_release_buffer(&tmpMinor, defaultCreds);
198 gssEapAcquireCred(OM_uint32 *minor,
199 const gss_name_t desiredName,
200 const gss_buffer_t password,
201 OM_uint32 timeReq GSSEAP_UNUSED,
202 const gss_OID_set desiredMechs,
204 gss_cred_id_t *pCred,
205 gss_OID_set *pActualMechs,
208 OM_uint32 major, tmpMinor;
210 gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
211 gss_name_t defaultIdentityName = GSS_C_NO_NAME;
212 gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
213 gss_OID nameMech = GSS_C_NO_OID;
215 /* XXX TODO validate with changed set_cred_option API */
216 *pCred = GSS_C_NO_CREDENTIAL;
218 major = gssEapAllocCred(minor, &cred);
219 if (GSS_ERROR(major))
224 cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
227 cred->flags |= CRED_FLAG_INITIATE;
230 cred->flags |= CRED_FLAG_ACCEPT;
233 major = GSS_S_FAILURE;
234 *minor = GSSEAP_BAD_USAGE;
239 major = gssEapValidateMechs(minor, desiredMechs);
240 if (GSS_ERROR(major))
243 major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
244 if (GSS_ERROR(major))
247 if (cred->mechanisms != GSS_C_NO_OID_SET &&
248 cred->mechanisms->count == 1)
249 nameMech = &cred->mechanisms->elements[0];
251 if (cred->flags & CRED_FLAG_INITIATE) {
252 major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
253 if (major == GSS_S_COMPLETE) {
254 major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
255 nameMech, &defaultIdentityName);
256 if (GSS_ERROR(major))
258 } else if (major != GSS_S_CRED_UNAVAIL)
262 if (desiredName != GSS_C_NO_NAME) {
263 GSSEAP_MUTEX_LOCK(&desiredName->mutex);
265 major = gssEapDuplicateName(minor, desiredName, &cred->name);
266 if (GSS_ERROR(major)) {
267 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
271 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
273 if (defaultIdentityName != GSS_C_NO_NAME) {
276 major = gssEapCompareName(minor, desiredName,
277 defaultIdentityName, &nameEqual);
278 if (GSS_ERROR(major))
281 cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
284 if (cred->flags & CRED_FLAG_ACCEPT) {
285 gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
286 char serviceName[5 + MAXHOSTNAMELEN];
288 /* default host-based service is host@localhost */
289 memcpy(serviceName, "host@", 5);
290 if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
291 major = GSS_S_FAILURE;
292 *minor = GSSEAP_NO_HOSTNAME;
296 nameBuf.value = serviceName;
297 nameBuf.length = strlen((char *)nameBuf.value);
299 major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
300 nameMech, &cred->name);
301 if (GSS_ERROR(major))
303 } else if (cred->flags & CRED_FLAG_INITIATE) {
304 if (defaultIdentityName == GSS_C_NO_NAME) {
305 major = GSS_S_CRED_UNAVAIL;
306 *minor = GSSEAP_NO_DEFAULT_IDENTITY;
310 cred->name = defaultIdentityName;
311 defaultIdentityName = GSS_C_NO_NAME;
313 cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
316 assert(cred->name != GSS_C_NO_NAME);
318 if (password != GSS_C_NO_BUFFER) {
319 major = duplicateBuffer(minor, password, &cred->password);
320 if (GSS_ERROR(major))
323 cred->flags |= CRED_FLAG_PASSWORD;
324 } else if (defaultCreds.value != NULL &&
325 (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
326 cred->password = defaultCreds;
328 defaultCreds.length = 0;
329 defaultCreds.value = NULL;
331 cred->flags |= CRED_FLAG_PASSWORD;
332 } else if (cred->flags & CRED_FLAG_INITIATE) {
334 * OK, here we need to ask the supplicant if we have creds or it
335 * will acquire them, so GS2 can know whether to prompt for a
339 && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
341 major = GSS_S_CRED_UNAVAIL;
342 *minor = GSSEAP_NO_DEFAULT_CRED;
346 if (pActualMechs != NULL) {
347 major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
348 if (GSS_ERROR(major))
353 *timeRec = GSS_C_INDEFINITE;
357 major = GSS_S_COMPLETE;
361 if (GSS_ERROR(major))
362 gssEapReleaseCred(&tmpMinor, &cred);
363 gssEapReleaseName(&tmpMinor, &defaultIdentityName);
364 gss_release_buffer(&tmpMinor, &defaultIdentity);
365 if (defaultCreds.value != NULL) {
366 memset(defaultCreds.value, 0, defaultCreds.length);
367 gss_release_buffer(&tmpMinor, &defaultCreds);
374 * Return TRUE if cred available for mechanism. Caller need no acquire
375 * lock because mechanisms list is immutable.
378 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
383 assert(mech != GSS_C_NO_OID);
385 if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
388 gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);