typedef struct OpaqueKLPrincipal {
krb5_context context;
krb5_principal principal;
} Principal;
static KLStatus __KLTranslateKLPrincipal (KLPrincipal inPrincipal);
KLStatus KLCreatePrincipalFromTriplet (const char *inName,
const char *inInstance,
const char *inRealm,
KLPrincipal *outPrincipal)
{
KLKerberosVersion version = (__KLRealmHasKerberos5Profile (inRealm) ||
!__KLRealmHasKerberos4Profile (inRealm)) ? kerberosVersion_V5 :
kerberosVersion_V4;
return __KLCreatePrincipalFromTriplet (inName, inInstance, inRealm, version, outPrincipal);
}
KLStatus __KLCreatePrincipalFromTriplet (const char *inName,
const char *inInstance,
const char *inRealm,
KLKerberosVersion inKerberosVersion,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
if (inName == NULL) { err = KLError_ (klParameterErr); }
if (inInstance == NULL) { err = KLError_ (klParameterErr); }
if (inRealm == NULL) { err = KLError_ (klParameterErr); }
if (outPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
principal = (KLPrincipal) malloc (sizeof (Principal));
if (principal == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
principal->context = NULL;
principal->principal = NULL;
}
if (err == klNoErr) {
err = krb5_init_context (&principal->context);
}
if (err == klNoErr) {
if (inKerberosVersion == kerberosVersion_V4) {
err = krb5_425_conv_principal (principal->context, inName, inInstance, inRealm,
&principal->principal);
} else if (inKerberosVersion == kerberosVersion_V5) {
err = krb5_build_principal_ext (principal->context, &principal->principal,
strlen (inRealm), inRealm,
strlen (inName), inName,
strlen (inInstance), inInstance, NULL);
} else {
err = KLError_ (klInvalidVersionErr);
}
}
if (err == klNoErr) {
err = __KLTranslateKLPrincipal (principal);
}
if (err == klNoErr) {
*outPrincipal = principal;
principal = NULL;
}
if (principal != NULL) {
if (principal->context != NULL) {
if (principal->principal != NULL) {
krb5_free_principal (principal->context, principal->principal);
}
krb5_free_context (principal->context);
}
free (principal);
}
return KLError_ (err);
}
KLStatus KLCreatePrincipalFromString (const char *inFullPrincipal,
KLKerberosVersion inKerberosVersion,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
if (inFullPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
principal = (KLPrincipal) malloc (sizeof (Principal));
if (principal == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
principal->context = NULL;
principal->principal = NULL;
}
if (err == klNoErr) {
err = krb5_init_context (&principal->context);
}
if (inKerberosVersion == kerberosVersion_V4) {
char name [ANAME_SZ];
char instance [INST_SZ];
char realm [REALM_SZ];
if (err == klNoErr) {
name[0] = '\0';
instance[0] = '\0';
realm[0] = '\0';
err = kname_parse (name, instance, realm, (char *) inFullPrincipal);
err = __KLRemapKerberos4Error (err);
}
if (err == klNoErr) {
if (realm[0] == '\0') {
err = krb_get_lrealm (realm, 1);
err = __KLRemapKerberos4Error (err);
}
}
if (err == klNoErr) {
err = krb5_425_conv_principal (principal->context, name, instance, realm, &principal->principal);
}
} else if (inKerberosVersion == kerberosVersion_V5) {
if (err == klNoErr) {
err = krb5_parse_name (principal->context, inFullPrincipal, &principal->principal);
}
} else {
err = KLError_ (klInvalidVersionErr);
}
if (err == klNoErr) {
err = __KLTranslateKLPrincipal (principal);
}
if (err == klNoErr) {
*outPrincipal = principal;
principal = NULL;
}
if (principal != NULL) {
if (principal->context != NULL) {
if (principal->principal != NULL) {
krb5_free_principal (principal->context, principal->principal);
}
krb5_free_context (principal->context);
}
free (principal);
}
return KLError_ (err);
}
KLStatus KLCreatePrincipalFromKerberos5Principal (krb5_principal inKerberos5Principal,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
if (inKerberos5Principal == NULL) { err = KLError_ (klParameterErr); }
if (outPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
principal = (KLPrincipal) malloc (sizeof (Principal));
if (principal == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
principal->context = NULL;
principal->principal = NULL;
}
if (err == klNoErr) {
err = krb5_init_context (&principal->context);
}
if (err == klNoErr) {
err = krb5_copy_principal (principal->context,
inKerberos5Principal, &principal->principal);
}
if (err == klNoErr) {
*outPrincipal = principal;
principal = NULL;
}
if (principal != NULL) {
if (principal->context != NULL) {
if (principal->principal != NULL) {
krb5_free_principal (principal->context, principal->principal);
}
krb5_free_context (principal->context);
}
free (principal);
}
return KLError_ (err);
}
KLStatus KLCreatePrincipalFromPrincipal (KLPrincipal inPrincipal,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
err = KLCreatePrincipalFromKerberos5Principal (inPrincipal->principal, outPrincipal);
}
return KLError_ (err);
}
KLStatus KLGetTripletFromPrincipal (KLPrincipal inPrincipal,
char **outName,
char **outInstance,
char **outRealm)
{
return __KLGetTripletFromPrincipal (inPrincipal, kerberosVersion_Any, outName, outInstance, outRealm);
}
KLStatus __KLGetTripletFromPrincipal (KLPrincipal inPrincipal,
KLKerberosVersion inKerberosVersion,
char **outName,
char **outInstance,
char **outRealm)
{
KLStatus err = klNoErr;
KLKerberosVersion version = inKerberosVersion;
char *name = NULL;
char *instance = NULL;
char *realm = NULL;
if (inPrincipal == NULL) { return KLError_ (klBadPrincipalErr); }
if (outName == NULL) { return KLError_ (klParameterErr); }
if (outInstance == NULL) { return KLError_ (klParameterErr); }
if (outRealm == NULL) { return KLError_ (klParameterErr); }
if (err == klNoErr) {
switch (version) {
case kerberosVersion_V4:
case kerberosVersion_V5:
break;
case kerberosVersion_All:
case kerberosVersion_Any:
if (__KLPrincipalHasKerberos5Profile (inPrincipal) ||
!__KLPrincipalHasKerberos4Profile (inPrincipal)) {
version = kerberosVersion_V5;
} else {
version = kerberosVersion_V4;
}
break;
default:
err = KLError_ (klInvalidVersionErr);
break;
}
}
if (version == kerberosVersion_V5) {
int componentCount = 0;
if (err == klNoErr) {
componentCount = krb5_princ_size (inPrincipal->context, inPrincipal->principal);
if (componentCount > 2) { err = KLError_ (klBadPrincipalErr); }
}
if (err == klNoErr) {
krb5_data *nameData = krb5_princ_name (inPrincipal->context, inPrincipal->principal);
err = __KLCreateStringFromBuffer (nameData->data, nameData->length, &name);
}
if (err == klNoErr) {
if (componentCount > 1) {
krb5_data *instanceData = krb5_princ_component (inPrincipal->context, inPrincipal->principal, 1);
err = __KLCreateStringFromBuffer (instanceData->data, instanceData->length, &instance);
} else {
err = __KLCreateString ("", &instance);
}
}
if (err == klNoErr) {
krb5_data *realmData = krb5_princ_realm (inPrincipal->context, inPrincipal->principal);
err = __KLCreateStringFromBuffer (realmData->data, realmData->length, &realm);
}
} else if (version == kerberosVersion_V4) {
char v4Name [ANAME_SZ];
char v4Instance [INST_SZ];
char v4Realm [REALM_SZ];
if (err == klNoErr) {
err = krb5_524_conv_principal (inPrincipal->context, inPrincipal->principal,
v4Name, v4Instance, v4Realm);
}
if (err == klNoErr) {
err = __KLCreateString (v4Name, &name);
}
if (err == klNoErr) {
err = __KLCreateString (v4Instance, &instance);
}
if (err == klNoErr) {
err = __KLCreateString (v4Realm, &realm);
}
} else {
err = KLError_ (klInvalidVersionErr);
}
if (err == klNoErr) {
*outName = name;
*outInstance = instance;
*outRealm = realm;
} else {
if (name != NULL) { KLDisposeString (name); }
if (instance != NULL) { KLDisposeString (instance); }
if (realm != NULL) { KLDisposeString (realm); }
}
return KLError_ (err);
}
KLStatus KLGetStringFromPrincipal (KLPrincipal inPrincipal,
KLKerberosVersion inKerberosVersion,
char **outFullPrincipal)
{
KLStatus err = klNoErr;
KLKerberosVersion version = inKerberosVersion;
char *principalString = NULL;
krb5_context context = NULL;
if (inPrincipal == NULL) { return KLError_ (klBadPrincipalErr); }
if (outFullPrincipal == NULL) { return KLError_ (klParameterErr); }
switch (version) {
case kerberosVersion_V4:
case kerberosVersion_V5:
break;
case kerberosVersion_All:
case kerberosVersion_Any:
if (__KLPrincipalHasKerberos5Profile (inPrincipal) || !__KLPrincipalHasKerberos4Profile (inPrincipal)) {
version = kerberosVersion_V5;
} else {
version = kerberosVersion_V4;
}
break;
default:
err = KLError_ (klInvalidVersionErr);
break;
}
if (err == klNoErr) {
err = krb5_init_context (&context);
}
if (version == kerberosVersion_V5) {
char *tempPrincipalString = NULL;
if (err == klNoErr) {
err = krb5_unparse_name (inPrincipal->context, inPrincipal->principal, &tempPrincipalString);
}
if (err == klNoErr) {
err = __KLCreateString (tempPrincipalString, &principalString);
}
if (tempPrincipalString != NULL) { krb5_free_unparsed_name (inPrincipal->context, tempPrincipalString); }
} else if (version == kerberosVersion_V4) {
char name [ANAME_SZ];
char instance [INST_SZ];
char realm [REALM_SZ];
char tempPrincipalString [MAX_K_NAME_SZ];
if (err == klNoErr) {
err = krb5_524_conv_principal (inPrincipal->context, inPrincipal->principal, name, instance, realm);
}
if (err == klNoErr) {
err = kname_unparse (tempPrincipalString, name, instance, realm);
}
if (err == klNoErr) {
err = __KLCreateString (tempPrincipalString, &principalString);
}
} else {
err = KLError_ (klInvalidVersionErr);
}
if (err == klNoErr) {
*outFullPrincipal = principalString;
} else {
if (principalString != NULL) { KLDisposeString (principalString); }
}
if (context != NULL) { krb5_free_context (context); }
return KLError_ (err);
}
KLStatus KLGetDisplayStringFromPrincipal (KLPrincipal inPrincipal,
KLKerberosVersion inKerberosVersion,
char **outFullPrincipal)
{
KLStatus err = klNoErr;
char *principalString = NULL;
char *displayPrincipalString = NULL;
if (err == klNoErr) {
err = KLGetStringFromPrincipal (inPrincipal, inKerberosVersion, &principalString);
}
if (err == klNoErr) {
err = __KLCreateString (principalString, &displayPrincipalString);
}
if (err == klNoErr) {
KLIndex i = 0, j = 0;
for (i = 0; i <= strlen (principalString); i++) {
if ((principalString[i] == '\\') && (principalString[i+1] != '\\')) {
continue;
}
displayPrincipalString[j] = principalString[i]; j++;
if (principalString[i+1] == '\\') {
i++; }
}
err = __KLCreateString (displayPrincipalString, outFullPrincipal);
}
if (principalString != NULL) { KLDisposeString (principalString); }
if (displayPrincipalString != NULL) { KLDisposeString (displayPrincipalString); }
return KLError_ (err);
}
KLStatus KLComparePrincipal (KLPrincipal inFirstPrincipal,
KLPrincipal inSecondPrincipal,
KLBoolean *outAreEquivalent)
{
KLStatus err = klNoErr;
if (inFirstPrincipal == NULL) { err = KLError_ (klBadPrincipalErr); }
if (inSecondPrincipal == NULL) { err = KLError_ (klBadPrincipalErr); }
if (outAreEquivalent == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
*outAreEquivalent = krb5_principal_compare (inFirstPrincipal->context,
inFirstPrincipal->principal,
inSecondPrincipal->principal);
}
return KLError_ (err);
}
KLStatus KLDisposePrincipal (KLPrincipal inPrincipal)
{
if (inPrincipal == NULL) { return KLError_ (klBadPrincipalErr); }
if (inPrincipal->context != NULL) {
if (inPrincipal->principal != NULL) {
krb5_free_principal (inPrincipal->context, inPrincipal->principal);
}
krb5_free_context (inPrincipal->context);
}
free (inPrincipal);
return klNoErr;
}
#pragma mark -
KLStatus __KLCreatePrincipalFromKerberos5Principal (krb5_principal inPrincipal,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
principal = (KLPrincipal) malloc (sizeof (Principal));
if (principal == NULL) { err = KLError_ (klMemFullErr); }
}
if (err == klNoErr) {
principal->context = NULL;
principal->principal = NULL;
}
if (err == klNoErr) {
err = krb5_init_context (&principal->context);
}
if (err == klNoErr) {
err = krb5_copy_principal (principal->context, inPrincipal, &principal->principal);
}
if (err == klNoErr) {
err = __KLTranslateKLPrincipal (principal);
}
if (err == klNoErr) {
*outPrincipal = principal;
principal = NULL;
}
if (principal != NULL) {
if (principal->context != NULL) {
if (principal->principal != NULL) {
krb5_free_principal (principal->context, principal->principal);
}
krb5_free_context (principal->context);
}
free (principal);
}
return KLError_ (err);
}
krb5_principal __KLGetKerberos5PrincipalFromPrincipal (KLPrincipal inPrincipal)
{
if (inPrincipal == NULL) {
return NULL;
} else {
return inPrincipal->principal;
}
}
KLStatus __KLGetRealmFromPrincipal (KLPrincipal inPrincipal, KLKerberosVersion inKerberosVersion, char **outRealm)
{
KLStatus err = klNoErr;
char *realm = NULL;
if (inPrincipal == NULL) { err = KLError_ (klBadPrincipalErr); }
if (outRealm == NULL) { err = KLError_ (klParameterErr); }
switch (inKerberosVersion) {
case kerberosVersion_V5:
case kerberosVersion_All:
case kerberosVersion_Any:
if (err == klNoErr) {
krb5_data *realmData = krb5_princ_realm (inPrincipal->context, inPrincipal->principal);
err = __KLCreateStringFromBuffer (realmData->data, realmData->length, &realm);
}
break;
case kerberosVersion_V4:
if (err == klNoErr) {
char v4Name [ANAME_SZ];
char v4Instance [INST_SZ];
char v4Realm [REALM_SZ];
if (err == klNoErr) {
err = krb5_524_conv_principal (inPrincipal->context, inPrincipal->principal, v4Name, v4Instance, v4Realm);
}
if (err == klNoErr) {
err = __KLCreateString (v4Realm, &realm);
}
}
break;
default:
err = KLError_ (klInvalidVersionErr);
break;
}
if (err == klNoErr) {
*outRealm = realm;
} else {
if (realm != NULL) { KLDisposeString (realm); }
}
return KLError_ (err);
}
KLBoolean __KLPrincipalIsTicketGrantingService (KLPrincipal inPrincipal, KLKerberosVersion inVersion)
{
KLStatus err = klNoErr;
KLBoolean isTicketGrantingService = false;
krb5_data *name = NULL;
KLIndex components;
char *tgsName = (inVersion == kerberosVersion_V4) ? KRB_TICKET_GRANTING_TICKET : KRB5_TGS_NAME;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
components = krb5_princ_size (inPrincipal->context, inPrincipal->principal);
name = krb5_princ_name (inPrincipal->context, inPrincipal->principal);
}
if (err == klNoErr) {
isTicketGrantingService = (components == 2) && (strlen (tgsName) == name->length) &&
(strncmp (name->data, tgsName, name->length) == 0); }
return isTicketGrantingService;
}
#pragma mark -
static KLStatus __KLTranslateKLPrincipal (KLPrincipal inPrincipal)
{
KLStatus err = klNoErr;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (err == klNoErr) {
char *name = NULL;
char *instance = NULL;
char *realm = NULL;
if (__KLGetTripletFromPrincipal (inPrincipal, kerberosVersion_V5, &name, &instance, &realm) == klNoErr) {
KLBoolean changed = false;
char *realName = NULL;
char *realInstance = NULL;
char *realRealm = NULL;
krb5_principal principal = NULL;
changed = __KLTranslatePrincipal (name, instance, realm, &realName, &realInstance, &realRealm);
if (!changed) {
realName = name;
realInstance = instance;
realRealm = realm;
}
if (err == klNoErr) {
err = krb5_build_principal_ext (inPrincipal->context, &principal,
strlen (realRealm), realRealm,
strlen (realName), realName,
strlen (realInstance), realInstance, NULL);
}
if (err == klNoErr) {
krb5_principal swap = inPrincipal->principal;
inPrincipal->principal = principal;
principal = swap;
}
if (changed) {
if (realName != NULL) { KLDisposeString (realName); }
if (realInstance != NULL) { KLDisposeString (realInstance); }
if (realRealm != NULL) { KLDisposeString (realRealm); }
}
if (principal != NULL) { krb5_free_principal (inPrincipal->context, principal); }
}
if (name != NULL) { KLDisposeString (name); }
if (instance != NULL) { KLDisposeString (instance); }
if (realm != NULL) { KLDisposeString (realm); }
}
return KLError_ (err);
}