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->krbCred != GSS_C_NO_CREDENTIAL)
100 gssReleaseCred(&tmpMinor, &cred->krbCred);
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)
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 *minor = GSSEAP_NO_DEFAULT_CRED;
145 major = GSS_S_CRED_UNAVAIL;
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;
193 gssEapAcquireCred(OM_uint32 *minor,
194 const gss_name_t desiredName,
195 const gss_buffer_t password,
196 OM_uint32 timeReq GSSEAP_UNUSED,
197 const gss_OID_set desiredMechs,
199 gss_cred_id_t *pCred,
200 gss_OID_set *pActualMechs,
203 OM_uint32 major, tmpMinor;
205 gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
207 /* XXX TODO validate with changed set_cred_option API */
208 *pCred = GSS_C_NO_CREDENTIAL;
210 major = gssEapAllocCred(minor, &cred);
211 if (GSS_ERROR(major))
216 cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
219 cred->flags |= CRED_FLAG_INITIATE;
222 cred->flags |= CRED_FLAG_ACCEPT;
225 major = GSS_S_FAILURE;
226 *minor = GSSEAP_BAD_USAGE;
231 if (desiredName != GSS_C_NO_NAME) {
232 GSSEAP_MUTEX_LOCK(&desiredName->mutex);
234 major = gssEapDuplicateName(minor, desiredName, &cred->name);
235 if (GSS_ERROR(major)) {
236 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
240 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
242 gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
243 gss_OID nameType = GSS_C_NO_OID;
244 char serviceName[5 + MAXHOSTNAMELEN];
246 if (cred->flags & CRED_FLAG_ACCEPT) {
247 /* default host-based service is host@localhost */
248 memcpy(serviceName, "host@", 5);
249 if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
250 major = GSS_S_FAILURE;
251 *minor = GSSEAP_NO_HOSTNAME;
255 nameBuf.value = serviceName;
256 nameBuf.length = strlen((char *)nameBuf.value);
258 nameType = GSS_C_NT_HOSTBASED_SERVICE;
259 } else if (cred->flags & CRED_FLAG_INITIATE) {
260 major = readDefaultIdentityAndCreds(minor, &nameBuf, &defaultCreds);
261 if (GSS_ERROR(major))
264 nameType = GSS_C_NT_USER_NAME;
267 if (nameBuf.length != 0) {
268 gss_OID mech = GSS_C_NO_OID;
270 if (cred->mechanisms != GSS_C_NO_OID_SET &&
271 cred->mechanisms->count == 1)
272 mech = &cred->mechanisms->elements[0];
274 major = gssEapImportName(minor, &nameBuf, nameType, mech, &cred->name);
275 if (GSS_ERROR(major))
279 if (nameBuf.value != serviceName)
280 gss_release_buffer(&tmpMinor, &nameBuf);
282 cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
285 if (password != GSS_C_NO_BUFFER) {
286 major = duplicateBuffer(minor, password, &cred->password);
287 if (GSS_ERROR(major))
290 cred->flags |= CRED_FLAG_PASSWORD;
291 } else if (defaultCreds.value != NULL) {
292 cred->password = defaultCreds;
294 defaultCreds.length = 0;
295 defaultCreds.value = NULL;
297 cred->flags |= CRED_FLAG_PASSWORD;
298 } else if (cred->flags & CRED_FLAG_INITIATE) {
300 * OK, here we need to ask the supplicant if we have creds or it
301 * will acquire them, so GS2 can know whether to prompt for a
305 && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
307 major = GSS_S_CRED_UNAVAIL;
308 *minor = GSSEAP_NO_DEFAULT_CRED;
312 major = gssEapValidateMechs(minor, desiredMechs);
313 if (GSS_ERROR(major))
316 major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
317 if (GSS_ERROR(major))
320 if (pActualMechs != NULL) {
321 major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
322 if (GSS_ERROR(major))
327 *timeRec = GSS_C_INDEFINITE;
331 major = GSS_S_COMPLETE;
335 if (GSS_ERROR(major))
336 gssEapReleaseCred(&tmpMinor, &cred);
337 if (defaultCreds.value != NULL) {
338 memset(defaultCreds.value, 0, defaultCreds.length);
339 gss_release_buffer(&tmpMinor, &defaultCreds);
346 * Return TRUE if cred available for mechanism. Caller need no acquire
347 * lock because mechanisms list is immutable.
350 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
355 assert(mech != GSS_C_NO_OID);
357 if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
360 gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);