#include "k5-int.h"
#include "admin_internal.h"
#include "adm_proto.h"
#include <ctype.h>
static const char default_tupleseps[] = ", \t";
static const char default_ksaltseps[] = ":";
struct flag_table_row {
const char *spec;
krb5_flags flag;
int invert;
};
static const struct flag_table_row ftbl[] = {
{"allow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 1},
{"postdateable", KRB5_KDB_DISALLOW_POSTDATED, 1},
{"disallow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 0},
{"allow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},
{"forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},
{"disallow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 0},
{"allow_tgs_req", KRB5_KDB_DISALLOW_TGT_BASED, 1},
{"tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 1},
{"disallow_tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 0},
{"allow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},
{"renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},
{"disallow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 0},
{"allow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},
{"proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},
{"disallow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 0},
{"allow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},
{"dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},
{"disallow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 0},
{"allow_tickets", KRB5_KDB_DISALLOW_ALL_TIX, 1},
{"allow_tix", KRB5_KDB_DISALLOW_ALL_TIX, 1},
{"disallow_all_tix", KRB5_KDB_DISALLOW_ALL_TIX, 0},
{"preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
{"requires_pre_auth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
{"requires_preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
{"hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
{"requires_hw_auth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
{"requires_hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
{"needchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
{"pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
{"requires_pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
{"allow_svr", KRB5_KDB_DISALLOW_SVR, 1},
{"service", KRB5_KDB_DISALLOW_SVR, 1},
{"disallow_svr", KRB5_KDB_DISALLOW_SVR, 0},
{"password_changing_service", KRB5_KDB_PWCHANGE_SERVICE, 0},
{"pwchange_service", KRB5_KDB_PWCHANGE_SERVICE, 0},
{"pwservice", KRB5_KDB_PWCHANGE_SERVICE, 0},
{"md5", KRB5_KDB_SUPPORT_DESMD5, 0},
{"support_desmd5", KRB5_KDB_SUPPORT_DESMD5, 0},
{"new_princ", KRB5_KDB_NEW_PRINC, 0},
{"ok_as_delegate", KRB5_KDB_OK_AS_DELEGATE, 0},
{"ok_to_auth_as_delegate", KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0},
{"no_auth_data_required", KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},
{"lockdown_keys", KRB5_KDB_LOCKDOWN_KEYS, 0},
};
#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))
static const char *outflags[] = {
"DISALLOW_POSTDATED",
"DISALLOW_FORWARDABLE",
"DISALLOW_TGT_BASED",
"DISALLOW_RENEWABLE",
"DISALLOW_PROXIABLE",
"DISALLOW_DUP_SKEY",
"DISALLOW_ALL_TIX",
"REQUIRES_PRE_AUTH",
"REQUIRES_HW_AUTH",
"REQUIRES_PWCHANGE",
NULL,
NULL,
"DISALLOW_SVR",
"PWCHANGE_SERVICE",
"SUPPORT_DESMD5",
"NEW_PRINC",
NULL,
NULL,
NULL,
NULL,
"OK_AS_DELEGATE",
"OK_TO_AUTH_AS_DELEGATE",
"NO_AUTH_DATA_REQUIRED",
"LOCKDOWN_KEYS",
};
#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))
static krb5_error_code
raw_flagspec_to_mask(const char *s, int req_neg, krb5_flags *toset,
krb5_flags *toclear)
{
int found = 0, invert = 0;
size_t i;
krb5_flags flag;
unsigned long ul;
for (i = 0; !found && i < NFTBL; i++) {
if (strcmp(s, ftbl[i].spec) != 0)
continue;
found = 1;
invert = ftbl[i].invert;
flag = ftbl[i].flag;
}
if (!found && strncmp(s, "0x", 2) == 0) {
ul = strtoul(s, NULL, 16) & 0xffffffff;
flag = (krb5_flags)ul;
found = 1;
}
if (!found)
return EINVAL;
if (req_neg)
invert = !invert;
if (invert)
*toclear &= ~flag;
else
*toset |= flag;
return 0;
}
krb5_error_code
krb5_flagspec_to_mask(const char *spec, krb5_flags *toset, krb5_flags *toclear)
{
int req_neg = 0;
char *copy, *cp, *s;
krb5_error_code retval;
s = copy = strdup(spec);
if (s == NULL)
return ENOMEM;
if (*s == '-') {
req_neg = 1;
s++;
} else if (*s == '+')
s++;
for (cp = s; *cp != '\0'; cp++) {
if (*cp == '-')
*cp = '_';
if (isupper((unsigned char)*cp))
*cp = tolower((unsigned char)*cp);
}
retval = raw_flagspec_to_mask(s, req_neg, toset, toclear);
free(copy);
return retval;
}
krb5_error_code
krb5_flagnum_to_string(int flagnum, char **outstr)
{
const char *s = NULL;
*outstr = NULL;
if ((unsigned int)flagnum < NOUTFLAGS)
s = outflags[flagnum];
if (s == NULL) {
if (asprintf(outstr, "0x%08lx", 1UL << flagnum) == -1)
*outstr = NULL;
} else {
*outstr = strdup(s);
}
if (*outstr == NULL)
return ENOMEM;
return 0;
}
krb5_error_code
krb5_flags_to_strings(krb5_int32 flags, char ***outarray)
{
char **a = NULL, **a_new = NULL, **ap;
size_t amax = 0, i;
krb5_error_code retval;
*outarray = NULL;
for (i = 0; i < 32; i++) {
if (!(flags & (1UL << i)))
continue;
a_new = realloc(a, (amax + 2) * sizeof(*a));
if (a_new == NULL) {
retval = ENOMEM;
goto cleanup;
}
a = a_new;
retval = krb5_flagnum_to_string(i, &a[amax++]);
a[amax] = NULL;
if (retval)
goto cleanup;
}
*outarray = a;
return 0;
cleanup:
for (ap = a; ap != NULL && *ap != NULL; ap++) {
free(*ap);
}
free(a);
return retval;
}
krb5_boolean
krb5_keysalt_is_present(krb5_key_salt_tuple *ksaltlist, krb5_int32 nksalts,
krb5_enctype enctype, krb5_int32 salttype)
{
krb5_boolean foundit;
int i;
foundit = 0;
if (ksaltlist) {
for (i=0; i<nksalts; i++) {
if ((ksaltlist[i].ks_enctype == enctype) &&
((ksaltlist[i].ks_salttype == salttype) ||
(salttype < 0))) {
foundit = 1;
break;
}
}
}
return(foundit);
}
static krb5_error_code
string_to_keysalt(char *s, const char *ksaltseps,
krb5_enctype *etype, krb5_int32 *stype)
{
char *sp;
const char *ksseps = (ksaltseps != NULL) ? ksaltseps : default_ksaltseps;
krb5_error_code ret = 0;
sp = strpbrk(s, ksseps);
if (sp != NULL) {
*sp++ = '\0';
}
ret = krb5_string_to_enctype(s, etype);
if (ret)
return ret;
*stype = KRB5_KDB_SALTTYPE_NORMAL;
if (sp == NULL)
return 0;
return krb5_string_to_salttype(sp, stype);
}
krb5_error_code
krb5_string_to_keysalts(const char *string, const char *tupleseps,
const char *ksaltseps, krb5_boolean dups,
krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp)
{
char *copy, *p, *ksp;
char *tlasts = NULL;
const char *tseps = (tupleseps != NULL) ? tupleseps : default_tupleseps;
krb5_int32 nksalts = 0;
krb5_int32 stype;
krb5_enctype etype;
krb5_error_code ret = 0;
krb5_key_salt_tuple *ksalts = NULL, *ksalts_new = NULL;
*ksaltp = NULL;
*nksaltp = 0;
p = copy = strdup(string);
if (p == NULL)
return ENOMEM;
while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {
p = NULL;
if (string_to_keysalt(ksp, ksaltseps, &etype, &stype) != 0)
continue;
if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))
continue;
ksalts_new = realloc(ksalts, (nksalts + 1) * sizeof(*ksalts));
if (ksalts_new == NULL) {
ret = ENOMEM;
goto cleanup;
}
ksalts = ksalts_new;
ksalts[nksalts].ks_enctype = etype;
ksalts[nksalts].ks_salttype = stype;
nksalts++;
}
*ksaltp = ksalts;
*nksaltp = nksalts;
cleanup:
if (ret)
free(ksalts);
free(copy);
return ret;
}
krb5_error_code
krb5_keysalt_iterate(krb5_key_salt_tuple *ksaltlist, krb5_int32 nksalt,
krb5_boolean ignoresalt,
krb5_error_code (*iterator)(krb5_key_salt_tuple *,
void *),
void *arg)
{
int i;
krb5_error_code kret;
krb5_key_salt_tuple scratch;
kret = 0;
for (i=0; i<nksalt; i++) {
scratch.ks_enctype = ksaltlist[i].ks_enctype;
scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;
if (!krb5_keysalt_is_present(ksaltlist,
i,
scratch.ks_enctype,
scratch.ks_salttype)) {
kret = (*iterator)(&scratch, arg);
if (kret)
break;
}
}
return(kret);
}