import re import string # Module for translating KDB principal flags between string and # integer forms. # # When run as a standalone script, print out C tables to insert into # lib/kadm5/str_conv.c. # KDB principal flag definitions copied from kdb.h KRB5_KDB_DISALLOW_POSTDATED = 0x00000001 KRB5_KDB_DISALLOW_FORWARDABLE = 0x00000002 KRB5_KDB_DISALLOW_TGT_BASED = 0x00000004 KRB5_KDB_DISALLOW_RENEWABLE = 0x00000008 KRB5_KDB_DISALLOW_PROXIABLE = 0x00000010 KRB5_KDB_DISALLOW_DUP_SKEY = 0x00000020 KRB5_KDB_DISALLOW_ALL_TIX = 0x00000040 KRB5_KDB_REQUIRES_PRE_AUTH = 0x00000080 KRB5_KDB_REQUIRES_HW_AUTH = 0x00000100 KRB5_KDB_REQUIRES_PWCHANGE = 0x00000200 KRB5_KDB_DISALLOW_SVR = 0x00001000 KRB5_KDB_PWCHANGE_SERVICE = 0x00002000 KRB5_KDB_SUPPORT_DESMD5 = 0x00004000 KRB5_KDB_NEW_PRINC = 0x00008000 KRB5_KDB_OK_AS_DELEGATE = 0x00100000 KRB5_KDB_OK_TO_AUTH_AS_DELEGATE = 0x00200000 KRB5_KDB_NO_AUTH_DATA_REQUIRED = 0x00400000 KRB5_KDB_LOCKDOWN_KEYS = 0x00800000 # Input tables -- list of tuples of the form (name, flag, invert) # Input forms from kadmin.c _kadmin_pflags = [ ("allow_postdated", KRB5_KDB_DISALLOW_POSTDATED, True), ("allow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, True), ("allow_tgs_req", KRB5_KDB_DISALLOW_TGT_BASED, True), ("allow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, True), ("allow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, True), ("allow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, True), ("allow_tix", KRB5_KDB_DISALLOW_ALL_TIX, True), ("requires_preauth", KRB5_KDB_REQUIRES_PRE_AUTH, False), ("requires_hwauth", KRB5_KDB_REQUIRES_HW_AUTH, False), ("needchange", KRB5_KDB_REQUIRES_PWCHANGE, False), ("allow_svr", KRB5_KDB_DISALLOW_SVR, True), ("password_changing_service", KRB5_KDB_PWCHANGE_SERVICE, False), ("support_desmd5", KRB5_KDB_SUPPORT_DESMD5, False), ("ok_as_delegate", KRB5_KDB_OK_AS_DELEGATE, False), ("ok_to_auth_as_delegate", KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, False), ("no_auth_data_required", KRB5_KDB_NO_AUTH_DATA_REQUIRED, False), ("lockdown_keys", KRB5_KDB_LOCKDOWN_KEYS, False), ] # Input forms from lib/kadm5/str_conv.c _strconv_pflags = [ ("postdateable", KRB5_KDB_DISALLOW_POSTDATED, True), ("forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, True), ("tgt-based", KRB5_KDB_DISALLOW_TGT_BASED, True), ("renewable", KRB5_KDB_DISALLOW_RENEWABLE, True), ("proxiable", KRB5_KDB_DISALLOW_PROXIABLE, True), ("dup-skey", KRB5_KDB_DISALLOW_DUP_SKEY, True), ("allow-tickets", KRB5_KDB_DISALLOW_ALL_TIX, True), ("preauth", KRB5_KDB_REQUIRES_PRE_AUTH, False), ("hwauth", KRB5_KDB_REQUIRES_HW_AUTH, False), ("ok-as-delegate", KRB5_KDB_OK_AS_DELEGATE, False), ("pwchange", KRB5_KDB_REQUIRES_PWCHANGE, False), ("service", KRB5_KDB_DISALLOW_SVR, True), ("pwservice", KRB5_KDB_PWCHANGE_SERVICE, False), ("md5", KRB5_KDB_SUPPORT_DESMD5, False), ("ok-to-auth-as-delegate", KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, False), ("no-auth-data-required", KRB5_KDB_NO_AUTH_DATA_REQUIRED, False), ("lockdown-keys", KRB5_KDB_LOCKDOWN_KEYS, False), ] # kdb.h symbol prefix _prefix = 'KRB5_KDB_' _prefixlen = len(_prefix) # Names of flags, as printed by kadmin (derived from kdb.h symbols). # To be filled in by _setup_tables(). _flagnames = {} # Translation table to map hyphens to underscores _squash = string.maketrans('-', '_') # Combined input-to-flag lookup table, to be filled in by # _setup_tables() pflags = {} # Tables of ftuples, to be filled in by _setup_tables() kadmin_ftuples = [] strconv_ftuples = [] sym_ftuples = [] all_ftuples = [] # Inverted table to look up ftuples by flag value, to be filled in by # _setup_tables() kadmin_itable = {} strconv_itable = {} sym_itable = {} # Bundle some methods that are useful for writing tests. class Ftuple(object): def __init__(self, name, flag, invert): self.name = name self.flag = flag self.invert = invert def __repr__(self): return "Ftuple" + str((self.name, self.flag, self.invert)) def flagname(self): return _flagnames[self.flag] def setspec(self): return ('-' if self.invert else '+') + self.name def clearspec(self): return ('+' if self.invert else '-') + self.name def spec(self, doset): return self.setspec() if doset else self.clearspec() def _setup_tables(): # Filter globals for 'KRB5_KDB_' prefix to create lookup tables. # Make the reasonable assumption that the Python runtime doesn't # define any names with that prefix by default. global _flagnames for k, v in globals().items(): if k.startswith(_prefix): _flagnames[v] = k[_prefixlen:] # Construct an input table based on kdb.h constant names by # truncating the "KRB5_KDB_" prefix and downcasing. sym_pflags = [] for v, k in sorted(_flagnames.items()): sym_pflags.append((k.lower(), v, False)) global kadmin_ftuples, strconv_ftuples, sym_ftuples, all_ftuples for x in _kadmin_pflags: kadmin_ftuples.append(Ftuple(*x)) for x in _strconv_pflags: strconv_ftuples.append(Ftuple(*x)) for x in sym_pflags: sym_ftuples.append(Ftuple(*x)) all_ftuples = kadmin_ftuples + strconv_ftuples + sym_ftuples # Populate combined input-to-flag lookup table. This will # eliminate some duplicates. global pflags for x in all_ftuples: name = x.name.translate(_squash) pflags[name] = x global kadmin_itable, strconv_itable, sym_itable for x in kadmin_ftuples: kadmin_itable[x.flag] = x for x in strconv_ftuples: strconv_itable[x.flag] = x for x in sym_ftuples: sym_itable[x.flag] = x # Convert the bit number of a flag to a string. Remove the # 'KRB5_KDB_' prefix. Give an 8-digit hexadecimal number if the flag # is unknown. def flagnum2str(n): s = _flagnames.get(1 << n) if s is None: return "0x%08x" % ((1 << n) & 0xffffffff) return s # Return a list of flag names from a flag word. def flags2namelist(flags): a = [] for n in xrange(32): if flags & (1 << n): a.append(flagnum2str(n)) return a # Given a single specifier in the form {+|-}flagname, return a tuple # of the form (flagstoset, flagstoclear). def flagspec2mask(s): req_neg = False if s[0] == '-': req_neg = True s = s[1:] elif s[0] == '+': s = s[1:] s = s.lower().translate(_squash) x = pflags.get(s) if x is not None: flag, invert = x.flag, x.invert else: # Maybe it's a hex number. if not s.startswith('0x'): raise ValueError flag, invert = int(s, 16), False if req_neg: invert = not invert return (0, ~flag) if invert else (flag, ~0) # Given a string containing a space/comma separated list of specifiers # of the form {+|-}flagname, return a tuple of the form (flagstoset, # flagstoclear). This shares the same limitation as # kadm5int_acl_parse_restrictions() of losing the distinction between # orderings when the same flag bit appears in both the positive and # the negative sense. def speclist2mask(s): toset, toclear = (0, ~0) for x in re.split('[\t, ]+', s): fset, fclear = flagspec2mask(x) toset |= fset toclear &= fclear return toset, toclear # Print C table of input flag specifiers for lib/kadm5/str_conv.c. def _print_ftbl(): print 'static const struct flag_table_row ftbl[] = {' a = sorted(pflags.items(), key=lambda (k, v): (v.flag, -v.invert, k)) for k, v in a: s1 = ' {"%s",' % k s2 = '%-31s KRB5_KDB_%s,' % (s1, v.flagname()) print '%-63s %d},' % (s2, 1 if v.invert else 0) print '};' print '#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))' # Print C table of output flag names for lib/kadm5/str_conv.c. def _print_outflags(): print 'static const char *outflags[] = {' for i in xrange(32): flag = 1 << i if flag > max(_flagnames.keys()): break try: s = ' "%s",' % _flagnames[flag] except KeyError: s = ' NULL,' print '%-32s/* 0x%08x */' % (s, flag) print '};' print '#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))' # Print out C tables to insert into lib/kadm5/str_conv.c. def _main(): _print_ftbl() print _print_outflags() _setup_tables() if __name__ == '__main__': _main()