#define AN_TO_LN_RULES
#include "k5-int.h"
#include <ctype.h>
#if HAVE_REGEX_H
#include <regex.h>
#endif
#include <string.h>
#if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXPR_H) && defined(HAVE_COMPILE)
#define RE_BUF_SIZE 1024
#include <regexpr.h>
#endif
#define MAX_FORMAT_BUFFER ((size_t)1024)
#ifndef min
#define min(a,b) ((a>b) ? b : a)
#endif
#ifdef ANAME_DB
#define KDBM_OPEN(db, fl, mo) dbm_open(db, fl, mo)
#define KDBM_CLOSE(db) dbm_close(db)
#define KDBM_FETCH(db, key) dbm_fetch(db, key)
#endif
static char *
aname_full_to_mapping_name(char *fprincname)
{
char *atp;
size_t mlen;
char *mname;
mname = (char *) NULL;
if (fprincname) {
atp = strrchr(fprincname, '@');
if (!atp)
atp = &fprincname[strlen(fprincname)];
mlen = (size_t) (atp - fprincname);
if ((mname = (char *) malloc(mlen+1))) {
strncpy(mname, fprincname, mlen);
mname[mlen] = '\0';
}
}
return(mname);
}
#ifdef ANAME_DB
static krb5_error_code
db_an_to_ln(context, dbname, aname, lnsize, lname)
krb5_context context;
char *dbname;
krb5_const_principal aname;
const unsigned int lnsize;
char *lname;
{
#if !defined(_WIN32)
DBM *db;
krb5_error_code retval;
datum key, contents;
char *princ_name;
if ((retval = krb5_unparse_name(context, aname, &princ_name)))
return(retval);
key.dptr = princ_name;
key.dsize = strlen(princ_name)+1;
db = KDBM_OPEN(dbname, O_RDONLY, 0600);
if (!db) {
krb5_xfree(princ_name);
return KRB5_LNAME_CANTOPEN;
}
contents = KDBM_FETCH(db, key);
krb5_xfree(princ_name);
if (contents.dptr == NULL) {
retval = KRB5_LNAME_NOTRANS;
} else {
strncpy(lname, contents.dptr, lnsize);
if (lnsize < contents.dsize)
retval = KRB5_CONFIG_NOTENUFSPACE;
else if (lname[contents.dsize-1] != '\0')
retval = KRB5_LNAME_BADFORMAT;
else
retval = 0;
}
(void) KDBM_CLOSE(db);
return retval;
#else
return KRB5_LNAME_NOTRANS;
#endif
}
#endif
#ifdef AN_TO_LN_RULES
static krb5_error_code
aname_do_match(char *string, char **contextp)
{
krb5_error_code kret;
char *regexp, *startp, *endp = 0;
size_t regexlen;
#if HAVE_REGCOMP
regex_t match_exp;
regmatch_t match_match;
#elif HAVE_REGEXPR_H
char regexp_buffer[RE_BUF_SIZE];
#endif
kret = 0;
if (**contextp == '(') {
kret = KRB5_CONFIG_BADFORMAT;
startp = (*contextp) + 1;
endp = strchr(startp, ')');
if (endp) {
regexlen = (size_t) (endp - startp);
regexp = (char *) malloc((size_t) regexlen+1);
kret = ENOMEM;
if (regexp) {
strncpy(regexp, startp, regexlen);
regexp[regexlen] = '\0';
kret = KRB5_LNAME_NOTRANS;
#if HAVE_REGCOMP
if (!regcomp(&match_exp, regexp, REG_EXTENDED) &&
!regexec(&match_exp, string, 1, &match_match, 0)) {
if ((match_match.rm_so == 0) &&
(match_match.rm_eo == strlen(string)))
kret = 0;
}
regfree(&match_exp);
#elif HAVE_REGEXPR_H
compile(regexp,
regexp_buffer,
®exp_buffer[RE_BUF_SIZE]);
if (step(string, regexp_buffer)) {
if ((loc1 == string) &&
(loc2 == &string[strlen(string)]))
kret = 0;
}
#elif HAVE_RE_COMP
if (!re_comp(regexp) && re_exec(string))
kret = 0;
#else
kret = 0;
#endif
free(regexp);
}
endp++;
}
else
endp = startp;
}
*contextp = endp;
return(kret);
}
#define use_bytes(x) \
out_used += (x); \
if (out_used > MAX_FORMAT_BUFFER) goto mem_err
static int
do_replacement(char *regexp, char *repl, int doall, char *in, char *out)
{
size_t out_used = 0;
#if HAVE_REGCOMP
regex_t match_exp;
regmatch_t match_match;
int matched;
char *cp;
char *op;
if (!regcomp(&match_exp, regexp, REG_EXTENDED)) {
cp = in;
op = out;
matched = 0;
do {
if (!regexec(&match_exp, cp, 1, &match_match, 0)) {
if (match_match.rm_so) {
use_bytes(match_match.rm_so);
strncpy(op, cp, match_match.rm_so);
op += match_match.rm_so;
}
use_bytes(strlen(repl));
strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out));
op += strlen(op);
cp += match_match.rm_eo;
if (!doall) {
use_bytes(strlen(cp));
strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
}
matched = 1;
}
else {
use_bytes(strlen(cp));
strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
matched = 0;
}
} while (doall && matched);
regfree(&match_exp);
}
#elif HAVE_REGEXPR_H
int matched;
char *cp;
char *op;
char regexp_buffer[RE_BUF_SIZE];
size_t sdispl, edispl;
compile(regexp,
regexp_buffer,
®exp_buffer[RE_BUF_SIZE]);
cp = in;
op = out;
matched = 0;
do {
if (step(cp, regexp_buffer)) {
sdispl = (size_t) (loc1 - cp);
edispl = (size_t) (loc2 - cp);
if (sdispl) {
use_bytes(sdispl);
strncpy(op, cp, sdispl);
op += sdispl;
}
use_bytes(strlen(repl));
strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out));
op += strlen(repl);
cp += edispl;
if (!doall) {
use_bytes(strlen(cp));
strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
}
matched = 1;
}
else {
use_bytes(strlen(cp));
strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
matched = 0;
}
} while (doall && matched);
#else
memcpy(out, in, MAX_FORMAT_BUFFER);
#endif
return 1;
mem_err:
#ifdef HAVE_REGCMP
regfree(&match_exp);
#endif
return 0;
}
#undef use_bytes
static krb5_error_code
aname_replacer(char *string, char **contextp, char **result)
{
krb5_error_code kret;
char *in;
char *out;
char *cp, *ep, *tp;
char *rule, *repl;
size_t rule_size, repl_size;
int doglobal;
kret = ENOMEM;
*result = (char *) NULL;
if ((in = (char *) malloc(MAX_FORMAT_BUFFER)) &&
(out = (char *) malloc(MAX_FORMAT_BUFFER))) {
strncpy(out, string, MAX_FORMAT_BUFFER - 1);
out[MAX_FORMAT_BUFFER - 1] = '\0';
in[0] = '\0';
kret = 0;
for (cp = *contextp; *cp; ) {
while (isspace((int) (*cp)))
cp++;
if ((cp[0] == 's') &&
(cp[1] == '/') &&
(ep = strchr(&cp[2], '/')) &&
(tp = strchr(&ep[1], '/'))) {
rule_size = (size_t) (ep - &cp[2]);
repl_size = (size_t) (tp - &ep[1]);
if ((rule = (char *) malloc(rule_size+1)) &&
(repl = (char *) malloc(repl_size+1))) {
strncpy(rule, &cp[2], rule_size);
strncpy(repl, &ep[1], repl_size);
rule[rule_size] = repl[repl_size] = '\0';
doglobal = (tp[1] == 'g') ? 1 : 0;
if (doglobal)
tp++;
ep = in;
in = out;
out = ep;
memset(out, '\0', MAX_FORMAT_BUFFER);
if (!do_replacement(rule, repl, doglobal, in, out)) {
free(rule);
free(repl);
kret = KRB5_LNAME_NOTRANS;
break;
}
free(rule);
free(repl);
if (strlen(out) == 0) {
kret = KRB5_LNAME_NOTRANS;
break;
}
}
else {
free(rule);
kret = ENOMEM;
break;
}
}
else {
kret = KRB5_CONFIG_BADFORMAT;
break;
}
cp = &tp[1];
}
free(in);
if (!kret)
*result = out;
else
free(out);
}
return(kret);
}
static krb5_error_code
rule_an_to_ln(krb5_context context, char *rule, krb5_const_principal aname, const unsigned int lnsize, char *lname)
{
krb5_error_code kret;
char *current;
char *fprincname;
char *selstring = 0;
int num_comps, compind;
size_t selstring_used;
char *cout;
krb5_const krb5_data *datap;
char *outstring;
current = rule;
if (!(kret = krb5_unparse_name(context, aname, &fprincname))) {
if (*current == '[') {
if (sscanf(current+1,"%d:", &num_comps) == 1) {
if (num_comps == aname->length) {
current = strchr(current, ':');
selstring = (char *) malloc(MAX_FORMAT_BUFFER);
selstring_used = 0;
if (current && selstring) {
current++;
cout = selstring;
while ((*current != ']') &&
(*current != '\0')) {
if (*current == '$') {
if ((sscanf(current+1, "%d", &compind) == 1) &&
(compind <= num_comps) &&
(datap =
(compind > 0)
? krb5_princ_component(context, aname,
compind-1)
: krb5_princ_realm(context, aname))
) {
if ((datap->length < MAX_FORMAT_BUFFER)
&& (selstring_used+datap->length
< MAX_FORMAT_BUFFER)) {
selstring_used += datap->length;
} else {
kret = ENOMEM;
goto errout;
}
strncpy(cout,
datap->data,
(unsigned) datap->length);
cout += datap->length;
*cout = '\0';
current++;
while (isdigit((int) (*current)))
current++;
}
else
kret = KRB5_CONFIG_BADFORMAT;
}
else {
*cout = *current;
cout++;
*cout = '\0';
current++;
}
}
if (*current == ']')
current++;
else
kret = KRB5_CONFIG_BADFORMAT;
errout: if (kret)
free(selstring);
}
}
else
kret = KRB5_LNAME_NOTRANS;
}
else
kret = KRB5_CONFIG_BADFORMAT;
}
else {
if (!(selstring = aname_full_to_mapping_name(fprincname)))
kret = ENOMEM;
}
krb5_xfree(fprincname);
}
if (!kret) {
if (*current == '(')
kret = aname_do_match(selstring, ¤t);
if (!kret) {
outstring = (char *) NULL;
kret = aname_replacer(selstring, ¤t, &outstring);
if (outstring) {
if (strlcpy(lname, outstring, lnsize) >= lnsize)
kret = KRB5_CONFIG_NOTENUFSPACE;
free(outstring);
}
}
free(selstring);
}
return(kret);
}
#endif
static krb5_error_code
default_an_to_ln(krb5_context context, krb5_const_principal aname, const unsigned int lnsize, char *lname)
{
krb5_error_code retval;
char *def_realm;
unsigned int realm_length;
realm_length = krb5_princ_realm(context, aname)->length;
if ((retval = krb5_get_default_realm(context, &def_realm))) {
return(retval);
}
if (!data_eq_string(*krb5_princ_realm(context, aname), def_realm)) {
free(def_realm);
return KRB5_LNAME_NOTRANS;
}
if (krb5_princ_size(context, aname) != 1) {
if (krb5_princ_size(context, aname) == 2 ) {
if ( strncmp(krb5_princ_component(context, aname,1)->data,def_realm,
realm_length) ||
realm_length != krb5_princ_component(context, aname,1)->length)
return KRB5_LNAME_NOTRANS;
}
else
return KRB5_LNAME_NOTRANS;
}
free(def_realm);
strncpy(lname, krb5_princ_component(context, aname,0)->data,
min(krb5_princ_component(context, aname,0)->length,lnsize));
if (lnsize <= krb5_princ_component(context, aname,0)->length ) {
retval = KRB5_CONFIG_NOTENUFSPACE;
} else {
lname[krb5_princ_component(context, aname,0)->length] = '\0';
retval = 0;
}
return retval;
}
krb5_error_code KRB5_CALLCONV
krb5_aname_to_localname(krb5_context context, krb5_const_principal aname, int lnsize_in, char *lname)
{
krb5_error_code kret;
char *realm;
char *pname;
char *mname;
const char *hierarchy[5];
char **mapping_values;
int i, nvalid;
char *cp, *s;
char *typep, *argp;
unsigned int lnsize;
if (lnsize_in < 0)
return KRB5_CONFIG_NOTENUFSPACE;
lnsize = lnsize_in;
if (!(kret = krb5_get_default_realm(context, &realm))) {
if (!(kret = krb5_unparse_name(context, aname, &pname))) {
if ((mname = aname_full_to_mapping_name(pname))) {
hierarchy[0] = "realms";
hierarchy[1] = realm;
hierarchy[2] = "auth_to_local_names";
hierarchy[3] = mname;
hierarchy[4] = (char *) NULL;
if (!(kret = profile_get_values(context->profile,
hierarchy,
&mapping_values))) {
for (nvalid=0; mapping_values[nvalid]; nvalid++);
s = mapping_values[nvalid-1];
cp = s + strlen(s);
while (cp > s) {
cp--;
if (!isspace((int)(*cp)))
break;
*cp = '\0';
}
if (strlcpy(lname, mapping_values[nvalid-1],
lnsize) >= lnsize)
kret = KRB5_CONFIG_NOTENUFSPACE;
profile_free_list(mapping_values);
}
else {
hierarchy[0] = "realms";
hierarchy[1] = realm;
hierarchy[2] = "auth_to_local";
hierarchy[3] = (char *) NULL;
if (!(kret = profile_get_values(context->profile,
hierarchy,
&mapping_values))) {
for (i=0; mapping_values[i]; i++) {
typep = mapping_values[i];
argp = strchr(typep, ':');
if (argp) {
*argp = '\0';
argp++;
}
#ifdef ANAME_DB
if (!strcmp(typep, "DB") && argp) {
kret = db_an_to_ln(context,
argp,
aname,
lnsize,
lname);
if (kret != KRB5_LNAME_NOTRANS)
break;
}
else
#endif
#ifdef AN_TO_LN_RULES
if (!strcmp(typep, "RULE") && argp) {
kret = rule_an_to_ln(context,
argp,
aname,
lnsize,
lname);
if (kret != KRB5_LNAME_NOTRANS)
break;
}
else
#endif
if (!strcmp(typep, "DEFAULT") && !argp) {
kret = default_an_to_ln(context,
aname,
lnsize,
lname);
if (kret != KRB5_LNAME_NOTRANS)
break;
}
else {
kret = KRB5_CONFIG_BADFORMAT;
break;
}
}
profile_free_list(mapping_values);
}
else {
kret = default_an_to_ln(context,
aname,
lnsize,
lname);
}
}
free(mname);
}
else
kret = ENOMEM;
krb5_xfree(pname);
}
krb5_xfree(realm);
}
return(kret);
}