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"
41 const gss_OID_desc gssEapPasswordCredType =
42 { 7, "\x2a\x85\x70\x2b\x0d\x81\x48" };
45 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
50 *pCred = GSS_C_NO_CREDENTIAL;
52 cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
58 if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
60 gssEapReleaseCred(&tmpMinor, &cred);
67 return GSS_S_COMPLETE;
71 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
74 gss_cred_id_t cred = *pCred;
75 krb5_context krbContext = NULL;
77 if (cred == GSS_C_NO_CREDENTIAL) {
78 return GSS_S_COMPLETE;
81 GSSEAP_KRB_INIT(&krbContext);
83 gssEapReleaseName(&tmpMinor, &cred->name);
85 if (cred->password.value != NULL) {
86 memset(cred->password.value, 0, cred->password.length);
87 GSSEAP_FREE(cred->password.value);
90 if (cred->radiusConfigFile != NULL)
91 GSSEAP_FREE(cred->radiusConfigFile);
92 if (cred->radiusConfigStanza != NULL)
93 GSSEAP_FREE(cred->radiusConfigStanza);
95 #ifdef GSSEAP_ENABLE_REAUTH
96 if (cred->krbCredCache != NULL) {
97 if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
98 krb5_cc_close(krbContext, cred->krbCredCache);
100 krb5_cc_destroy(krbContext, cred->krbCredCache);
102 if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
103 gssReleaseCred(&tmpMinor, &cred->reauthCred);
106 GSSEAP_MUTEX_DESTROY(&cred->mutex);
107 memset(cred, 0, sizeof(*cred));
112 return GSS_S_COMPLETE;
116 readDefaultIdentityAndCreds(OM_uint32 *minor,
117 gss_buffer_t defaultIdentity,
118 gss_buffer_t defaultCreds)
120 OM_uint32 major, tmpMinor;
122 char pwbuf[BUFSIZ], buf[BUFSIZ];
124 struct passwd *pw = NULL, pwd;
126 defaultIdentity->length = 0;
127 defaultIdentity->value = NULL;
129 defaultCreds->length = 0;
130 defaultCreds->value = NULL;
132 ccacheName = getenv("GSSEAP_IDENTITY");
133 if (ccacheName == NULL) {
134 if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
135 pw == NULL || pw->pw_dir == NULL) {
136 major = GSS_S_CRED_UNAVAIL;
141 snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
145 fp = fopen(ccacheName, "r");
147 major = GSS_S_CRED_UNAVAIL;
148 *minor = GSSEAP_NO_DEFAULT_CRED;
152 while (fgets(buf, sizeof(buf), fp) != NULL) {
153 gss_buffer_desc src, *dst;
155 src.length = strlen(buf);
161 if (buf[src.length - 1] == '\n') {
162 buf[src.length - 1] = '\0';
163 if (--src.length == 0)
167 if (defaultIdentity->value == NULL)
168 dst = defaultIdentity;
169 else if (defaultCreds->value == NULL)
174 major = duplicateBuffer(minor, &src, dst);
175 if (GSS_ERROR(major))
179 if (defaultIdentity->length == 0) {
180 major = GSS_S_CRED_UNAVAIL;
181 *minor = GSSEAP_NO_DEFAULT_CRED;
185 major = GSS_S_COMPLETE;
192 if (GSS_ERROR(major)) {
193 gss_release_buffer(&tmpMinor, defaultIdentity);
194 gss_release_buffer(&tmpMinor, defaultCreds);
201 gssEapAcquireCred(OM_uint32 *minor,
202 const gss_name_t desiredName,
203 gss_const_OID credType,
204 const void *credData,
205 OM_uint32 timeReq GSSEAP_UNUSED,
206 const gss_OID_set desiredMechs,
208 gss_cred_id_t *pCred,
209 gss_OID_set *pActualMechs,
212 OM_uint32 major, tmpMinor;
214 gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
215 gss_name_t defaultIdentityName = GSS_C_NO_NAME;
216 gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
217 gss_OID nameMech = GSS_C_NO_OID;
218 gss_buffer_t password = GSS_C_NO_BUFFER;
220 /* XXX TODO validate with changed set_cred_option API */
221 *pCred = GSS_C_NO_CREDENTIAL;
223 if (credType != GSS_C_NO_OID) {
224 if (oidEqual(credType, &gssEapPasswordCredType)) {
225 password = (gss_buffer_t)credData;
227 major = GSS_S_CRED_UNAVAIL;
228 *minor = GSSEAP_BAD_CRED_TYPE;
233 major = gssEapAllocCred(minor, &cred);
234 if (GSS_ERROR(major))
239 cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
242 cred->flags |= CRED_FLAG_INITIATE;
245 cred->flags |= CRED_FLAG_ACCEPT;
248 major = GSS_S_FAILURE;
249 *minor = GSSEAP_BAD_USAGE;
254 major = gssEapValidateMechs(minor, desiredMechs);
255 if (GSS_ERROR(major))
258 major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
259 if (GSS_ERROR(major))
262 if (cred->mechanisms != GSS_C_NO_OID_SET &&
263 cred->mechanisms->count == 1)
264 nameMech = &cred->mechanisms->elements[0];
266 if (cred->flags & CRED_FLAG_INITIATE) {
267 major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
268 if (major == GSS_S_COMPLETE) {
269 major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
270 nameMech, &defaultIdentityName);
271 if (GSS_ERROR(major))
273 } else if (major != GSS_S_CRED_UNAVAIL)
277 if (desiredName != GSS_C_NO_NAME) {
278 GSSEAP_MUTEX_LOCK(&desiredName->mutex);
280 major = gssEapDuplicateName(minor, desiredName, &cred->name);
281 if (GSS_ERROR(major)) {
282 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
286 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
288 if (defaultIdentityName != GSS_C_NO_NAME) {
291 major = gssEapCompareName(minor, desiredName,
292 defaultIdentityName, &nameEqual);
293 if (GSS_ERROR(major))
296 cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
299 if (cred->flags & CRED_FLAG_ACCEPT) {
300 gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
301 char serviceName[5 + MAXHOSTNAMELEN];
303 /* default host-based service is host@localhost */
304 memcpy(serviceName, "host@", 5);
305 if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
306 major = GSS_S_FAILURE;
307 *minor = GSSEAP_NO_HOSTNAME;
311 nameBuf.value = serviceName;
312 nameBuf.length = strlen((char *)nameBuf.value);
314 major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
315 nameMech, &cred->name);
316 if (GSS_ERROR(major))
318 } else if (cred->flags & CRED_FLAG_INITIATE) {
319 if (defaultIdentityName == GSS_C_NO_NAME) {
320 major = GSS_S_CRED_UNAVAIL;
321 *minor = GSSEAP_NO_DEFAULT_IDENTITY;
325 cred->name = defaultIdentityName;
326 defaultIdentityName = GSS_C_NO_NAME;
328 cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
331 assert(cred->name != GSS_C_NO_NAME);
333 if (password != GSS_C_NO_BUFFER) {
334 major = duplicateBuffer(minor, password, &cred->password);
335 if (GSS_ERROR(major))
338 cred->flags |= CRED_FLAG_PASSWORD;
339 } else if (defaultCreds.value != NULL &&
340 (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
341 cred->password = defaultCreds;
343 defaultCreds.length = 0;
344 defaultCreds.value = NULL;
346 cred->flags |= CRED_FLAG_PASSWORD;
347 } else if (cred->flags & CRED_FLAG_INITIATE) {
349 * OK, here we need to ask the supplicant if we have creds or it
350 * will acquire them, so GS2 can know whether to prompt for a
354 && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
356 major = GSS_S_CRED_UNAVAIL;
357 *minor = GSSEAP_NO_DEFAULT_CRED;
361 if (pActualMechs != NULL) {
362 major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
363 if (GSS_ERROR(major))
368 *timeRec = GSS_C_INDEFINITE;
372 major = GSS_S_COMPLETE;
376 if (GSS_ERROR(major))
377 gssEapReleaseCred(&tmpMinor, &cred);
378 gssEapReleaseName(&tmpMinor, &defaultIdentityName);
379 gss_release_buffer(&tmpMinor, &defaultIdentity);
380 if (defaultCreds.value != NULL) {
381 memset(defaultCreds.value, 0, defaultCreds.length);
382 gss_release_buffer(&tmpMinor, &defaultCreds);
389 * Return TRUE if cred available for mechanism. Caller need no acquire
390 * lock because mechanisms list is immutable.
393 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
398 assert(mech != GSS_C_NO_OID);
400 if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
403 gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
409 gssEapInquireCred(OM_uint32 *minor,
412 OM_uint32 *pLifetime,
413 gss_cred_usage_t *cred_usage,
414 gss_OID_set *mechanisms)
417 time_t now, lifetime;
420 major = gssEapDuplicateName(minor, cred->name, name);
421 if (GSS_ERROR(major))
425 if (cred_usage != NULL) {
426 OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
429 case CRED_FLAG_INITIATE:
430 *cred_usage = GSS_C_INITIATE;
432 case CRED_FLAG_ACCEPT:
433 *cred_usage = GSS_C_ACCEPT;
436 *cred_usage = GSS_C_BOTH;
441 if (mechanisms != NULL) {
442 if (cred->mechanisms != GSS_C_NO_OID_SET)
443 major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
445 major = gssEapIndicateMechs(minor, mechanisms);
446 if (GSS_ERROR(major))
450 if (cred->expiryTime == 0) {
451 lifetime = GSS_C_INDEFINITE;
454 lifetime = now - cred->expiryTime;
459 if (pLifetime != NULL) {
460 *pLifetime = lifetime;
464 *minor = GSSEAP_CRED_EXPIRED;
465 return GSS_S_CREDENTIALS_EXPIRED;
468 major = GSS_S_COMPLETE;