#include "mech_locl.h"
#include <heim_threads.h>
#include <Security/Security.h>
OM_uint32 GSSAPI_LIB_FUNCTION
gss_aapl_initial_cred(const gss_name_t desired_name,
gss_const_OID desired_mech,
CFDictionaryRef attributes,
gss_cred_id_t * output_cred_handle,
CFErrorRef *error)
{
OM_uint32 major_status, minor_status;
gss_buffer_desc credential;
CFStringRef usage;
CFTypeRef password, certificate;
gss_cred_usage_t cred_usage = GSS_C_INITIATE;
gss_const_OID cred_type;
void *cred_value;
credential.value = NULL;
credential.length = 0;
HEIM_WARN_BLOCKING("gss_aapl_initial_cred", warn_once);
if (error)
*error = NULL;
if (desired_mech == GSS_C_NO_OID)
return GSS_S_BAD_MECH;
if (desired_name == GSS_C_NO_NAME)
return GSS_S_BAD_NAME;
if (output_cred_handle == NULL)
return GSS_S_CALL_INACCESSIBLE_READ;
*output_cred_handle = GSS_C_NO_CREDENTIAL;
password = CFDictionaryGetValue(attributes, kGSSICPassword);
certificate = CFDictionaryGetValue(attributes, kGSSICCertificate);
if (password == NULL && certificate == NULL)
return GSS_S_CALL_INACCESSIBLE_READ;
usage = CFDictionaryGetValue(attributes, kGSSCredentialUsage);
if (usage && CFGetTypeID(usage) == CFStringGetTypeID()) {
if (CFStringCompare(usage, kGSS_C_INITIATE, 0) == kCFCompareEqualTo)
cred_usage = GSS_C_INITIATE;
else if (CFStringCompare(usage, kGSS_C_ACCEPT, 0) == kCFCompareEqualTo)
cred_usage = GSS_C_ACCEPT;
else if (CFStringCompare(usage, kGSS_C_BOTH, 0) == kCFCompareEqualTo)
cred_usage = GSS_C_BOTH;
else
return GSS_S_FAILURE;
}
if (password && CFGetTypeID(password) == CFStringGetTypeID()) {
char *str = rk_cfstring2cstring(password);
if (str == NULL)
return GSS_S_FAILURE;
credential.value = str;
credential.length = strlen(str);
cred_value = &credential;
cred_type = GSS_C_CRED_PASSWORD;
} else if (password && CFGetTypeID(password) == CFDataGetTypeID()) {
credential.value = malloc(CFDataGetLength(password));
if (credential.value == NULL)
return GSS_S_FAILURE;
credential.length = CFDataGetLength(password);
memcpy(credential.value, CFDataGetBytePtr(password), CFDataGetLength(password));
cred_value = &credential;
cred_type = GSS_C_CRED_PASSWORD;
} else if (certificate && CFGetTypeID(certificate) == SecIdentityGetTypeID()) {
cred_value = rk_UNCONST(certificate);
cred_type = GSS_C_CRED_SecIdentity;
} else if (certificate && CFGetTypeID(certificate) == SecCertificateGetTypeID()) {
cred_value = rk_UNCONST(certificate);
cred_type = GSS_C_CRED_SecIdentity;
} else
return GSS_S_FAILURE;
major_status = gss_acquire_cred_ext(&minor_status,
desired_name,
cred_type,
cred_value,
GSS_C_INDEFINITE,
desired_mech,
cred_usage,
output_cred_handle);
if (credential.length) {
memset(credential.value, 0, credential.length);
free(credential.value);
}
if (major_status && error) {
*error = _gss_mg_cferror(major_status, minor_status, desired_mech);
return major_status;
}
if (CFDictionaryGetValue(attributes, kGSSICVerifyCredential)) {
gss_buffer_set_t bufferset = GSS_C_NO_BUFFER_SET;
major_status = gss_inquire_cred_by_oid(&minor_status, *output_cred_handle,
GSS_C_CRED_VALIDATE, &bufferset);
if (major_status == GSS_S_COMPLETE)
gss_release_buffer_set(&minor_status, &bufferset);
else {
if (error)
*error = _gss_mg_cferror(major_status, minor_status, desired_mech);
gss_destroy_cred(&minor_status, output_cred_handle);
}
}
return major_status;
}
OM_uint32 GSSAPI_LIB_FUNCTION
gss_aapl_change_password(const gss_name_t name,
gss_const_OID mech,
CFDictionaryRef attributes,
CFErrorRef *error)
{
struct _gss_mechanism_name *mn = NULL;
char *oldpw = NULL, *newpw = NULL;
OM_uint32 maj_stat, min_stat;
gssapi_mech_interface m;
CFStringRef old, new;
_gss_load_mech();
m = __gss_get_mechanism(mech);
if (m == NULL) {
maj_stat = GSS_S_BAD_MECH;
min_stat = 0;
goto out;
}
if (m->gm_aapl_change_password == NULL) {
maj_stat = GSS_S_UNAVAILABLE;
min_stat = 0;
goto out;
}
maj_stat = _gss_find_mn(&min_stat, (struct _gss_name *)name, mech, &mn);
if (maj_stat != GSS_S_COMPLETE)
goto out;
old = CFDictionaryGetValue(attributes, kGSSChangePasswordOldPassword);
new = CFDictionaryGetValue(attributes, kGSSChangePasswordNewPassword);
heim_assert(old != NULL, "old password missing");
heim_assert(new != NULL, "new password missing");
oldpw = rk_cfstring2cstring(old);
newpw = rk_cfstring2cstring(new);
if (oldpw == NULL || newpw == NULL) {
maj_stat = GSS_S_FAILURE;
min_stat = 0;
goto out;
}
maj_stat = m->gm_aapl_change_password(&min_stat,
mn->gmn_name,
oldpw, newpw);
if (maj_stat)
_gss_mg_error(m, min_stat);
out:
if (maj_stat && error)
*error = _gss_mg_cferror(maj_stat, min_stat, mech);
if (oldpw) {
memset(oldpw, 0, strlen(oldpw));
free(oldpw);
}
if (newpw) {
memset(newpw, 0, strlen(newpw));
free(newpw);
}
return maj_stat;
}