#include "k5-int.h"
#include <stdio.h>
#define REALM_SEP '@'
#define COMPONENT_SEP '/'
static int
component_length_quoted(const krb5_data *src, int flags)
{
const char *cp = src->data;
int length = src->length;
int j;
int size = length;
if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) {
int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
!(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
for (j = 0; j < length; j++,cp++)
if ((!no_realm && *cp == REALM_SEP) ||
*cp == COMPONENT_SEP ||
*cp == '\0' || *cp == '\\' || *cp == '\t' ||
*cp == '\n' || *cp == '\b')
size++;
}
return size;
}
static int
copy_component_quoting(char *dest, const krb5_data *src, int flags)
{
int j;
const char *cp = src->data;
char *q = dest;
int length = src->length;
if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) {
if (src->length > 0)
memcpy(dest, src->data, src->length);
return src->length;
}
for (j=0; j < length; j++,cp++) {
int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
!(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
switch (*cp) {
case REALM_SEP:
if (no_realm) {
*q++ = *cp;
break;
}
case COMPONENT_SEP:
case '\\':
*q++ = '\\';
*q++ = *cp;
break;
case '\t':
*q++ = '\\';
*q++ = 't';
break;
case '\n':
*q++ = '\\';
*q++ = 'n';
break;
case '\b':
*q++ = '\\';
*q++ = 'b';
break;
case '\0':
*q++ = '\\';
*q++ = '0';
break;
default:
*q++ = *cp;
}
}
return q - dest;
}
static krb5_error_code
k5_unparse_name(krb5_context context, krb5_const_principal principal,
int flags, char **name, unsigned int *size)
{
char *q;
krb5_int32 i;
unsigned int totalsize = 0;
char *default_realm = NULL;
krb5_error_code ret = 0;
if (!principal || !name)
return KRB5_PARSE_MALFORMED;
if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) {
krb5_principal_data p;
ret = krb5_get_default_realm(context, &default_realm);
if (ret != 0)
goto cleanup;
p.realm = string2data(default_realm);
if (krb5_realm_compare(context, &p, principal))
flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
}
if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
totalsize += component_length_quoted(&principal->realm, flags);
totalsize++;
}
for (i = 0; i < principal->length; i++) {
totalsize += component_length_quoted(&principal->data[i], flags);
totalsize++;
}
if (principal->length == 0)
totalsize++;
if (size) {
if (*name && (*size < totalsize)) {
*name = realloc(*name, totalsize);
} else {
*name = malloc(totalsize);
}
*size = totalsize;
} else {
*name = malloc(totalsize);
}
if (!*name) {
ret = ENOMEM;
goto cleanup;
}
q = *name;
for (i = 0; i < principal->length; i++) {
q += copy_component_quoting(q, &principal->data[i], flags);
*q++ = COMPONENT_SEP;
}
if (i > 0)
q--;
if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
*q++ = REALM_SEP;
q += copy_component_quoting(q, &principal->realm, flags);
}
*q++ = '\0';
cleanup:
if (default_realm != NULL)
krb5_free_default_realm(context, default_realm);
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_unparse_name(krb5_context context, krb5_const_principal principal,
char **name)
{
if (name != NULL)
*name = NULL;
return k5_unparse_name(context, principal, 0, name, NULL);
}
krb5_error_code KRB5_CALLCONV
krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal,
char **name, unsigned int *size)
{
return k5_unparse_name(context, principal, 0, name, size);
}
krb5_error_code KRB5_CALLCONV
krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal,
int flags, char **name)
{
if (name != NULL)
*name = NULL;
return k5_unparse_name(context, principal, flags, name, NULL);
}
krb5_error_code KRB5_CALLCONV
krb5_unparse_name_flags_ext(krb5_context context, krb5_const_principal principal,
int flags, char **name, unsigned int *size)
{
return k5_unparse_name(context, principal, flags, name, size);
}