KLPrincipalTranslator.c [plain text]
#define kKLPT_TranslatePrincipal CFSTR("KerberosLoginPrincipalTranslation_TranslatePrincipal")
#define kKLPT_ReleasePrincipal CFSTR("KerberosLoginPrincipalTranslation_ReleasePrincipal")
#define kKLPT_InitializePlugin CFSTR("KerberosLoginPrincipalTranslation_InitializePlugin")
typedef KLStatus (*KLPT_InitializePlugin) (
KLPT_APIVersion inAPIVersion);
typedef KLStatus (*KLPT_TranslatePrincipal) (
const char* inName,
const char* inInstance,
const char* inRealm,
char** outName,
char** outInstance,
char** outRealm,
KLBoolean* outChanged);
typedef void (*KLPT_ReleasePrincipal) (
const char* inName,
const char* inInstance,
const char* inRealm);
static KLStatus __KLFindTranslator (const char *inTranslatorName,
CFBundleRef *outBundle,
KLPT_TranslatePrincipal *outTranslate,
KLPT_ReleasePrincipal *outRelease);
static KLStatus __KLCallTranslator (KLPT_TranslatePrincipal inTranslator,
KLPT_ReleasePrincipal inRelease,
const char *inName,
const char *inInstance,
const char *inRealm,
char **outName,
char **outInstance,
char **outRealm,
KLBoolean *outChanged);
#pragma mark -
KLBoolean __KLTranslatePrincipal (const char *inName,
const char *inInstance,
const char *inRealm,
char **outName,
char **outInstance,
char **outRealm)
{
KLStatus err = klNoErr;
KLBoolean changed = false;
char translatorName[MAXPATHLEN];
krb5_context context = NULL;
profile_t profile = NULL;
const char *libdefaultRealmList[4] = { "libdefaults", inRealm, "principal_translation", NULL };
const char *libdefaultList[3] = { "libdefaults", "principal_translation", NULL };
const char *v5RealmsList[4] = { "realms", inRealm, "principal_translation", NULL };
const char *v4RealmsList[4] = { REALMS_V4_PROF_REALMS_SECTION, inRealm, "principal_translation", NULL };
char **values = NULL;
CFBundleRef translatorBundle = NULL;
KLPT_TranslatePrincipal translatePrincipal = NULL;
KLPT_ReleasePrincipal releasePrincipal = NULL;
if (err == klNoErr) {
err = krb5_init_context (&context);
}
if (err == klNoErr) {
err = krb5_get_profile (context, &profile);
}
if (err == klNoErr) {
err = profile_get_values (profile, libdefaultRealmList, &values);
if (err != klNoErr) {
err = profile_get_values (profile, libdefaultList, &values);
}
if ((err != klNoErr) && __KLRealmHasKerberos5Profile (inRealm)) {
err = profile_get_values (profile, v5RealmsList, &values);
}
if ((err != klNoErr) && __KLRealmHasKerberos4Profile (inRealm)) {
err = profile_get_values (profile, v4RealmsList, &values);
}
}
if (err == klNoErr) {
if ((values[0] != NULL) && (strlen (values[0]) < (MAXPATHLEN - 1))) {
strcpy (translatorName, values[0]);
} else {
err = KLError_ (klParameterErr);
}
}
if (err == klNoErr) {
dprintf ("TranslatePrincipal: translating realm '%s' with translator '%s'\n", inRealm, translatorName);
err = __KLFindTranslator (translatorName, &translatorBundle, &translatePrincipal, &releasePrincipal);
}
if (err == klNoErr) {
if ((translatePrincipal != NULL) && (releasePrincipal != NULL)) {
err = __KLCallTranslator (translatePrincipal, releasePrincipal,
inName, inInstance, inRealm,
outName, outInstance, outRealm, &changed);
}
}
if (translatorBundle != NULL) {
dprintf ("TranslatePrincipal: Unloaded translator '%s'\n", translatorName);
CFBundleUnloadExecutable (translatorBundle);
CFRelease (translatorBundle);
}
if (values != NULL) { profile_free_list (values); }
if (profile != NULL) { profile_abandon (profile); }
if (context != NULL) { krb5_free_context (context); }
return changed;
}
#pragma mark -
static KLStatus __KLFindTranslator (const char *inTranslatorName,
CFBundleRef *outBundle,
KLPT_TranslatePrincipal *outTranslate,
KLPT_ReleasePrincipal *outRelease)
{
KLStatus err = klNoErr;
char bundleName[MAXPATHLEN];
CFStringRef translatorString = NULL;
CFURLRef translatorURL = NULL;
CFBundleRef translatorBundle = NULL;
KLBoolean bundleLoaded = false;
KLPT_InitializePlugin pluginInitFunction = NULL;
if (inTranslatorName == NULL) { err = KLError_ (klParameterErr); }
if (outBundle == NULL) { err = KLError_ (klParameterErr); }
if (outTranslate == NULL) { err = KLError_ (klParameterErr); }
if (outRelease == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
int realLength = snprintf (bundleName, MAXPATHLEN, "%s%s%s", kKLPT_PluginBundleFolder, inTranslatorName, kKLPT_PluginBundleNameSuffix);
if (MAXPATHLEN < realLength) {
err = KLError_ (klParameterErr);
}
}
if (err == klNoErr) {
translatorString = CFStringCreateWithCString (kCFAllocatorDefault, bundleName, kCFStringEncodingASCII);
if (translatorString == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
translatorURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, translatorString, kCFURLPOSIXPathStyle, true);
if (translatorURL == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
translatorBundle = CFBundleCreate (kCFAllocatorDefault, translatorURL);
if (translatorBundle == NULL) { err = KLError_ (klMemFullErr); }
}
if ((err == klNoErr) && (ddebuglevel () > 0)) {
CFStringRef bundleIDString = CFBundleGetIdentifier (translatorBundle);
if (bundleIDString != NULL) {
char id[256];
if (CFStringGetCString (bundleIDString, id, sizeof (id), kCFStringEncodingASCII)) {
dprintf ("KLFindTranslator: bundle id for '%s' is '%s'\n", bundleName, id);
} else {
dprintf ("KLFindTranslator: CFStringGetCString (idString) failed\n");
}
CFRelease (bundleIDString);
} else {
dprintf ("KLFindTranslator: CFBundleGetIdentifier (translatorBundle) failed\n");
}
}
if (err == klNoErr) {
dprintf ("KLFindTranslator: Loading '%s'...\n", bundleName);
bundleLoaded = CFBundleIsExecutableLoaded (translatorBundle);
if (bundleLoaded == false) {
bundleLoaded = CFBundleLoadExecutable (translatorBundle);
if (bundleLoaded == false) {
dprintf ("KLFindTranslator: CFBundleLoadExecutable () failed, check your bundle settings (esp. \"Executable\")\n");
}
} else {
dprintf ("KLFindTranslator: Translator already loaded?!\n");
}
if (bundleLoaded == false) { err = KLError_ (klParameterErr); }
}
if (err == klNoErr) {
pluginInitFunction = (KLPT_InitializePlugin) CFBundleGetFunctionPointerForName (translatorBundle, kKLPT_InitializePlugin);
if (pluginInitFunction == NULL) { err = KLError_ (klParameterErr); }
}
if (err == klNoErr) {
__KLBeginPlugin ();
err = pluginInitFunction (kKLPT_APIVersion_Current);
__KLEndPlugin ();
}
if (err == klNoErr) {
*outTranslate = (KLPT_TranslatePrincipal) CFBundleGetFunctionPointerForName (translatorBundle, kKLPT_TranslatePrincipal);
if (*outTranslate == NULL) { err = KLError_ (klParameterErr); }
}
if (err == klNoErr) {
*outRelease = (KLPT_ReleasePrincipal) CFBundleGetFunctionPointerForName (translatorBundle, kKLPT_ReleasePrincipal);
if (*outRelease == NULL) { err = KLError_ (klParameterErr); }
}
if (translatorString != NULL)
CFRelease (translatorString);
if (translatorURL != NULL)
CFRelease (translatorURL);
if (err == klNoErr) {
*outBundle = translatorBundle;
} else {
if (bundleLoaded ) { CFBundleUnloadExecutable (translatorBundle); }
if (translatorBundle != NULL) { CFRelease (translatorBundle); }
}
return KLError_ (err);
}
static KLStatus __KLCallTranslator (KLPT_TranslatePrincipal inTranslator,
KLPT_ReleasePrincipal inRelease,
const char *inName,
const char *inInstance,
const char *inRealm,
char **outName,
char **outInstance,
char **outRealm,
KLBoolean *outChanged)
{
KLStatus err = klNoErr;
char *newName = NULL;
char *newInstance = NULL;
char *newRealm = NULL;
KLBoolean changed = false;
if (inTranslator == NULL) { err = KLError_ (klParameterErr); }
if (inRelease == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
err = inTranslator (inName, inInstance, inRealm, &newName, &newInstance, &newRealm, &changed);
}
if ((err == klNoErr) && (ddebuglevel () > 0)) {
char *checkNewName = NULL;
char *checkNewInstance = NULL;
char *checkNewRealm = NULL;
KLBoolean checkChanged = false;
__KLBeginPlugin ();
KLStatus checkErr = inTranslator (newName, newName, newRealm, &checkNewName, &checkNewInstance, &checkNewRealm, &checkChanged);
__KLEndPlugin ();
if (checkErr == klNoErr) {
if (checkChanged) {
if ((strcmp (newName, checkNewName) != 0) ||
(strcmp (newInstance, checkNewInstance) != 0) ||
(strcmp (newRealm, checkNewRealm) != 0)) {
dprintf ("KLCallTranslator: Principal translation plugin failed idempotency test.");
err = KLError_ (klBadPrincipalErr);
*outChanged = false;
}
}
}
if ((inRelease != NULL) && (checkNewName != NULL) && (checkNewInstance != NULL) && (checkNewRealm != NULL)) {
inRelease (checkNewName, checkNewInstance, checkNewRealm);
}
}
if (changed && (newName != NULL) && (newInstance != NULL) && (newRealm != NULL)) {
char *name = NULL;
char *instance = NULL;
char *realm = NULL;
if (err == klNoErr) {
err = __KLCreateString (newName, &name);
}
if (err == klNoErr) {
err = __KLCreateString (newInstance, &instance);
}
if (err == klNoErr) {
err = __KLCreateString (newRealm, &realm);
}
if (err == klNoErr) {
*outName = name;
*outInstance = instance;
*outRealm = realm;
*outChanged = true;
}
} else {
*outChanged = false;
}
if ((inRelease != NULL) && (newName != NULL) && (newInstance != NULL) && (newRealm != NULL)) {
inRelease (newName, newInstance, newRealm);
}
return KLError_ (err);
}