diff options
Diffstat (limited to 'src/lib/krb5/krb/conv_princ.c')
| -rw-r--r-- | src/lib/krb5/krb/conv_princ.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/src/lib/krb5/krb/conv_princ.c b/src/lib/krb5/krb/conv_princ.c new file mode 100644 index 000000000000..c33c67dda503 --- /dev/null +++ b/src/lib/krb5/krb/conv_princ.c @@ -0,0 +1,358 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/conv_princ.c */ +/* + * Copyright 1992 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Build a principal from a V4 specification, or separate a V5 + * principal into name, instance, and realm. + * + * NOTE: This is highly site specific, and is only really necessary + * for sites who need to convert from V4 to V5. It is used by both + * the KDC and the kdb5_convert program. Since its use is highly + * specialized, the necesary information is just going to be + * hard-coded in this file. + */ + +#include "k5-int.h" +#include <string.h> +#include <ctype.h> + +/* The maximum sizes for V4 aname, realm, sname, and instance +1 */ +/* Taken from krb.h */ +#define ANAME_SZ 40 +#define REALM_SZ 40 +#define SNAME_SZ 40 +#define INST_SZ 40 + +struct krb_convert { + char *v4_str; + char *v5_str; + unsigned int flags : 8; + unsigned int len : 8; +}; + +#define DO_REALM_CONVERSION 0x00000001 + +/* + * Kadmin doesn't do realm conversion because it's currently + * kadmin/REALM.NAME. Zephyr doesn't because it's just zephyr/zephyr. + * + * "Realm conversion" is a bit of a misnomer; really, the v5 name is + * using a FQDN or something that looks like it, where the v4 name is + * just using the first label. Sometimes that second principal name + * component is a hostname, sometimes the realm name, sometimes it's + * neither. + * + * This list should probably be more configurable, and more than + * likely on a per-realm basis, so locally-defined services can be + * added, or not. + */ +static const struct krb_convert sconv_list[] = { + /* Realm conversion, Change service name */ +#define RC(V5NAME,V4NAME) { V5NAME, V4NAME, DO_REALM_CONVERSION, sizeof(V5NAME)-1 } + /* Realm conversion */ +#define R(NAME) { NAME, NAME, DO_REALM_CONVERSION, sizeof(NAME)-1 } + /* No Realm conversion */ +#define NR(NAME) { NAME, NAME, 0, sizeof(NAME)-1 } + + NR("kadmin"), + RC("rcmd", "host"), + R("discuss"), + R("rvdsrv"), + R("sample"), + R("olc"), + R("pop"), + R("sis"), + R("rfs"), + R("imap"), + R("ftp"), + R("ecat"), + R("daemon"), + R("gnats"), + R("moira"), + R("prms"), + R("mandarin"), + R("register"), + R("changepw"), + R("sms"), + R("afpserver"), + R("gdss"), + R("news"), + R("abs"), + R("nfs"), + R("tftp"), + NR("zephyr"), + R("http"), + R("khttp"), + R("pgpsigner"), + R("irc"), + R("mandarin-agent"), + R("write"), + R("palladium"), + {0, 0, 0, 0}, +#undef R +#undef RC +#undef NR +}; + +/* + * char *strnchr(s, c, n) + * char *s; + * char c; + * unsigned int n; + * + * returns a pointer to the first occurrence of character c in the + * string s, or a NULL pointer if c does not occur in in the string; + * however, at most the first n characters will be considered. + * + * This falls in the "should have been in the ANSI C library" + * category. :-) + */ +static char *strnchr(register char *s, register int c, + register unsigned int n) +{ + if (n < 1) + return 0; + + while (n-- && *s) { + if (*s == c) + return s; + s++; + } + return 0; +} + + +/* XXX This calls for a new error code */ +#define KRB5_INVALID_PRINCIPAL KRB5_LNAME_BADFORMAT + +krb5_error_code KRB5_CALLCONV +krb5_524_conv_principal(krb5_context context, krb5_const_principal princ, + char *name, char *inst, char *realm) +{ + const struct krb_convert *p; + const krb5_data *compo; + char *c, *tmp_realm, *tmp_prealm; + unsigned int tmp_realm_len; + int retval; + + if (context->profile == 0) + return KRB5_CONFIG_CANTOPEN; + + *name = *inst = '\0'; + switch (princ->length) { + case 2: + /* Check if this principal is listed in the table */ + compo = &princ->data[0]; + p = sconv_list; + while (p->v4_str) { + if (p->len == compo->length + && memcmp(p->v5_str, compo->data, compo->length) == 0) { + /* + * It is, so set the new name now, and chop off + * instance's domain name if requested. + */ + if (strlcpy(name, p->v4_str, ANAME_SZ) >= ANAME_SZ) + return KRB5_INVALID_PRINCIPAL; + if (p->flags & DO_REALM_CONVERSION) { + compo = &princ->data[1]; + c = strnchr(compo->data, '.', compo->length); + if (!c || (c - compo->data) >= INST_SZ - 1) + return KRB5_INVALID_PRINCIPAL; + memcpy(inst, compo->data, (size_t) (c - compo->data)); + inst[c - compo->data] = '\0'; + } + break; + } + p++; + } + /* If inst isn't set, the service isn't listed in the table, */ + /* so just copy it. */ + if (*inst == '\0') { + compo = &princ->data[1]; + if (compo->length >= INST_SZ - 1) + return KRB5_INVALID_PRINCIPAL; + if (compo->length > 0) + memcpy(inst, compo->data, compo->length); + inst[compo->length] = '\0'; + } + /* fall through */ + case 1: + /* name may have been set above; otherwise, just copy it */ + if (*name == '\0') { + compo = &princ->data[0]; + if (compo->length >= ANAME_SZ) + return KRB5_INVALID_PRINCIPAL; + if (compo->length > 0) + memcpy(name, compo->data, compo->length); + name[compo->length] = '\0'; + } + break; + default: + return KRB5_INVALID_PRINCIPAL; + } + + compo = &princ->realm; + + tmp_prealm = malloc(compo->length + 1); + if (tmp_prealm == NULL) + return ENOMEM; + strncpy(tmp_prealm, compo->data, compo->length); + tmp_prealm[compo->length] = '\0'; + + /* Ask for v4_realm corresponding to + krb5 principal realm from krb5.conf realms stanza */ + + retval = profile_get_string(context->profile, KRB5_CONF_REALMS, + tmp_prealm, KRB5_CONF_V4_REALM, 0, + &tmp_realm); + free(tmp_prealm); + if (retval) { + return retval; + } else { + if (tmp_realm == 0) { + if (compo->length > REALM_SZ - 1) + return KRB5_INVALID_PRINCIPAL; + strncpy(realm, compo->data, compo->length); + realm[compo->length] = '\0'; + } else { + tmp_realm_len = strlen(tmp_realm); + if (tmp_realm_len > REALM_SZ - 1) + return KRB5_INVALID_PRINCIPAL; + strncpy(realm, tmp_realm, tmp_realm_len); + realm[tmp_realm_len] = '\0'; + profile_release_string(tmp_realm); + } + } + return 0; +} + +krb5_error_code KRB5_CALLCONV +krb5_425_conv_principal(krb5_context context, const char *name, + const char *instance, const char *realm, + krb5_principal *princ) +{ + const struct krb_convert *p; + char buf[256]; /* V4 instances are limited to 40 characters */ + krb5_error_code retval; + char *domain, *cp; + char **full_name = 0; + const char *names[5], *names2[2]; + void* iterator = NULL; + char** v4realms = NULL; + char* realm_name = NULL; + char* dummy_value = NULL; + + /* First, convert the realm, since the v4 realm is not necessarily the same as the v5 realm + To do that, iterate over all the realms in the config file, looking for a matching + v4_realm line */ + names2 [0] = KRB5_CONF_REALMS; + names2 [1] = NULL; + retval = profile_iterator_create (context -> profile, names2, PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, &iterator); + while (retval == 0) { + retval = profile_iterator (&iterator, &realm_name, &dummy_value); + if ((retval == 0) && (realm_name != NULL)) { + names [0] = KRB5_CONF_REALMS; + names [1] = realm_name; + names [2] = KRB5_CONF_V4_REALM; + names [3] = NULL; + + retval = profile_get_values (context -> profile, names, &v4realms); + if ((retval == 0) && (v4realms != NULL) && (v4realms [0] != NULL) && (strcmp (v4realms [0], realm) == 0)) { + realm = realm_name; + break; + } else if (retval == PROF_NO_RELATION) { + /* If it's not found, just keep going */ + retval = 0; + } + } else if ((retval == 0) && (realm_name == NULL)) { + break; + } + if (v4realms != NULL) { + profile_free_list(v4realms); + v4realms = NULL; + } + if (realm_name != NULL) { + profile_release_string (realm_name); + realm_name = NULL; + } + if (dummy_value != NULL) { + profile_release_string (dummy_value); + dummy_value = NULL; + } + } + + if (instance) { + if (instance[0] == '\0') { + instance = 0; + goto not_service; + } + p = sconv_list; + while (1) { + if (!p->v4_str) + goto not_service; + if (!strcmp(p->v4_str, name)) + break; + p++; + } + name = p->v5_str; + if ((p->flags & DO_REALM_CONVERSION) && !strchr(instance, '.')) { + names[0] = KRB5_CONF_REALMS; + names[1] = realm; + names[2] = KRB5_CONF_V4_INSTANCE_CONVERT; + names[3] = instance; + names[4] = 0; + retval = profile_get_values(context->profile, names, &full_name); + if (retval == 0 && full_name && full_name[0]) { + instance = full_name[0]; + } else { + strncpy(buf, instance, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + retval = krb5_get_realm_domain(context, realm, &domain); + if (retval) + return retval; + if (domain) { + for (cp = domain; *cp; cp++) + if (isupper((unsigned char) (*cp))) + *cp = tolower((unsigned char) *cp); + strncat(buf, ".", sizeof(buf) - 1 - strlen(buf)); + strncat(buf, domain, sizeof(buf) - 1 - strlen(buf)); + free(domain); + } + instance = buf; + } + } + } + +not_service: + retval = krb5_build_principal(context, princ, strlen(realm), realm, name, + instance, NULL); + if (iterator) profile_iterator_free (&iterator); + if (full_name) profile_free_list(full_name); + if (v4realms) profile_free_list(v4realms); + if (realm_name) profile_release_string (realm_name); + if (dummy_value) profile_release_string (dummy_value); + return retval; +} |
