krb5 commit: Unify KDB principal flag conversion functions

Tom Yu tlyu at mit.edu
Thu Jul 9 13:36:43 EDT 2015


https://github.com/krb5/krb5/commit/971fae8285427b27dfd8c9a535a18eb588ee0689
commit 971fae8285427b27dfd8c9a535a18eb588ee0689
Author: Tom Yu <tlyu at mit.edu>
Date:   Thu Jul 2 16:16:07 2015 -0400

    Unify KDB principal flag conversion functions
    
    These changes unify the KDB principal flag specifiers used by kadmin,
    kdc.conf default_principal_flags, and kadm5.acl.  Each of those
    interfaces will now accept any of the historically accepted input
    forms of any of those interfaces.  Additionally, accept flag
    specifiers in the forms that kadmin prints, as well as hexadecimal
    numbers.
    
    Replace krb5_string_to_flags() with krb5_flagspec_to_mask().  The
    latter has a pseudo-ternary output, allowing different pointers for
    flags to set versus flags to clear.  Additional functionality includes
    parsing hexadecimal numbers for flag settings.
    
    Remove krb5_input_flag_to_string(), which nothing in the tree used,
    and probably hasn't ever worked properly due to long-standing gaps in
    the flag number sequence.
    
    Remove krb5_flags_to_string(), which nothing in the tree used.
    Verbose flag output can be added back through another interface if
    there is demand.
    
    Add krb5_flagnum_to_string(), which produces a string representation
    of a flag number.  Additional functionality includes output of
    hexadecimal numbers for unknown flags.
    
    Add krb5_flags_to_strings(), which produces an array of strings
    describing the flags, using the output from krb5_flagnum_to_string().
    
    ticket: 8215

 src/include/adm_proto.h                     |    8 +-
 src/kadmin/cli/kadmin.c                     |  101 ++------
 src/lib/kadm5/admin_internal.h              |    4 -
 src/lib/kadm5/alt_prof.c                    |    2 +-
 src/lib/kadm5/clnt/Makefile.in              |    2 +-
 src/lib/kadm5/clnt/libkadm5clnt_mit.exports |    6 +-
 src/lib/kadm5/srv/Makefile.in               |    2 +-
 src/lib/kadm5/srv/libkadm5srv_mit.exports   |    6 +-
 src/lib/kadm5/srv/server_acl.c              |   18 +-
 src/lib/kadm5/str_conv.c                    |  400 +++++++++++++++------------
 src/plugins/kdb/test/kdb_test.c             |    6 +-
 11 files changed, 259 insertions(+), 296 deletions(-)

diff --git a/src/include/adm_proto.h b/src/include/adm_proto.h
index 3758f5f..e99a84d 100644
--- a/src/include/adm_proto.h
+++ b/src/include/adm_proto.h
@@ -72,10 +72,10 @@ krb5_error_code krb5_aprof_get_int32(krb5_pointer, const char **,
 krb5_error_code krb5_aprof_finish(krb5_pointer);
 
 /* str_conv.c */
-krb5_error_code krb5_string_to_flags(char *, const char *, const char *,
-                                     krb5_flags *);
-krb5_error_code krb5_flags_to_string(krb5_flags, const char *, char *, size_t);
-krb5_error_code krb5_input_flag_to_string (int, char *, size_t);
+krb5_error_code krb5_flagspec_to_mask(const char *,
+                                      krb5_flags *, krb5_flags *);
+krb5_error_code krb5_flagnum_to_string(int, char **);
+krb5_error_code krb5_flags_to_strings(krb5_int32, char ***);
 
 /* keysalt.c */
 krb5_boolean krb5_keysalt_is_present(krb5_key_salt_tuple *, krb5_int32,
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index defc0fe..c9cc0b0 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -47,60 +47,6 @@
 #include <time.h>
 #include "kadmin.h"
 
-/* special struct to convert flag names for principals
-   to actual krb5_flags for a principal */
-struct pflag {
-    char *flagname;             /* name of flag as typed to CLI */
-    size_t flaglen;             /* length of string (not counting -,+) */
-    krb5_flags theflag;         /* actual principal flag to set/clear */
-    int set;                    /* 0 means clear, 1 means set (on '-') */
-};
-
-static struct pflag flags[] = {
-    {"allow_postdated",     15,     KRB5_KDB_DISALLOW_POSTDATED,    1 },
-    {"allow_forwardable",   17,     KRB5_KDB_DISALLOW_FORWARDABLE,  1 },
-    {"allow_tgs_req",       13,     KRB5_KDB_DISALLOW_TGT_BASED,    1 },
-    {"allow_renewable",     15,     KRB5_KDB_DISALLOW_RENEWABLE,    1 },
-    {"allow_proxiable",     15,     KRB5_KDB_DISALLOW_PROXIABLE,    1 },
-    {"allow_dup_skey",      14,     KRB5_KDB_DISALLOW_DUP_SKEY,     1 },
-    {"allow_tix",            9,     KRB5_KDB_DISALLOW_ALL_TIX,      1 },
-    {"requires_preauth",    16,     KRB5_KDB_REQUIRES_PRE_AUTH,     0 },
-    {"requires_hwauth",     15,     KRB5_KDB_REQUIRES_HW_AUTH,      0 },
-    {"needchange",          10,     KRB5_KDB_REQUIRES_PWCHANGE,     0 },
-    {"allow_svr",            9,     KRB5_KDB_DISALLOW_SVR,          1 },
-    {"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE,    0 },
-    {"support_desmd5",      14,     KRB5_KDB_SUPPORT_DESMD5,        0 },
-    {"ok_as_delegate",      14,     KRB5_KDB_OK_AS_DELEGATE,        0 },
-    {"ok_to_auth_as_delegate", 22,  KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0 },
-    {"no_auth_data_required", 21,   KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0 },
-};
-
-static char *prflags[] = {
-    "DISALLOW_POSTDATED",       /* 0x00000001 */
-    "DISALLOW_FORWARDABLE",     /* 0x00000002 */
-    "DISALLOW_TGT_BASED",       /* 0x00000004 */
-    "DISALLOW_RENEWABLE",       /* 0x00000008 */
-    "DISALLOW_PROXIABLE",       /* 0x00000010 */
-    "DISALLOW_DUP_SKEY",        /* 0x00000020 */
-    "DISALLOW_ALL_TIX",         /* 0x00000040 */
-    "REQUIRES_PRE_AUTH",        /* 0x00000080 */
-    "REQUIRES_HW_AUTH",         /* 0x00000100 */
-    "REQUIRES_PWCHANGE",        /* 0x00000200 */
-    "UNKNOWN_0x00000400",       /* 0x00000400 */
-    "UNKNOWN_0x00000800",       /* 0x00000800 */
-    "DISALLOW_SVR",             /* 0x00001000 */
-    "PWCHANGE_SERVICE",         /* 0x00002000 */
-    "SUPPORT_DESMD5",           /* 0x00004000 */
-    "NEW_PRINC",                /* 0x00008000 */
-    "UNKNOWN_0x00010000",       /* 0x00010000 */
-    "UNKNOWN_0x00020000",       /* 0x00020000 */
-    "UNKNOWN_0x00040000",       /* 0x00040000 */
-    "UNKNOWN_0x00080000",       /* 0x00080000 */
-    "OK_AS_DELEGATE",           /* 0x00100000 */
-    "OK_TO_AUTH_AS_DELEGATE",   /* 0x00200000 */
-    "NO_AUTH_DATA_REQUIRED",    /* 0x00400000 */
-};
-
 static krb5_boolean script_mode = FALSE;
 int exit_status = 0;
 char *def_realm = NULL;
@@ -1005,8 +951,7 @@ kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
                         krb5_boolean *nokey, krb5_key_salt_tuple **ks_tuple,
                         int *n_ks_tuple, char *caller)
 {
-    int i, attrib_set;
-    size_t j;
+    int i;
     time_t date;
     time_t now;
     krb5_error_code retval;
@@ -1019,7 +964,6 @@ kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
     *randkey = FALSE;
     *nokey = FALSE;
     for (i = 1; i < argc - 1; i++) {
-        attrib_set = 0;
         if (!strcmp("-x",argv[i])) {
             if (++i > argc - 2)
                 return -1;
@@ -1127,29 +1071,12 @@ kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
             }
             continue;
         }
-        for (j = 0; j < sizeof(flags) / sizeof(struct pflag); j++) {
-            if (strlen(argv[i]) == flags[j].flaglen + 1 &&
-                !strcmp(flags[j].flagname,
-                        &argv[i][1] /* strip off leading + or - */)) {
-                if ((flags[j].set && argv[i][0] == '-') ||
-                    (!flags[j].set && argv[i][0] == '+')) {
-                    oprinc->attributes |= flags[j].theflag;
-                    *mask |= KADM5_ATTRIBUTES;
-                    attrib_set++;
-                    break;
-                } else if ((flags[j].set && argv[i][0] == '+') ||
-                           (!flags[j].set && argv[i][0] == '-')) {
-                    oprinc->attributes &= ~flags[j].theflag;
-                    *mask |= KADM5_ATTRIBUTES;
-                    attrib_set++;
-                    break;
-                } else {
-                    return -1;
-                }
-            }
-        }
-        if (!attrib_set)
-            return -1;          /* nothing was parsed */
+        retval = krb5_flagspec_to_mask(argv[i], &oprinc->attributes,
+                                       &oprinc->attributes);
+        if (retval)
+            return -1;
+        else
+            *mask |= KADM5_ATTRIBUTES;
     }
     if (i != argc - 1)
         return -1;
@@ -1423,8 +1350,8 @@ kadmin_getprinc(int argc, char *argv[])
     krb5_error_code retval;
     const char *polname, *noexist;
     char *canon = NULL, *princstr = NULL, *modprincstr = NULL;
+    char **sp = NULL, **attrstrs = NULL;
     int i;
-    size_t j;
 
     if (!(argc == 2 || (argc == 3 && !strcmp("-terse", argv[1])))) {
         error(_("usage: get_principal [-terse] principal\n"));
@@ -1504,10 +1431,16 @@ kadmin_getprinc(int argc, char *argv[])
         printf(_("MKey: vno %d\n"), dprinc.mkvno);
 
         printf(_("Attributes:"));
-        for (j = 0; j < sizeof(prflags) / sizeof(char *); j++) {
-            if (dprinc.attributes & (krb5_flags) 1 << j)
-                printf(" %s", prflags[j]);
+        retval = krb5_flags_to_strings(dprinc.attributes, &attrstrs);
+        if (retval) {
+            com_err("get_principal", retval, _("while printing flags"));
+            return;
+        }
+        for (sp = attrstrs; sp != NULL && *sp != NULL; sp++) {
+            printf(" %s", *sp);
+            free(*sp);
         }
+        free(attrstrs);
         printf("\n");
         polname = (dprinc.policy != NULL) ? dprinc.policy : _("[none]");
         noexist = (dprinc.policy != NULL && !policy_exists(dprinc.policy)) ?
diff --git a/src/lib/kadm5/admin_internal.h b/src/lib/kadm5/admin_internal.h
index ec604b2..faf8e9c 100644
--- a/src/lib/kadm5/admin_internal.h
+++ b/src/lib/kadm5/admin_internal.h
@@ -74,8 +74,4 @@ krb5_string_to_keysalts(const char *string, const char *tupleseps,
                         const char *ksaltseps, krb5_boolean dups,
                         krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp);
 
-krb5_error_code
-krb5_string_to_flags(char* string, const char* positive, const char* negative,
-                     krb5_flags *flagsp);
-
 #endif /* __KADM5_ADMIN_INTERNAL_H__ */
diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c
index db45d13..a157093 100644
--- a/src/lib/kadm5/alt_prof.c
+++ b/src/lib/kadm5/alt_prof.c
@@ -689,7 +689,7 @@ krb5_error_code kadm5_get_config_params(krb5_context context,
                     ep++;
             }
             /* Convert this flag. */
-            if (krb5_string_to_flags(sp, "+", "-", &params.flags))
+            if (krb5_flagspec_to_mask(sp, &params.flags, &params.flags))
                 break;
             sp = ep;
         }
diff --git a/src/lib/kadm5/clnt/Makefile.in b/src/lib/kadm5/clnt/Makefile.in
index 28d66ae..9301241 100644
--- a/src/lib/kadm5/clnt/Makefile.in
+++ b/src/lib/kadm5/clnt/Makefile.in
@@ -3,7 +3,7 @@ BUILDTOP=$(REL)..$(S)..$(S)..
 LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5
 
 LIBBASE=kadm5clnt_mit
-LIBMAJOR=9
+LIBMAJOR=10
 LIBMINOR=0
 STOBJLISTS=../OBJS.ST OBJS.ST
 SHLIB_EXPDEPS=\
diff --git a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
index f6f93b9..b7d0ec5 100644
--- a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
+++ b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
@@ -50,16 +50,16 @@ krb5_aprof_get_int32
 krb5_aprof_get_string
 krb5_aprof_getvals
 krb5_aprof_init
-krb5_flags_to_string
+krb5_flagnum_to_string
+krb5_flagspec_to_mask
+krb5_flags_to_strings
 krb5_free_key_data_contents
-krb5_input_flag_to_string
 krb5_keysalt_is_present
 krb5_keysalt_iterate
 krb5_klog_close
 krb5_klog_init
 krb5_klog_reopen
 krb5_klog_syslog
-krb5_string_to_flags
 krb5_string_to_keysalts
 xdr_chpass3_arg
 xdr_chpass_arg
diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in
index 26c5237..3fd4b9e 100644
--- a/src/lib/kadm5/srv/Makefile.in
+++ b/src/lib/kadm5/srv/Makefile.in
@@ -9,7 +9,7 @@ DEFINES = @HESIOD_DEFS@
 ##DOSLIBNAME = libkadm5srv.lib
 
 LIBBASE=kadm5srv_mit
-LIBMAJOR=9
+LIBMAJOR=10
 LIBMINOR=0
 STOBJLISTS=../OBJS.ST OBJS.ST
 
diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports
index 8602e76..86af371 100644
--- a/src/lib/kadm5/srv/libkadm5srv_mit.exports
+++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports
@@ -65,16 +65,16 @@ krb5_aprof_get_string_all
 krb5_aprof_getvals
 krb5_aprof_init
 krb5_copy_key_data_contents
-krb5_flags_to_string
+krb5_flagnum_to_string
+krb5_flagspec_to_mask
+krb5_flags_to_strings
 krb5_free_key_data_contents
-krb5_input_flag_to_string
 krb5_keysalt_is_present
 krb5_keysalt_iterate
 krb5_klog_close
 krb5_klog_init
 krb5_klog_reopen
 krb5_klog_syslog
-krb5_string_to_flags
 krb5_string_to_keysalts
 master_db
 master_princ
diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
index 64f7385..b6c2bb2 100644
--- a/src/lib/kadm5/srv/server_acl.c
+++ b/src/lib/kadm5/srv/server_acl.c
@@ -265,7 +265,7 @@ kadm5int_acl_parse_line(lp)
  * kadm5int_acl_parse_restrictions() - Parse optional restrictions field
  *
  * Allowed restrictions are:
- *      [+-]flagname            (recognized by krb5_string_to_flags)
+ *      [+-]flagname            (recognized by krb5_flagspec_to_mask)
  *                              flag is forced to indicated value
  *      -clearpolicy            policy is forced clear
  *      -policy pol             policy is forced to be "pol"
@@ -283,7 +283,6 @@ kadm5int_acl_parse_restrictions(s, rpp)
     char                *sp = NULL, *tp, *ap, *save;
     static const char   *delims = "\t\n\f\v\r ,";
     krb5_deltat         dt;
-    krb5_flags          flag;
     krb5_error_code     code;
 
     DPRINT(DEBUG_CALLS, acl_debug_level,
@@ -297,18 +296,11 @@ kadm5int_acl_parse_restrictions(s, rpp)
             code = ENOMEM;
         } else {
             memset(*rpp, 0, sizeof(**rpp));
+            (*rpp)->forbid_attrs = ~(krb5_flags)0;
             for (tp = strtok_r(sp, delims, &save); tp;
                  tp = strtok_r(NULL, delims, &save)) {
-                flag = 0;
-                if (!krb5_string_to_flags(tp, "+", "-", &flag)) {
-                    /* OK, but was it in the positive or negative sense? */
-                    if (flag) {
-                        (*rpp)->require_attrs |= flag;
-                    } else {
-                        flag = ~0;
-                        (void) krb5_string_to_flags(tp, "+", "-", &flag);
-                        (*rpp)->forbid_attrs |= ~flag;
-                    }
+                if (!krb5_flagspec_to_mask(tp, &(*rpp)->require_attrs,
+                                           &(*rpp)->forbid_attrs)) {
                     (*rpp)->mask |= KADM5_ATTRIBUTES;
                 } else if (!strcmp(tp, "-clearpolicy")) {
                     (*rpp)->mask |= KADM5_POLICY_CLR;
@@ -396,7 +388,7 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
 
     if (rp->mask & KADM5_ATTRIBUTES) {
         recp->attributes |= rp->require_attrs;
-        recp->attributes &= ~(rp->forbid_attrs);
+        recp->attributes &= rp->forbid_attrs;
         *maskp |= KADM5_ATTRIBUTES;
     }
     if (rp->mask & KADM5_POLICY_CLR) {
diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
index 30c3951..fd9a1d1 100644
--- a/src/lib/kadm5/str_conv.c
+++ b/src/lib/kadm5/str_conv.c
@@ -1,219 +1,259 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /* lib/kadm5/str_conv.c */
 /*
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
+ * Copyright (C) 1995-2015 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.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
  *
- * 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.
- */
-
-/* Convert between strings and Kerberos internal data. */
-
-/*
- * Table of contents:
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
  *
- * String decoding:
- * ----------------
- * krb5_string_to_flags()       - Convert string to krb5_flags.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
  *
- * String encoding:
- * ----------------
- * krb5_flags_to_string()       - Convert krb5_flags to string.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/* Convert between strings and Kerberos internal data. */
+
 #include "k5-int.h"
 #include "admin_internal.h"
 #include "adm_proto.h"
 
-/*
- * Local data structures.
- */
-struct flags_lookup_entry {
-    krb5_flags          fl_flags;               /* Flag                 */
-    krb5_boolean        fl_sense;               /* Sense of the flag    */
-    const char *        fl_specifier;           /* How to recognize it  */
-    const char *        fl_output;              /* How to spit it out   */
-};
-
-/*
- * Local strings
- */
+#include <ctype.h>
 
 static const char default_tupleseps[]   = ", \t";
 static const char default_ksaltseps[]   = ":";
 
-/* Keytype strings */
-/* Flags strings */
-static const char flags_pdate_in[]      = "postdateable";
-static const char flags_fwd_in[]        = "forwardable";
-static const char flags_tgtbased_in[]   = "tgt-based";
-static const char flags_renew_in[]      = "renewable";
-static const char flags_proxy_in[]      = "proxiable";
-static const char flags_dup_skey_in[]   = "dup-skey";
-static const char flags_tickets_in[]    = "allow-tickets";
-static const char flags_preauth_in[]    = "preauth";
-static const char flags_hwauth_in[]     = "hwauth";
-static const char flags_ok_as_delegate_in[]     = "ok-as-delegate";
-static const char flags_pwchange_in[]   = "pwchange";
-static const char flags_service_in[]    = "service";
-static const char flags_pwsvc_in[]      = "pwservice";
-static const char flags_md5_in[]        = "md5";
-static const char flags_ok_to_auth_as_delegate_in[] = "ok-to-auth-as-delegate";
-static const char flags_no_auth_data_required_in[] = "no-auth-data-required";
-static const char flags_pdate_out[]     = N_("Not Postdateable");
-static const char flags_fwd_out[]       = N_("Not Forwardable");
-static const char flags_tgtbased_out[]  = N_("No TGT-based requests");
-static const char flags_renew_out[]     = N_("Not renewable");
-static const char flags_proxy_out[]     = N_("Not proxiable");
-static const char flags_dup_skey_out[]  = N_("No DUP_SKEY requests");
-static const char flags_tickets_out[]   = N_("All Tickets Disallowed");
-static const char flags_preauth_out[]   = N_("Preauthentication required");
-static const char flags_hwauth_out[]    = N_("HW authentication required");
-static const char flags_ok_as_delegate_out[]    = N_("OK as Delegate");
-static const char flags_pwchange_out[]  = N_("Password Change required");
-static const char flags_service_out[]   = N_("Service Disabled");
-static const char flags_pwsvc_out[]     = N_("Password Changing Service");
-static const char flags_md5_out[]       = N_("RSA-MD5 supported");
-static const char flags_ok_to_auth_as_delegate_out[] = N_("Protocol transition with delegation allowed");
-static const char flags_no_auth_data_required_out[] = N_("No authorization data required");
-static const char flags_default_neg[]   = "-";
-static const char flags_default_sep[]   = " ";
-
-/*
- * Lookup tables.
- */
+struct flag_table_row {
+    const char *spec;           /* Input specifier string */
+    krb5_flags flag;            /* Flag */
+    int invert;                 /* Whether to invert the sense */
+};
 
-static const struct flags_lookup_entry flags_table[] = {
-/* flag                         sense   input specifier    output string     */
-/*----------------------------- ------- ------------------ ------------------*/
-    { KRB5_KDB_DISALLOW_POSTDATED,  0,      flags_pdate_in,    flags_pdate_out   },
-    { KRB5_KDB_DISALLOW_FORWARDABLE,0,      flags_fwd_in,      flags_fwd_out     },
-    { KRB5_KDB_DISALLOW_TGT_BASED,  0,      flags_tgtbased_in, flags_tgtbased_out},
-    { KRB5_KDB_DISALLOW_RENEWABLE,  0,      flags_renew_in,    flags_renew_out   },
-    { KRB5_KDB_DISALLOW_PROXIABLE,  0,      flags_proxy_in,    flags_proxy_out   },
-    { KRB5_KDB_DISALLOW_DUP_SKEY,   0,      flags_dup_skey_in, flags_dup_skey_out},
-    { KRB5_KDB_DISALLOW_ALL_TIX,    0,      flags_tickets_in,  flags_tickets_out },
-    { KRB5_KDB_REQUIRES_PRE_AUTH,   1,      flags_preauth_in,  flags_preauth_out },
-    { KRB5_KDB_REQUIRES_HW_AUTH,    1,      flags_hwauth_in,   flags_hwauth_out  },
-    { KRB5_KDB_OK_AS_DELEGATE,      1,      flags_ok_as_delegate_in, flags_ok_as_delegate_out },
-    { KRB5_KDB_REQUIRES_PWCHANGE,   1,      flags_pwchange_in, flags_pwchange_out},
-    { KRB5_KDB_DISALLOW_SVR,        0,      flags_service_in,  flags_service_out },
-    { KRB5_KDB_PWCHANGE_SERVICE,    1,      flags_pwsvc_in,    flags_pwsvc_out   },
-    { KRB5_KDB_SUPPORT_DESMD5,      1,      flags_md5_in,      flags_md5_out     },
-    { KRB5_KDB_OK_TO_AUTH_AS_DELEGATE,  1,  flags_ok_to_auth_as_delegate_in, flags_ok_to_auth_as_delegate_out },
-    { KRB5_KDB_NO_AUTH_DATA_REQUIRED,   1,  flags_no_auth_data_required_in, flags_no_auth_data_required_out }
+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},
 };
-static const int flags_table_nents = sizeof(flags_table)/
-    sizeof(flags_table[0]);
+#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))
 
+static const char *outflags[] = {
+    "DISALLOW_POSTDATED",       /* 0x00000001 */
+    "DISALLOW_FORWARDABLE",     /* 0x00000002 */
+    "DISALLOW_TGT_BASED",       /* 0x00000004 */
+    "DISALLOW_RENEWABLE",       /* 0x00000008 */
+    "DISALLOW_PROXIABLE",       /* 0x00000010 */
+    "DISALLOW_DUP_SKEY",        /* 0x00000020 */
+    "DISALLOW_ALL_TIX",         /* 0x00000040 */
+    "REQUIRES_PRE_AUTH",        /* 0x00000080 */
+    "REQUIRES_HW_AUTH",         /* 0x00000100 */
+    "REQUIRES_PWCHANGE",        /* 0x00000200 */
+    NULL,                       /* 0x00000400 */
+    NULL,                       /* 0x00000800 */
+    "DISALLOW_SVR",             /* 0x00001000 */
+    "PWCHANGE_SERVICE",         /* 0x00002000 */
+    "SUPPORT_DESMD5",           /* 0x00004000 */
+    "NEW_PRINC",                /* 0x00008000 */
+    NULL,                       /* 0x00010000 */
+    NULL,                       /* 0x00020000 */
+    NULL,                       /* 0x00040000 */
+    NULL,                       /* 0x00080000 */
+    "OK_AS_DELEGATE",           /* 0x00100000 */
+    "OK_TO_AUTH_AS_DELEGATE",   /* 0x00200000 */
+    "NO_AUTH_DATA_REQUIRED",    /* 0x00400000 */
+};
+#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))
 
-krb5_error_code
-krb5_string_to_flags(string, positive, negative, flagsp)
-    char        * string;
-    const char  * positive;
-    const char  * negative;
-    krb5_flags  * flagsp;
+/*
+ * Given s, which is a normalized flagspec with the prefix stripped off, and
+ * req_neg indicating whether the flagspec is negated, update the toset and
+ * toclear masks.
+ */
+static krb5_error_code
+raw_flagspec_to_mask(const char *s, int req_neg, krb5_flags *toset,
+                     krb5_flags *toclear)
 {
-    int         i;
-    int         found;
-    const char  *neg;
-    size_t      nsize, psize;
-    int         cpos;
-    int         sense;
-
-    found = 0;
-    /* We need to have a way to negate it. */
-    neg = (negative) ? negative : flags_default_neg;
-    nsize = strlen(neg);
-    psize = (positive) ? strlen(positive) : 0;
+    int found = 0, invert = 0;
+    size_t i;
+    krb5_flags flag;
+    unsigned long ul;
 
-    cpos = 0;
-    sense = 1;
-    /* First check for positive or negative sense */
-    if (!strncasecmp(neg, string, nsize)) {
-        sense = 0;
-        cpos += (int) nsize;
+    for (i = 0; !found && i < NFTBL; i++) {
+        if (strcmp(s, ftbl[i].spec) != 0)
+            continue;
+        /* Found a match */
+        found = 1;
+        invert = ftbl[i].invert;
+        flag = ftbl[i].flag;
     }
-    else if (psize && !strncasecmp(positive, string, psize)) {
-        cpos += (int) psize;
+    /* Accept hexadecimal numbers. */
+    if (!found && strncmp(s, "0x", 2) == 0) {
+        /* Assume that krb5_flags are 32 bits long. */
+        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;
+}
+
+/*
+ * Update the toset and toclear flag masks according to flag specifier string
+ * spec, which is of the form {+|-}flagname.  toset and toclear can point to
+ * the same flag word.
+ */
+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;
 
-    for (i=0; i<flags_table_nents; i++) {
-        if (!strcasecmp(&string[cpos], flags_table[i].fl_specifier)) {
-            found = 1;
-            if (sense == (int) flags_table[i].fl_sense)
-                *flagsp |= flags_table[i].fl_flags;
-            else
-                *flagsp &= ~flags_table[i].fl_flags;
+    s = copy = strdup(spec);
+    if (s == NULL)
+        return ENOMEM;
 
-            break;
-        }
+    if (*s == '-') {
+        req_neg = 1;
+        s++;
+    } else if (*s == '+')
+        s++;
+
+    for (cp = s; *cp != '\0'; cp++) {
+        /* Transform hyphens to underscores.*/
+        if (*cp == '-')
+            *cp = '_';
+        /* Downcase. */
+        if (isupper((unsigned char)*cp))
+            *cp = tolower((unsigned char)*cp);
     }
-    return((found) ? 0 : EINVAL);
+    retval = raw_flagspec_to_mask(s, req_neg, toset, toclear);
+    free(copy);
+    return retval;
 }
 
+/*
+ * Copy the flag name of flagnum to outstr.
+ */
 krb5_error_code
-krb5_flags_to_string(flags, sep, buffer, buflen)
-    krb5_flags  flags;
-    const char  * sep;
-    char        * buffer;
-    size_t      buflen;
+krb5_flagnum_to_string(int flagnum, char **outstr)
 {
-    int                 i;
-    krb5_flags          pflags;
-    const char          *sepstring;
-    struct k5buf        buf;
+    const char *s = NULL;
 
-    pflags = 0;
-    sepstring = (sep) ? sep : flags_default_sep;
-    k5_buf_init_fixed(&buf, buffer, buflen);
-    /* Blast through the table matching all we can */
-    for (i=0; i<flags_table_nents; i++) {
-        if (flags & flags_table[i].fl_flags) {
-            if (buf.len > 0)
-                k5_buf_add(&buf, sepstring);
-            k5_buf_add(&buf, _(flags_table[i].fl_output));
-            /* Keep track of what we matched */
-            pflags |= flags_table[i].fl_flags;
-        }
+    *outstr = NULL;
+    if ((unsigned int)flagnum < NOUTFLAGS) {
+        s = outflags[flagnum];
     }
-    if (k5_buf_status(&buf) != 0)
-        return(ENOMEM);
-
-    /* See if there's any leftovers */
-    if (flags & ~pflags)
-        return(EINVAL);
-
-    return(0);
+    if (s == NULL)
+        /* Assume that krb5_flags are 32 bits long. */
+        asprintf(outstr, "0x%08lx", 1UL<<flagnum);
+    else
+        *outstr = strdup(s);
+    if (*outstr == NULL)
+        return ENOMEM;
+    return 0;
 }
 
+/*
+ * Create a null-terminated array of string representations of flags.  Store a
+ * null pointer into outarray if there would be no strings.
+ */
 krb5_error_code
-krb5_input_flag_to_string(flag, buffer, buflen)
-    int         flag;
-    char        * buffer;
-    size_t      buflen;
+krb5_flags_to_strings(krb5_int32 flags, char ***outarray)
 {
-    if(flag < 0 || flag >= flags_table_nents) return ENOENT; /* End of list */
-    if(strlcpy(buffer, flags_table[flag].fl_specifier, buflen) >= buflen)
-        return ENOMEM;
-    return  0;
+    char **a = NULL, **a_new = NULL, **ap;
+    size_t amax = 0, i;
+    krb5_error_code retval;
+
+    *outarray = NULL;
+
+    /* Assume that krb5_flags are 32 bits long. */
+    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++]);
+        if (retval)
+            goto cleanup;
+        a[amax] = NULL;
+    }
+    *outarray = a;
+    return 0;
+cleanup:
+    for (ap = a; ap != NULL && *ap != NULL; ap++) {
+        free(ap);
+    }
+    free(a);
+    return retval;
 }
 
 /*
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
index acb1d76..5c61c23 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -324,8 +324,10 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
     check(krb5_parse_name(context, ename, &ent->princ));
 
     flagstr = get_string(h, "princs", ename, "flags");
-    if (flagstr != NULL)
-        check(krb5_string_to_flags(flagstr, "+", "-", &ent->attributes));
+    if (flagstr != NULL) {
+        check(krb5_flagspec_to_mask(flagstr, &ent->attributes,
+                                    &ent->attributes));
+    }
     free(flagstr);
 
     ent->max_life = get_duration(h, "princs", ename, "maxlife");


More information about the cvs-krb5 mailing list