summaryrefslogtreecommitdiffstats
path: root/src/kadmin/testing/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/testing/util')
-rw-r--r--src/kadmin/testing/util/ChangeLog3
-rw-r--r--src/kadmin/testing/util/Makefile.ov34
-rw-r--r--src/kadmin/testing/util/bsddb_dump.c64
-rw-r--r--src/kadmin/testing/util/tcl_kadm5.c2312
-rw-r--r--src/kadmin/testing/util/tcl_krb5_hash.c163
-rw-r--r--src/kadmin/testing/util/tcl_ovsec_kadm.c2016
-rw-r--r--src/kadmin/testing/util/tcl_ovsec_kadm_syntax57
-rw-r--r--src/kadmin/testing/util/test.c32
8 files changed, 4681 insertions, 0 deletions
diff --git a/src/kadmin/testing/util/ChangeLog b/src/kadmin/testing/util/ChangeLog
new file mode 100644
index 000000000..36df4616d
--- /dev/null
+++ b/src/kadmin/testing/util/ChangeLog
@@ -0,0 +1,3 @@
+Fri Jul 12 15:04:52 1996 Marc Horowitz <marc@mit.edu>
+
+ * tcl_ovsec_kadm.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
diff --git a/src/kadmin/testing/util/Makefile.ov b/src/kadmin/testing/util/Makefile.ov
new file mode 100644
index 000000000..6d0159092
--- /dev/null
+++ b/src/kadmin/testing/util/Makefile.ov
@@ -0,0 +1,34 @@
+# $Id$
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+CFLAGS += -I$(TCLINC)
+
+SRCS = tcl_ovsec_kadm.c tcl_kadm5.c test.c
+OBJS = tcl_ovsec_kadm.o tcl_kadm5.o test.o
+
+PROG = ovsec_kadm_srv_tcl
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBDYN) $(LIBGSSAPI_KRB5) \
+ $(LIBKDB5) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) $(LIBCOM_ERR) \
+ $(NDBMLIB) $(NETLIB)
+
+expand Program
+expand Depend
+
+PROG = ovsec_kadm_clnt_tcl
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBDYN) $(LIBGSSAPI_KRB5) \
+ $(LIBKDB5) $(LIBKRB5) $(LIBCRYPTO) \
+ $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) $(LIBCOM_ERR) \
+ $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+expand Program
+
+PROG = bsddb_dump
+SRCS = bsddb_dump.c
+OBJS = bsddb_dump.o
+LIBS = $(LIBDB)
+
+expand Program
+expand Depend
diff --git a/src/kadmin/testing/util/bsddb_dump.c b/src/kadmin/testing/util/bsddb_dump.c
new file mode 100644
index 000000000..ba69b8461
--- /dev/null
+++ b/src/kadmin/testing/util/bsddb_dump.c
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ */
+
+#include <sys/file.h>
+#include <fcntl.h>
+#include <db.h>
+#include <stdio.h>
+
+main(int argc, char *argv[])
+{
+ char *file;
+ DB *db;
+ DBT dbkey, dbdata;
+ int code, i;
+
+ HASHINFO info;
+
+ info.hash = NULL;
+ info.bsize = 256;
+ info.ffactor = 8;
+ info.nelem = 25000;
+ info.lorder = 0;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: argv[0] dbfile\n");
+ exit(2);
+ }
+
+ file = argv[1];
+
+ if((db = dbopen(file, O_RDWR, 0666, DB_HASH, &info)) == NULL) {
+ perror("Opening db file");
+ exit(1);
+ }
+
+ if ((code = (*db->seq)(db, &dbkey, &dbdata, R_FIRST)) == -1) {
+ perror("starting db iteration");
+ exit(1);
+ }
+
+ while (code == 0) {
+ for (i=0; i<dbkey.size; i++)
+ printf("%02x", (int) ((unsigned char *) dbkey.data)[i]);
+ printf("\t");
+ for (i=0; i<dbdata.size; i++)
+ printf("%02x", (int) ((unsigned char *) dbdata.data)[i]);
+ printf("\n");
+
+ code = (*db->seq)(db, &dbkey, &dbdata, R_NEXT);
+ }
+
+ if (code == -1) {
+ perror("during db iteration");
+ exit(1);
+ }
+
+ if ((*db->close)(db) == -1) {
+ perror("closing db");
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
new file mode 100644
index 000000000..b102cdfc2
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_kadm5.c
@@ -0,0 +1,2312 @@
+#include <stdio.h>
+#include <string.h>
+#include <tcl.h>
+#define USE_KADM5_API_VERSION 2
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <malloc.h>
+#include <k5-int.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct flagval {
+ char *name;
+ krb5_flags val;
+};
+
+/* XXX This should probably be in the hash table like server_handle */
+static krb5_context context;
+
+static struct flagval krb5_flags_array[] = {
+ {"KRB5_KDB_DISALLOW_POSTDATED", KRB5_KDB_DISALLOW_POSTDATED},
+ {"KRB5_KDB_DISALLOW_FORWARDABLE", KRB5_KDB_DISALLOW_FORWARDABLE},
+ {"KRB5_KDB_DISALLOW_TGT_BASED", KRB5_KDB_DISALLOW_TGT_BASED},
+ {"KRB5_KDB_DISALLOW_RENEWABLE", KRB5_KDB_DISALLOW_RENEWABLE},
+ {"KRB5_KDB_DISALLOW_PROXIABLE", KRB5_KDB_DISALLOW_PROXIABLE},
+ {"KRB5_KDB_DISALLOW_DUP_SKEY", KRB5_KDB_DISALLOW_DUP_SKEY},
+ {"KRB5_KDB_DISALLOW_ALL_TIX", KRB5_KDB_DISALLOW_ALL_TIX},
+ {"KRB5_KDB_REQUIRES_PRE_AUTH", KRB5_KDB_REQUIRES_PRE_AUTH},
+ {"KRB5_KDB_REQUIRES_HW_AUTH", KRB5_KDB_REQUIRES_HW_AUTH},
+ {"KRB5_KDB_REQUIRES_PWCHANGE", KRB5_KDB_REQUIRES_PWCHANGE},
+ {"KRB5_KDB_DISALLOW_SVR", KRB5_KDB_DISALLOW_SVR},
+ {"KRB5_KDB_PWCHANGE_SERVICE", KRB5_KDB_PWCHANGE_SERVICE}
+};
+
+static struct flagval aux_attributes[] = {
+ {"KADM5_POLICY", KADM5_POLICY}
+};
+
+static struct flagval principal_mask_flags[] = {
+ {"KADM5_PRINCIPAL", KADM5_PRINCIPAL},
+ {"KADM5_PRINC_EXPIRE_TIME", KADM5_PRINC_EXPIRE_TIME},
+ {"KADM5_PW_EXPIRATION", KADM5_PW_EXPIRATION},
+ {"KADM5_LAST_PWD_CHANGE", KADM5_LAST_PWD_CHANGE},
+ {"KADM5_ATTRIBUTES", KADM5_ATTRIBUTES},
+ {"KADM5_MAX_LIFE", KADM5_MAX_LIFE},
+ {"KADM5_MOD_TIME", KADM5_MOD_TIME},
+ {"KADM5_MOD_NAME", KADM5_MOD_NAME},
+ {"KADM5_KVNO", KADM5_KVNO},
+ {"KADM5_MKVNO", KADM5_MKVNO},
+ {"KADM5_AUX_ATTRIBUTES", KADM5_AUX_ATTRIBUTES},
+ {"KADM5_POLICY", KADM5_POLICY},
+ {"KADM5_POLICY_CLR", KADM5_POLICY_CLR},
+ {"KADM5_MAX_RLIFE", KADM5_MAX_RLIFE},
+ {"KADM5_LAST_SUCCESS", KADM5_LAST_SUCCESS},
+ {"KADM5_LAST_FAILED", KADM5_LAST_FAILED},
+ {"KADM5_FAIL_AUTH_COUNT", KADM5_FAIL_AUTH_COUNT},
+ {"KADM5_KEY_DATA", KADM5_KEY_DATA},
+ {"KADM5_TL_DATA", KADM5_TL_DATA},
+ {"KADM5_PRINCIPAL_NORMAL_MASK", KADM5_PRINCIPAL_NORMAL_MASK}
+};
+
+static struct flagval policy_mask_flags[] = {
+ {"KADM5_POLICY", KADM5_POLICY},
+ {"KADM5_PW_MAX_LIFE", KADM5_PW_MAX_LIFE},
+ {"KADM5_PW_MIN_LIFE", KADM5_PW_MIN_LIFE},
+ {"KADM5_PW_MIN_LENGTH", KADM5_PW_MIN_LENGTH},
+ {"KADM5_PW_MIN_CLASSES", KADM5_PW_MIN_CLASSES},
+ {"KADM5_PW_HISTORY_NUM", KADM5_PW_HISTORY_NUM},
+ {"KADM5_REF_COUNT", KADM5_REF_COUNT}
+};
+
+static struct flagval config_mask_flags[] = {
+ {"KADM5_CONFIG_REALM", KADM5_CONFIG_REALM},
+ {"KADM5_CONFIG_DBNAME", KADM5_CONFIG_DBNAME},
+ {"KADM5_CONFIG_MKEY_NAME", KADM5_CONFIG_MKEY_NAME},
+ {"KADM5_CONFIG_MAX_LIFE", KADM5_CONFIG_MAX_LIFE},
+ {"KADM5_CONFIG_MAX_RLIFE", KADM5_CONFIG_MAX_RLIFE},
+ {"KADM5_CONFIG_EXPIRATION", KADM5_CONFIG_EXPIRATION},
+ {"KADM5_CONFIG_FLAGS", KADM5_CONFIG_FLAGS},
+ {"KADM5_CONFIG_ADMIN_KEYTAB", KADM5_CONFIG_ADMIN_KEYTAB},
+ {"KADM5_CONFIG_STASH_FILE", KADM5_CONFIG_STASH_FILE},
+ {"KADM5_CONFIG_ENCTYPE", KADM5_CONFIG_ENCTYPE},
+ {"KADM5_CONFIG_ADBNAME", KADM5_CONFIG_ADBNAME},
+ {"KADM5_CONFIG_ADB_LOCKFILE", KADM5_CONFIG_ADB_LOCKFILE},
+ {"KADM5_CONFIG_PROFILE", KADM5_CONFIG_PROFILE},
+ {"KADM5_CONFIG_ACL_FILE", KADM5_CONFIG_ACL_FILE},
+ {"KADM5_CONFIG_KADMIND_PORT", KADM5_CONFIG_KADMIND_PORT},
+ {"KADM5_CONFIG_ENCTYPES", KADM5_CONFIG_ENCTYPES},
+ {"KADM5_CONFIG_ADMIN_SERVER", KADM5_CONFIG_ADMIN_SERVER},
+ {"KADM5_CONFIG_DICT_FILE", KADM5_CONFIG_DICT_FILE},
+ {"KADM5_CONFIG_MKEY_FROM_KBD", KADM5_CONFIG_MKEY_FROM_KBD},
+};
+
+static struct flagval priv_flags[] = {
+ {"KADM5_PRIV_GET", KADM5_PRIV_GET},
+ {"KADM5_PRIV_ADD", KADM5_PRIV_ADD},
+ {"KADM5_PRIV_MODIFY", KADM5_PRIV_MODIFY},
+ {"KADM5_PRIV_DELETE", KADM5_PRIV_DELETE}
+};
+
+
+static char *arg_error = "wrong # args";
+
+static Tcl_HashTable *struct_table = 0;
+
+static int put_server_handle(Tcl_Interp *interp, void *handle, char **name)
+{
+ int i = 1, newPtr = 0;
+ static char buf[20];
+ Tcl_HashEntry *entry;
+
+ if (! struct_table) {
+ if (! (struct_table =
+ malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ do {
+ /*
+ * Handles from ovsec_kadm_init() and kadm5_init() should not
+ * be mixed during unit tests, but the API would happily
+ * accept them. Making the hash entry names different in
+ * tcl_kadm.c and tcl_ovsec_kadm.c ensures that GET_HANDLE
+ * will fail if presented a handle from the other API.
+ */
+ sprintf(buf, "kadm5_handle%d", i);
+ entry = Tcl_CreateHashEntry(struct_table, buf, &newPtr);
+ i++;
+ } while (! newPtr);
+
+ Tcl_SetHashValue(entry, handle);
+
+ *name = buf;
+
+ return TCL_OK;
+}
+
+static int get_server_handle(Tcl_Interp *interp, char *name, void **handle)
+{
+ Tcl_HashEntry *entry;
+
+ if(!strcasecmp(name, "null"))
+ *handle = 0;
+ else {
+ if (! (struct_table &&
+ (entry = Tcl_FindHashEntry(struct_table, name)))) {
+ if (strncmp(name, "ovsec_kadm_handle", 17) == 0)
+ Tcl_AppendResult(interp, "ovsec_kadm handle "
+ "specified for kadm5 api: ", name, 0);
+ else
+ Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+ return TCL_ERROR;
+ }
+ *handle = (void *) Tcl_GetHashValue(entry);
+ }
+ return TCL_OK;
+}
+
+static int remove_server_handle(Tcl_Interp *interp, char *name)
+{
+ Tcl_HashEntry *entry;
+
+ if (! (struct_table &&
+ (entry = Tcl_FindHashEntry(struct_table, name)))) {
+ Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+ return TCL_ERROR;
+ }
+
+ Tcl_SetHashValue(entry, NULL);
+ return TCL_OK;
+}
+
+#define GET_HANDLE(num_args, ignored) \
+ void *server_handle; \
+ char *whoami = argv[0]; \
+ argv++, argc--; \
+ if (argc != num_args + 1) { \
+ Tcl_AppendResult(interp, whoami, ": ", arg_error, 0); \
+ return TCL_ERROR; \
+ } \
+ { \
+ int tcl_ret; \
+ if ((tcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+ != TCL_OK) { \
+ return tcl_ret; \
+ } \
+ } \
+ argv++, argc--;
+
+static Tcl_HashTable *create_flag_table(struct flagval *flags, int size)
+{
+ Tcl_HashTable *table;
+ Tcl_HashEntry *entry;
+ int i;
+
+ if (! (table = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_InitHashTable(table, TCL_STRING_KEYS);
+
+ for (i = 0; i < size; i++) {
+ int newPtr;
+
+ if (! (entry = Tcl_CreateHashEntry(table, flags[i].name, &newPtr))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_SetHashValue(entry, &flags[i].val);
+ }
+
+ return table;
+}
+
+
+static Tcl_DString *unparse_str(char *in_str)
+{
+ Tcl_DString *str;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ if (! in_str) {
+ Tcl_DStringAppend(str, "null", -1);
+ }
+ else {
+ Tcl_DStringAppend(str, in_str, -1);
+ }
+
+ return str;
+}
+
+
+
+static int parse_str(Tcl_Interp *interp, char *in_str, char **out_str)
+{
+ if (! in_str) {
+ *out_str = 0;
+ }
+ else if (! strcasecmp(in_str, "null")) {
+ *out_str = 0;
+ }
+ else {
+ *out_str = in_str;
+ }
+ return TCL_OK;
+}
+
+
+static void set_ok(Tcl_Interp *interp, char *string)
+{
+ Tcl_SetResult(interp, "OK", TCL_STATIC);
+ Tcl_AppendElement(interp, "KADM5_OK");
+ Tcl_AppendElement(interp, string);
+}
+
+
+
+static Tcl_DString *unparse_err(kadm5_ret_t code)
+{
+ char *code_string, *error_string;
+ Tcl_DString *dstring;
+
+ switch (code) {
+ case KADM5_FAILURE: code_string = "KADM5_FAILURE"; break;
+ case KADM5_AUTH_GET: code_string = "KADM5_AUTH_GET"; break;
+ case KADM5_AUTH_ADD: code_string = "KADM5_AUTH_ADD"; break;
+ case KADM5_AUTH_MODIFY:
+ code_string = "KADM5_AUTH_MODIFY"; break;
+ case KADM5_AUTH_DELETE:
+ code_string = "KADM5_AUTH_DELETE"; break;
+ case KADM5_AUTH_INSUFFICIENT:
+ code_string = "KADM5_AUTH_INSUFFICIENT"; break;
+ case KADM5_BAD_DB: code_string = "KADM5_BAD_DB"; break;
+ case KADM5_DUP: code_string = "KADM5_DUP"; break;
+ case KADM5_RPC_ERROR: code_string = "KADM5_RPC_ERROR"; break;
+ case KADM5_NO_SRV: code_string = "KADM5_NO_SRV"; break;
+ case KADM5_BAD_HIST_KEY:
+ code_string = "KADM5_BAD_HIST_KEY"; break;
+ case KADM5_NOT_INIT: code_string = "KADM5_NOT_INIT"; break;
+ case KADM5_INIT: code_string = "KADM5_INIT"; break;
+ case KADM5_BAD_PASSWORD:
+ code_string = "KADM5_BAD_PASSWORD"; break;
+ case KADM5_UNK_PRINC: code_string = "KADM5_UNK_PRINC"; break;
+ case KADM5_UNK_POLICY: code_string = "KADM5_UNK_POLICY"; break;
+ case KADM5_BAD_MASK: code_string = "KADM5_BAD_MASK"; break;
+ case KADM5_BAD_CLASS: code_string = "KADM5_BAD_CLASS"; break;
+ case KADM5_BAD_LENGTH: code_string = "KADM5_BAD_LENGTH"; break;
+ case KADM5_BAD_POLICY: code_string = "KADM5_BAD_POLICY"; break;
+ case KADM5_BAD_HISTORY: code_string = "KADM5_BAD_HISTORY"; break;
+ case KADM5_BAD_PRINCIPAL:
+ code_string = "KADM5_BAD_PRINCIPAL"; break;
+ case KADM5_BAD_AUX_ATTR:
+ code_string = "KADM5_BAD_AUX_ATTR"; break;
+ case KADM5_PASS_Q_TOOSHORT:
+ code_string = "KADM5_PASS_Q_TOOSHORT"; break;
+ case KADM5_PASS_Q_CLASS:
+ code_string = "KADM5_PASS_Q_CLASS"; break;
+ case KADM5_PASS_Q_DICT:
+ code_string = "KADM5_PASS_Q_DICT"; break;
+ case KADM5_PASS_REUSE: code_string = "KADM5_PASS_REUSE"; break;
+ case KADM5_PASS_TOOSOON:
+ code_string = "KADM5_PASS_TOOSOON"; break;
+ case KADM5_POLICY_REF:
+ code_string = "KADM5_POLICY_REF"; break;
+ case KADM5_PROTECT_PRINCIPAL:
+ code_string = "KADM5_PROTECT_PRINCIPAL"; break;
+ case KADM5_BAD_SERVER_HANDLE:
+ code_string = "KADM5_BAD_SERVER_HANDLE"; break;
+ case KADM5_BAD_STRUCT_VERSION:
+ code_string = "KADM5_BAD_STRUCT_VERSION"; break;
+ case KADM5_OLD_STRUCT_VERSION:
+ code_string = "KADM5_OLD_STRUCT_VERSION"; break;
+ case KADM5_NEW_STRUCT_VERSION:
+ code_string = "KADM5_NEW_STRUCT_VERSION"; break;
+ case KADM5_BAD_API_VERSION:
+ code_string = "KADM5_BAD_API_VERSION"; break;
+ case KADM5_OLD_LIB_API_VERSION:
+ code_string = "KADM5_OLD_LIB_API_VERSION"; break;
+ case KADM5_OLD_SERVER_API_VERSION:
+ code_string = "KADM5_OLD_SERVER_API_VERSION"; break;
+ case KADM5_NEW_LIB_API_VERSION:
+ code_string = "KADM5_NEW_LIB_API_VERSION"; break;
+ case KADM5_NEW_SERVER_API_VERSION:
+ code_string = "KADM5_NEW_SERVER_API_VERSION"; break;
+ case KADM5_SECURE_PRINC_MISSING:
+ code_string = "KADM5_SECURE_PRINC_MISSING"; break;
+ case KADM5_NO_RENAME_SALT:
+ code_string = "KADM5_NO_RENAME_SALT"; break;
+ case KADM5_BAD_CLIENT_PARAMS:
+ code_string = "KADM5_BAD_CLIENT_PARAMS"; break;
+ case KADM5_BAD_SERVER_PARAMS:
+ code_string = "KADM5_BAD_SERVER_PARAMS"; break;
+ case KADM5_AUTH_LIST:
+ code_string = "KADM5_AUTH_LIST"; break;
+ case KADM5_AUTH_CHANGEPW:
+ code_string = "KADM5_AUTH_CHANGEPW"; break;
+ case KADM5_GSS_ERROR: code_string = "KADM5_GSS_ERROR"; break;
+ case OSA_ADB_DUP: code_string = "OSA_ADB_DUP"; break;
+ case OSA_ADB_NOENT: code_string = "ENOENT"; break;
+ case OSA_ADB_DBINIT: code_string = "OSA_ADB_DBINIT"; break;
+ case OSA_ADB_BAD_POLICY: code_string = "Bad policy name"; break;
+ case OSA_ADB_BAD_PRINC: code_string = "Bad principal name"; break;
+ case OSA_ADB_BAD_DB: code_string = "Invalid database."; break;
+ case OSA_ADB_XDR_FAILURE: code_string = "OSA_ADB_XDR_FAILURE"; break;
+ case OSA_ADB_BADLOCKMODE: code_string = "OSA_ADB_BADLOCKMODE"; break;
+ case OSA_ADB_CANTLOCK_DB: code_string = "OSA_ADB_CANTLOCK_DB"; break;
+ case OSA_ADB_NOTLOCKED: code_string = "OSA_ADB_NOTLOCKED"; break;
+ case OSA_ADB_NOLOCKFILE: code_string = "OSA_ADB_NOLOCKFILE"; break;
+ case OSA_ADB_NOEXCL_PERM: code_string = "OSA_ADB_NOEXCL_PERM"; break;
+ case KRB5_KDB_INUSE: code_string = "KRB5_KDB_INUSE"; break;
+ case KRB5_KDB_UK_SERROR: code_string = "KRB5_KDB_UK_SERROR"; break;
+ case KRB5_KDB_UK_RERROR: code_string = "KRB5_KDB_UK_RERROR"; break;
+ case KRB5_KDB_UNAUTH: code_string = "KRB5_KDB_UNAUTH"; break;
+ case KRB5_KDB_NOENTRY: code_string = "KRB5_KDB_NOENTRY"; break;
+ case KRB5_KDB_ILL_WILDCARD: code_string = "KRB5_KDB_ILL_WILDCARD"; break;
+ case KRB5_KDB_DB_INUSE: code_string = "KRB5_KDB_DB_INUSE"; break;
+ case KRB5_KDB_DB_CHANGED: code_string = "KRB5_KDB_DB_CHANGED"; break;
+ case KRB5_KDB_TRUNCATED_RECORD:
+ code_string = "KRB5_KDB_TRUNCATED_RECORD"; break;
+ case KRB5_KDB_RECURSIVELOCK:
+ code_string = "KRB5_KDB_RECURSIVELOCK"; break;
+ case KRB5_KDB_NOTLOCKED: code_string = "KRB5_KDB_NOTLOCKED"; break;
+ case KRB5_KDB_BADLOCKMODE: code_string = "KRB5_KDB_BADLOCKMODE"; break;
+ case KRB5_KDB_DBNOTINITED: code_string = "KRB5_KDB_DBNOTINITED"; break;
+ case KRB5_KDB_DBINITED: code_string = "KRB5_KDB_DBINITED"; break;
+ case KRB5_KDB_ILLDIRECTION: code_string = "KRB5_KDB_ILLDIRECTION"; break;
+ case KRB5_KDB_NOMASTERKEY: code_string = "KRB5_KDB_NOMASTERKEY"; break;
+ case KRB5_KDB_BADMASTERKEY: code_string = "KRB5_KDB_BADMASTERKEY"; break;
+ case KRB5_KDB_INVALIDKEYSIZE:
+ code_string = "KRB5_KDB_INVALIDKEYSIZE"; break;
+ case KRB5_KDB_CANTREAD_STORED:
+ code_string = "KRB5_KDB_CANTREAD_STORED"; break;
+ case KRB5_KDB_BADSTORED_MKEY:
+ code_string = "KRB5_KDB_BADSTORED_MKEY"; break;
+ case KRB5_KDB_CANTLOCK_DB: code_string = "KRB5_KDB_CANTLOCK_DB"; break;
+ case KRB5_KDB_DB_CORRUPT: code_string = "KRB5_KDB_DB_CORRUPT"; break;
+ case KRB5_PARSE_ILLCHAR: code_string = "KRB5_PARSE_ILLCHAR"; break;
+ case KRB5_PARSE_MALFORMED: code_string = "KRB5_PARSE_MALFORMED"; break;
+ case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN"; break;
+ case KRB5_REALM_UNKNOWN: code_string = "KRB5_REALM_UNKNOWN"; break;
+ case KRB5_KDC_UNREACH: code_string = "KRB5_KDC_UNREACH"; break;
+ case KRB5_KDCREP_MODIFIED: code_string = "KRB5_KDCREP_MODIFIED"; break;
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY: code_string = "KRB5KRB_AP_ERR_BAD_INTEGRITY"; break;
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN"; break;
+ case KRB5_CONFIG_BADFORMAT: code_string = "KRB5_CONFIG_BADFORMAT"; break;
+ case EINVAL: code_string = "EINVAL"; break;
+ case ENOENT: code_string = "ENOENT"; break;
+ default: fprintf(stderr, "**** CODE %d ***\n", code); code_string = "UNKNOWN"; break;
+ }
+
+ error_string = (char *) error_message(code);
+
+ if (! (dstring = (Tcl_DString *) malloc(sizeof(Tcl_DString)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX Do we really want to exit? Ok if this is */
+ /* just a test program, but what about if it gets */
+ /* used for other things later? */
+ }
+
+ Tcl_DStringInit(dstring);
+
+ if (! (Tcl_DStringAppendElement(dstring, "ERROR") &&
+ Tcl_DStringAppendElement(dstring, code_string) &&
+ Tcl_DStringAppendElement(dstring, error_string))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ return dstring;
+}
+
+
+
+static void stash_error(Tcl_Interp *interp, krb5_error_code code)
+{
+ Tcl_DString *dstring = unparse_err(code);
+ Tcl_DStringResult(interp, dstring);
+ Tcl_DStringFree(dstring);
+ free(dstring);
+}
+
+static Tcl_DString *unparse_key_data(krb5_key_data *key_data, int n_key_data)
+{
+ Tcl_DString *str;
+ char buf[2048];
+ int i, j;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+ for (i = 0; i < n_key_data; i++) {
+ krb5_key_data *key = &key_data[i];
+
+ Tcl_DStringStartSublist(str);
+ sprintf(buf, "%d", key->key_data_type[0]);
+ Tcl_DStringAppendElement(str, buf);
+ sprintf(buf, "%d", key->key_data_ver > 1 ?
+ key->key_data_type[1] : -1);
+ Tcl_DStringAppendElement(str, buf);
+ if (key->key_data_contents[0]) {
+ sprintf(buf, "0x");
+ for (j = 0; j < key->key_data_length[0]; j++) {
+ sprintf(buf + 2*(j+1), "%02x",
+ key->key_data_contents[0][j]);
+ }
+ } else *buf = '\0';
+ Tcl_DStringAppendElement(str, buf);
+ Tcl_DStringEndSublist(str);
+ }
+
+ return str;
+}
+
+static Tcl_DString *unparse_tl_data(krb5_tl_data *tl_data, int n_tl_data)
+{
+ Tcl_DString *str;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+ if (n_tl_data > 0 && tl_data->tl_data_contents)
+ Tcl_DStringAppendElement(str, "[cannot unparse tl data yet]");
+ else
+ Tcl_DStringAppendElement(str, "");
+
+ return str;
+}
+
+static Tcl_DString *unparse_flags(struct flagval *array, int size,
+ krb5_int32 flags)
+{
+ int i;
+ Tcl_DString *str;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ for (i = 0; i < size; i++) {
+ if (flags & array[i].val) {
+ Tcl_DStringAppendElement(str, array[i].name);
+ }
+ }
+
+ return str;
+}
+
+
+static int parse_flags(Tcl_Interp *interp, Tcl_HashTable *table,
+ struct flagval *array, int size, char *str,
+ krb5_flags *flags)
+{
+ int tcl_ret, tmp, argc, i, retcode = TCL_OK;
+ char **argv;
+ Tcl_HashEntry *entry;
+
+ if ((tcl_ret = Tcl_GetInt(interp, str, &tmp)) == TCL_OK) {
+ *flags = tmp;
+ return TCL_OK;
+ }
+ Tcl_ResetResult(interp);
+
+ if ((tcl_ret = Tcl_SplitList(interp, str, &argc, &argv)) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (! table) {
+ table = create_flag_table(array, size);
+ }
+
+ *flags = 0;
+
+ for (i = 0; i < argc; i++) {
+ if (! (entry = Tcl_FindHashEntry(table, argv[i]))) {
+ Tcl_AppendResult(interp, "unknown krb5 flag ", argv[i], 0);
+ retcode = TCL_ERROR;
+ break;
+ }
+ *flags |= *(krb5_flags *) Tcl_GetHashValue(entry);
+ }
+
+ free(argv);
+ return(retcode);
+}
+
+static Tcl_DString *unparse_privs(krb5_flags flags)
+{
+ return unparse_flags(priv_flags, sizeof(priv_flags) /
+ sizeof(struct flagval), flags);
+}
+
+
+static Tcl_DString *unparse_krb5_flags(krb5_flags flags)
+{
+ return unparse_flags(krb5_flags_array, sizeof(krb5_flags_array) /
+ sizeof(struct flagval), flags);
+}
+
+static int parse_krb5_flags(Tcl_Interp *interp, char *str, krb5_flags *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, krb5_flags_array,
+ sizeof(krb5_flags_array) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+static Tcl_DString *unparse_aux_attributes(krb5_int32 flags)
+{
+ return unparse_flags(aux_attributes, sizeof(aux_attributes) /
+ sizeof(struct flagval), flags);
+}
+
+
+static int parse_aux_attributes(Tcl_Interp *interp, char *str, long *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, aux_attributes,
+ sizeof(aux_attributes) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+static int parse_principal_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, principal_mask_flags,
+ sizeof(principal_mask_flags) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+static int parse_policy_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, policy_mask_flags,
+ sizeof(policy_mask_flags) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+
+static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ)
+{
+ Tcl_DString *str, *tmp_dstring;
+ char *tmp;
+ char buf[20];
+ krb5_error_code krb5_ret;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ tmp = 0; /* It looks to me from looking at the library source */
+ /* code for krb5_parse_name that the pointer passed into */
+ /* it should be initialized to 0 if I want it do be */
+ /* allocated automatically. */
+ if (krb5_ret = krb5_unparse_name(context, princ->principal, &tmp)) {
+ /* XXX Do we want to return an error? Not sure. */
+ Tcl_DStringAppendElement(str, "[unparseable principal]");
+ }
+ else {
+ Tcl_DStringAppendElement(str, tmp);
+ free(tmp);
+ }
+
+ sprintf(buf, "%d", princ->princ_expire_time);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->last_pwd_change);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->pw_expiration);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ tmp = 0;
+ if (krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp)) {
+ /* XXX */
+ Tcl_DStringAppendElement(str, "[unparseable principal]");
+ }
+ else {
+ Tcl_DStringAppendElement(str, tmp);
+ free(tmp);
+ }
+
+ sprintf(buf, "%d", princ->mod_date);
+ Tcl_DStringAppendElement(str, buf);
+
+ tmp_dstring = unparse_krb5_flags(princ->attributes);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ sprintf(buf, "%d", princ->kvno);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->mkvno);
+ Tcl_DStringAppendElement(str, buf);
+
+ /* XXX This may be dangerous, because the contents of the policy */
+ /* field are undefined if the POLICY bit isn't set. However, I */
+ /* think it's a bug for the field not to be null in that case */
+ /* anyway, so we should assume that it will be null so that we'll */
+ /* catch it if it isn't. */
+
+ tmp_dstring = unparse_str(princ->policy);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ tmp_dstring = unparse_aux_attributes(princ->aux_attributes);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ sprintf(buf, "%d", princ->max_renewable_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->last_success);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->last_failed);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->fail_auth_count);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->n_key_data);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->n_tl_data);
+ Tcl_DStringAppendElement(str, buf);
+
+ tmp_dstring = unparse_key_data(princ->key_data, princ->n_key_data);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ tmp_dstring = unparse_tl_data(princ->tl_data, princ->n_tl_data);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ return str;
+}
+
+static int parse_keysalts(Tcl_Interp *interp, char *list,
+ krb5_key_salt_tuple **keysalts,
+ int num_keysalts)
+{
+ char **argv, **argv1 = NULL;
+ int i, tmp, argc, argc1, retcode;
+
+ *keysalts = NULL;
+ if (list == NULL)
+ return TCL_OK;
+
+ if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return retcode;
+ }
+ if (argc != num_keysalts) {
+ sprintf(interp->result, "%d keysalts specified, "
+ "but num_keysalts is %d", argc, num_keysalts);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ *keysalts = (krb5_key_salt_tuple *)
+ malloc(sizeof(krb5_key_salt_tuple)*num_keysalts);
+ for (i = 0; i < num_keysalts; i++) {
+ if ((retcode = Tcl_SplitList(interp, argv[i], &argc1, &argv1)) !=
+ TCL_OK) {
+ goto finished;
+ }
+ if (argc1 != 2) {
+ sprintf(interp->result, "wrong # fields in keysalt "
+ "(%d should be 2)", argc1);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = Tcl_GetInt(interp, argv1[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing ks_enctype");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ (*keysalts)[i].ks_enctype = tmp;
+ if ((retcode = Tcl_GetInt(interp, argv1[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing ks_salttype");
+ goto finished;
+ }
+ (*keysalts)[i].ks_salttype = tmp;
+
+ free(argv1);
+ }
+
+finished:
+ if (argv1)
+ free(argv1);
+ if (*keysalts)
+ free(*keysalts);
+ free(argv);
+ return retcode;
+}
+
+static int parse_config_params(Tcl_Interp *interp, char *list,
+ kadm5_config_params *params)
+{
+ static Tcl_HashTable *table = 0;
+ char **argv = NULL;
+ int tmp, argc, retcode;
+
+ memset(params, 0, sizeof(kadm5_config_params));
+ if (list == NULL)
+ return TCL_OK;
+
+ if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return retcode;
+ }
+
+ if (argc != 21) {
+ sprintf(interp->result,
+ "wrong # args in config params structure (%d should be 21)",
+ argc);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((retcode = parse_flags(interp, table, config_mask_flags,
+ sizeof(config_mask_flags) /
+ sizeof(struct flagval),
+ argv[0], &tmp)) != TCL_OK) {
+ goto finished;
+ }
+ params->mask = tmp;
+
+ if ((retcode = parse_str(interp, argv[1], &params->realm)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing realm name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[2], &params->profile)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing profile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = Tcl_GetInt(interp, argv[3], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing kadmind_port");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->kadmind_port = tmp;
+ if ((retcode = parse_str(interp, argv[4], &params->admin_server))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing profile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[5], &params->dbname)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing profile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[6], &params->admin_dbname)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_dbname name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[7], &params->admin_lockfile)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_lockfile name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[8], &params->admin_keytab)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing admin_keytab name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[9], &params->acl_file)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing acl_file name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[10], &params->dict_file)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing dict_file name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = Tcl_GetInt(interp, argv[11], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mkey_from_kbd");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->mkey_from_kbd = tmp;
+ if ((retcode = parse_str(interp, argv[12], &params->stash_file)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing stash_file name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = parse_str(interp, argv[13], &params->mkey_name)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mkey_name name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((retcode = Tcl_GetInt(interp, argv[14], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing enctype");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->enctype = tmp;
+ if ((retcode = Tcl_GetInt(interp, argv[15], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing max_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->max_life = tmp;
+ if ((retcode = Tcl_GetInt(interp, argv[16], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing max_rlife");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->max_rlife = tmp;
+ if ((retcode = Tcl_GetInt(interp, argv[17], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing expiration");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->expiration = tmp;
+ if ((retcode = parse_krb5_flags(interp, argv[18], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing flags");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->flags = tmp;
+ if ((retcode = Tcl_GetInt(interp, argv[19], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing num_keysalts");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ params->num_keysalts = tmp;
+ if ((retcode = parse_keysalts(interp, argv[20], &params->keysalts,
+ params->num_keysalts)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing keysalts");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+finished:
+ return retcode;
+}
+
+static int parse_principal_ent(Tcl_Interp *interp, char *list,
+ kadm5_principal_ent_t *out_princ)
+{
+ kadm5_principal_ent_t princ;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ int argc;
+ char **argv;
+ int tmp;
+ int retcode = TCL_OK;
+
+ if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (argc != 12) {
+ sprintf(interp->result, "wrong # args in principal structure (%d should be 12)",
+ argc);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if (! (princ = malloc(sizeof *princ))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ if ((krb5_ret = krb5_parse_name(context, argv[0], &princ->principal)) != 0) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ /*
+ * All of the numerical values parsed here are parsed into an
+ * "int" and then assigned into the structure in case the actual
+ * width of the field in the Kerberos structure is different from
+ * the width of an integer.
+ */
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing princ_expire_time");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->princ_expire_time = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing last_pwd_change");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->last_pwd_change = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_expiration");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->pw_expiration = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing max_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->max_life = tmp;
+
+ if ((krb5_ret = krb5_parse_name(context, argv[5], &princ->mod_name)) != 0) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing mod_name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mod_date");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->mod_date = tmp;
+
+ if ((tcl_ret = parse_krb5_flags(interp, argv[7], &princ->attributes))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing attributes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[8], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing kvno");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->kvno = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[9], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mkvno");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->mkvno = tmp;
+
+ if ((tcl_ret = parse_str(interp, argv[10], &princ->policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if(princ->policy != NULL) {
+ if(!(princ->policy = strdup(princ->policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ }
+
+ if ((tcl_ret = parse_aux_attributes(interp, argv[11],
+ &princ->aux_attributes)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing aux_attributes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+finished:
+ free(argv);
+ *out_princ = princ;
+ return retcode;
+}
+
+
+static void free_principal_ent(kadm5_principal_ent_t *princ)
+{
+ krb5_free_principal(context, (*princ)->principal);
+ krb5_free_principal(context, (*princ)->mod_name);
+ free(*princ);
+ *princ = 0;
+}
+
+static Tcl_DString *unparse_policy_ent(kadm5_policy_ent_t policy)
+{
+ Tcl_DString *str, *tmp_dstring;
+ char buf[20];
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ tmp_dstring = unparse_str(policy->policy);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ sprintf(buf, "%d", policy->pw_min_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_length);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_classes);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_history_num);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->policy_refcnt);
+ Tcl_DStringAppendElement(str, buf);
+
+ return str;
+}
+
+
+
+static int parse_policy_ent(Tcl_Interp *interp, char *list,
+ kadm5_policy_ent_t *out_policy)
+{
+ kadm5_policy_ent_t policy;
+ int tcl_ret;
+ int argc;
+ char **argv;
+ int tmp;
+ int retcode = TCL_OK;
+
+ if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (argc != 7) {
+ sprintf(interp->result, "wrong # args in policy structure (%d should be 7)",
+ argc);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if (! (policy = malloc(sizeof *policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy->policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if(policy->policy != NULL) {
+ if (! (policy->policy = strdup(policy->policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ }
+
+ /*
+ * All of the numerical values parsed here are parsed into an
+ * "int" and then assigned into the structure in case the actual
+ * width of the field in the Kerberos structure is different from
+ * the width of an integer.
+ */
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_life = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_max_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_max_life = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_length");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_length = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_classes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_classes = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[5], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_history_num");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_history_num = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy_refcnt");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->policy_refcnt = tmp;
+
+finished:
+ free(argv);
+ *out_policy = policy;
+ return retcode;
+}
+
+
+static void free_policy_ent(kadm5_policy_ent_t *policy)
+{
+ free(*policy);
+ *policy = 0;
+}
+
+static Tcl_DString *unparse_keytype(krb5_enctype enctype)
+{
+ Tcl_DString *str;
+ char buf[50];
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ switch (enctype) {
+ /* XXX is this right? */
+ case ENCTYPE_NULL: Tcl_DStringAppend(str, "ENCTYPE_NULL", -1); break;
+ case ENCTYPE_DES_CBC_CRC:
+ Tcl_DStringAppend(str, "ENCTYPE_DES_CBC_CRC", -1); break;
+ default:
+ sprintf(buf, "UNKNOWN KEYTYPE (0x%x)", enctype);
+ Tcl_DStringAppend(str, buf, -1);
+ break;
+ }
+
+ return str;
+}
+
+
+static Tcl_DString *unparse_keyblocks(krb5_keyblock *keyblocks, int num_keys)
+{
+ Tcl_DString *str;
+ Tcl_DString *keytype;
+ int i, j;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ for (j = 0; j < num_keys; j++) {
+ krb5_keyblock *keyblock = &keyblocks[j];
+
+ Tcl_DStringStartSublist(str);
+
+ keytype = unparse_keytype(keyblock->enctype);
+ Tcl_DStringAppendElement(str, keytype->string);
+ Tcl_DStringFree(keytype);
+ free(keytype);
+ if (keyblock->length == 0) {
+ Tcl_DStringAppendElement(str, "0x00");
+ }
+ else {
+ Tcl_DStringAppendElement(str, "0x");
+ for (i = 0; i < keyblock->length; i++) {
+ char buf[3];
+ sprintf(buf, "%02x", (int) keyblock->contents[i]);
+ Tcl_DStringAppend(str, buf, -1);
+ }
+ }
+
+ Tcl_DStringEndSublist(str);
+ }
+
+
+ return str;
+}
+
+enum init_type { INIT_NONE, INIT_PASS, INIT_CREDS };
+
+int _tcl_kadm5_init_any(enum init_type init_type, ClientData clientData,
+ Tcl_Interp *interp, int argc, char *argv[])
+{
+ kadm5_ret_t ret;
+ char *client_name, *pass, *service_name, *realm;
+ int tcl_ret;
+ krb5_ui_4 struct_version, api_version;
+ char *handle_var;
+ void *server_handle;
+ char *handle_name, *params_str;
+ char *whoami = argv[0];
+ kadm5_config_params params;
+
+ argv++, argc--;
+
+ krb5_init_context(&context);
+
+ if (argc != 7) {
+ Tcl_AppendResult(interp, whoami, ": ", arg_error, 0);
+ return TCL_ERROR;
+ }
+
+ if (((tcl_ret = parse_str(interp, argv[0], &client_name)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[1], &pass)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[2], &service_name)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[3], &params_str)) != TCL_OK) ||
+ ((tcl_ret = parse_config_params(interp, params_str, &params))
+ != TCL_OK) ||
+ ((tcl_ret = Tcl_GetInt(interp, argv[4], (int *) &struct_version)) !=
+ TCL_OK) ||
+ ((tcl_ret = Tcl_GetInt(interp, argv[5], (int *) &api_version)) !=
+ TCL_OK)) {
+ return tcl_ret;
+ }
+
+ handle_var = argv[6];
+
+ if (! (handle_var && *handle_var)) {
+ Tcl_SetResult(interp, "must specify server handle variable name",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ if (init_type == INIT_CREDS) {
+ krb5_ccache cc;
+
+ if (pass == NULL) {
+ if (ret = krb5_cc_default(context, &cc)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ } else {
+ if (ret = krb5_cc_resolve(context, pass, &cc)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ }
+
+ ret = kadm5_init_with_creds(client_name, cc, service_name,
+ &params, struct_version,
+ api_version, &server_handle);
+
+ (void) krb5_cc_close(context, cc);
+ } else
+ ret = kadm5_init(client_name, pass, service_name, &params,
+ struct_version, api_version, &server_handle);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = put_server_handle(interp, server_handle, &handle_name))
+ != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (! Tcl_SetVar(interp, handle_var, handle_name, TCL_LEAVE_ERR_MSG)) {
+ return TCL_ERROR;
+ }
+
+ set_ok(interp, "KADM5 API initialized.");
+ return TCL_OK;
+}
+
+int tcl_kadm5_init(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ return _tcl_kadm5_init_any(INIT_PASS, clientData, interp, argc, argv);
+}
+
+int tcl_kadm5_init_with_creds(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ return _tcl_kadm5_init_any(INIT_CREDS, clientData, interp, argc, argv);
+}
+
+int tcl_kadm5_destroy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ kadm5_ret_t ret;
+ int tcl_ret;
+
+ GET_HANDLE(0, 0);
+
+ ret = kadm5_destroy(server_handle);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = remove_server_handle(interp, argv[-1])) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ set_ok(interp, "KADM5 API deinitialized.");
+ return TCL_OK;
+}
+
+int tcl_kadm5_create_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+ char *princ_string;
+ kadm5_principal_ent_t princ = 0;
+ krb5_int32 mask;
+ char *pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+
+ GET_HANDLE(3, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing principal");
+ return tcl_ret;
+ }
+
+ if (princ_string &&
+ ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[2], &pw)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[3], &override_qual)) !=
+ TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+#endif
+
+#ifdef OVERRIDE
+ ret = kadm5_create_principal(server_handle, princ, mask, pw,
+ override_qual);
+#else
+ ret = kadm5_create_principal(server_handle, princ, mask, pw);
+#endif
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ else {
+ set_ok(interp, "Principal created.");
+ }
+
+finished:
+ if (princ) {
+ free_principal_ent(&princ);
+ }
+ return retcode;
+}
+
+
+
+int tcl_kadm5_delete_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ kadm5_ret_t ret;
+ int tcl_ret;
+ char *name;
+
+ GET_HANDLE(1, 0);
+
+ if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+ return tcl_ret;
+ if(name != NULL) {
+ if (krb5_ret = krb5_parse_name(context, name, &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal");
+ return TCL_ERROR;
+ }
+ } else princ = NULL;
+ ret = kadm5_delete_principal(server_handle, princ);
+
+ if(princ != NULL)
+ krb5_free_principal(context, princ);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Principal deleted.");
+ return TCL_OK;
+ }
+}
+
+
+
+int tcl_kadm5_modify_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *princ_string;
+ kadm5_principal_ent_t princ = 0;
+ int tcl_ret;
+ krb5_int32 mask;
+ int retcode = TCL_OK;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing principal");
+ return tcl_ret;
+ }
+
+ if (princ_string &&
+ ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_modify_principal(server_handle, princ, mask);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Principal modified.");
+ }
+
+finished:
+ if (princ) {
+ free_principal_ent(&princ);
+ }
+ return retcode;
+}
+
+
+int tcl_kadm5_rename_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal source, target;
+ krb5_error_code krb5_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &source)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing source");
+ return TCL_ERROR;
+ }
+
+ if (krb5_ret = krb5_parse_name(context, argv[1], &target)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing target");
+ krb5_free_principal(context, source);
+ return TCL_ERROR;
+ }
+
+ ret = kadm5_rename_principal(server_handle, source, target);
+
+ if (ret == KADM5_OK) {
+ set_ok(interp, "Principal renamed.");
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+ krb5_free_principal(context, source);
+ krb5_free_principal(context, target);
+ return retcode;
+}
+
+
+
+int tcl_kadm5_chpass_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ char *pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ int retcode = TCL_OK;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_chpass_principal(server_handle,
+ princ, pw, override_qual);
+#else
+ ret = kadm5_chpass_principal(server_handle, princ, pw);
+#endif
+
+ if (ret == KADM5_OK) {
+ set_ok(interp, "Password changed.");
+ goto finished;
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ return retcode;
+}
+
+
+
+int tcl_kadm5_chpass_principal_util(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ char *new_pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+ char *pw_ret, *pw_ret_var;
+ char msg_ret[1024], *msg_ret_var;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(4, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &new_pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing new password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#endif
+ if ((tcl_ret = parse_str(interp, argv[3], &pw_ret_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_ret variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[4], &msg_ret_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing msg_ret variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_chpass_principal_util(server_handle, princ, new_pw,
+#ifdef OVERRIDE
+ override_qual,
+#endif
+ pw_ret_var ? &pw_ret : 0,
+ msg_ret_var ? msg_ret : 0);
+
+ if (ret == KADM5_OK) {
+ if (pw_ret_var &&
+ (! Tcl_SetVar(interp, pw_ret_var, pw_ret,
+ TCL_LEAVE_ERR_MSG))) {
+ Tcl_AppendElement(interp, "while setting pw_ret variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if (msg_ret_var &&
+ (! Tcl_SetVar(interp, msg_ret_var, msg_ret,
+ TCL_LEAVE_ERR_MSG))) {
+ Tcl_AppendElement(interp,
+ "while setting msg_ret variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Password changed.");
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ return retcode;
+}
+
+
+
+int tcl_kadm5_randkey_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_keyblock *keyblocks;
+ int num_keys;
+ char *keyblock_var, *num_var, buf[50];
+ Tcl_DString *keyblock_dstring = 0;
+ krb5_error_code krb5_ret;
+ kadm5_ret_t ret;
+ int tcl_ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(3, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &keyblock_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing keyblock variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((tcl_ret = parse_str(interp, argv[2], &num_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing keyblock variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_randkey_principal(server_handle,
+ princ, keyblock_var ? &keyblocks : 0,
+ num_var ? &num_keys : 0);
+
+ if (ret == KADM5_OK) {
+ if (keyblock_var) {
+ keyblock_dstring = unparse_keyblocks(keyblocks, num_keys);
+ if (! Tcl_SetVar(interp, keyblock_var,
+ keyblock_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting keyblock variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ }
+ if (num_var) {
+ sprintf(buf, "%d", num_keys);
+ if (! Tcl_SetVar(interp, num_var, buf,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting num_keys variable");
+ }
+ }
+ set_ok(interp, "Key randomized.");
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ if (keyblock_dstring) {
+ Tcl_DStringFree(keyblock_dstring);
+ free(keyblock_dstring);
+ }
+ return retcode;
+}
+
+
+
+int tcl_kadm5_get_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ kadm5_principal_ent_rec ent;
+ Tcl_DString *ent_dstring = 0;
+ char *ent_var;
+ char *name;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ kadm5_ret_t ret = -1;
+ krb5_int32 mask;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(3, 1);
+
+ if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+ return tcl_ret;
+ if(name != NULL) {
+ if (krb5_ret = krb5_parse_name(context, name, &princ)) {
+ stash_error(interp, ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+ } else princ = NULL;
+
+ if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if ((tcl_ret = parse_principal_mask(interp, argv[2], &mask)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing principal mask");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_get_principal(server_handle, princ, ent_var ? &ent : 0,
+ mask);
+
+ if (ret == KADM5_OK) {
+ if (ent_var) {
+ ent_dstring = unparse_principal_ent(&ent);
+ if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Principal retrieved.");
+ }
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ if (ent_dstring) {
+ Tcl_DStringFree(ent_dstring);
+ free(ent_dstring);
+ }
+ if(princ != NULL)
+ krb5_free_principal(context, princ);
+ if (ret == KADM5_OK && ent_var &&
+ (ret = kadm5_free_principal_ent(server_handle, &ent)) &&
+ (retcode == TCL_OK)) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ return retcode;
+}
+
+int tcl_kadm5_create_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+ char *policy_string;
+ kadm5_policy_ent_t policy = 0;
+ krb5_int32 mask;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ return tcl_ret;
+ }
+
+ if (policy_string &&
+ ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+
+ ret = kadm5_create_policy(server_handle, policy, mask);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ else {
+ set_ok(interp, "Policy created.");
+ }
+
+finished:
+ if (policy) {
+ free_policy_ent(&policy);
+ }
+ return retcode;
+}
+
+
+
+int tcl_kadm5_delete_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ kadm5_ret_t ret;
+ char *policy;
+ int tcl_ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ ret = kadm5_delete_policy(server_handle, policy);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Policy deleted.");
+ return TCL_OK;
+ }
+}
+
+
+
+int tcl_kadm5_modify_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *policy_string;
+ kadm5_policy_ent_t policy = 0;
+ int tcl_ret;
+ krb5_int32 mask;
+ int retcode = TCL_OK;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ return tcl_ret;
+ }
+
+ if (policy_string &&
+ ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = kadm5_modify_policy(server_handle, policy, mask);
+
+ if (ret != KADM5_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Policy modified.");
+ }
+
+finished:
+ if (policy) {
+ free_policy_ent(&policy);
+ }
+ return retcode;
+}
+
+
+int tcl_kadm5_get_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ kadm5_policy_ent_rec ent;
+ Tcl_DString *ent_dstring = 0;
+ char *policy;
+ char *ent_var;
+ int tcl_ret;
+ kadm5_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 1);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry variable name");
+ return TCL_ERROR;
+ }
+
+ ret = kadm5_get_policy(server_handle, policy, ent_var ? &ent : 0);
+
+ if (ret == KADM5_OK) {
+ if (ent_var) {
+ ent_dstring = unparse_policy_ent(&ent);
+ if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Policy retrieved.");
+ }
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ if (ent_dstring) {
+ Tcl_DStringFree(ent_dstring);
+ free(ent_dstring);
+ }
+ if (ent_var && ret == KADM5_OK &&
+ (ret = kadm5_free_policy_ent(server_handle, &ent)) &&
+ (retcode == TCL_OK)) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ return retcode;
+}
+
+
+
+int tcl_kadm5_free_principal_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ kadm5_principal_ent_t ent;
+ int tcl_ret;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &ent_name)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry name");
+ return TCL_ERROR;
+ }
+
+ if ((! ent_name) &&
+ (ret = kadm5_free_principal_ent(server_handle, 0))) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ Tcl_HashEntry *entry;
+
+ if (strncmp(ent_name, "principal", sizeof("principal")-1)) {
+ Tcl_AppendResult(interp, "invalid principal handle \"",
+ ent_name, "\"", 0);
+ return TCL_ERROR;
+ }
+ if (! struct_table) {
+ if (! (struct_table = malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+ Tcl_AppendResult(interp, "principal handle \"", ent_name,
+ "\" not found", 0);
+ return TCL_ERROR;
+ }
+
+ ent = Tcl_GetHashValue(entry);
+
+ if (ret = kadm5_free_principal_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Principal freed.");
+ return TCL_OK;
+}
+
+
+int tcl_kadm5_free_policy_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ kadm5_policy_ent_t ent;
+ int tcl_ret;
+ kadm5_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &ent_name)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry name");
+ return TCL_ERROR;
+ }
+
+ if ((! ent_name) &&
+ (ret = kadm5_free_policy_ent(server_handle, 0))) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ Tcl_HashEntry *entry;
+
+ if (strncmp(ent_name, "policy", sizeof("policy")-1)) {
+ Tcl_AppendResult(interp, "invalid principal handle \"",
+ ent_name, "\"", 0);
+ return TCL_ERROR;
+ }
+ if (! struct_table) {
+ if (! (struct_table = malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+ Tcl_AppendResult(interp, "policy handle \"", ent_name,
+ "\" not found", 0);
+ return TCL_ERROR;
+ }
+
+ ent = Tcl_GetHashValue(entry);
+
+ if (ret = kadm5_free_policy_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Policy freed.");
+ return TCL_OK;
+}
+
+
+int tcl_kadm5_get_privs(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ char *set_ret;
+ kadm5_ret_t ret;
+ char *priv_var;
+ long privs;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &priv_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing privs variable name");
+ return TCL_ERROR;
+ }
+
+ ret = kadm5_get_privs(server_handle, priv_var ? &privs : 0);
+
+ if (ret == KADM5_OK) {
+ if (priv_var) {
+ Tcl_DString *str = unparse_privs(privs);
+ set_ret = Tcl_SetVar(interp, priv_var, str->string,
+ TCL_LEAVE_ERR_MSG);
+ Tcl_DStringFree(str);
+ free(str);
+ if (! set_ret) {
+ Tcl_AppendElement(interp, "while setting priv variable");
+ return TCL_ERROR;
+ }
+ }
+ set_ok(interp, "Privileges retrieved.");
+ return TCL_OK;
+ }
+ else {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+}
+
+
+void Tcl_kadm5_init(Tcl_Interp *interp)
+{
+ char buf[20];
+
+ Tcl_SetVar(interp, "KADM5_ADMIN_SERVICE",
+ KADM5_ADMIN_SERVICE, TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp, "KADM5_CHANGEPW_SERVICE",
+ KADM5_CHANGEPW_SERVICE, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_STRUCT_VERSION);
+ Tcl_SetVar(interp, "KADM5_STRUCT_VERSION", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_API_VERSION_1);
+ Tcl_SetVar(interp, "KADM5_API_VERSION_1", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_API_VERSION_2);
+ Tcl_SetVar(interp, "KADM5_API_VERSION_2", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_API_VERSION_MASK);
+ Tcl_SetVar(interp, "KADM5_API_VERSION_MASK", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_STRUCT_VERSION_MASK);
+ Tcl_SetVar(interp, "KADM5_STRUCT_VERSION_MASK", buf,
+ TCL_GLOBAL_ONLY);
+
+ Tcl_CreateCommand(interp, "kadm5_init", tcl_kadm5_init, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_init_with_creds",
+ tcl_kadm5_init_with_creds, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_destroy", tcl_kadm5_destroy, 0,
+ 0);
+ Tcl_CreateCommand(interp, "kadm5_create_principal",
+ tcl_kadm5_create_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_delete_principal",
+ tcl_kadm5_delete_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_modify_principal",
+ tcl_kadm5_modify_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_rename_principal",
+ tcl_kadm5_rename_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_chpass_principal",
+ tcl_kadm5_chpass_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_chpass_principal_util",
+ tcl_kadm5_chpass_principal_util, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_randkey_principal",
+ tcl_kadm5_randkey_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_get_principal",
+ tcl_kadm5_get_principal, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_create_policy",
+ tcl_kadm5_create_policy, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_delete_policy",
+ tcl_kadm5_delete_policy, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_modify_policy",
+ tcl_kadm5_modify_policy, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_get_policy",
+ tcl_kadm5_get_policy, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_free_principal_ent",
+ tcl_kadm5_free_principal_ent, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_free_policy_ent",
+ tcl_kadm5_free_policy_ent, 0, 0);
+ Tcl_CreateCommand(interp, "kadm5_get_privs",
+ tcl_kadm5_get_privs, 0, 0);
+}
diff --git a/src/kadmin/testing/util/tcl_krb5_hash.c b/src/kadmin/testing/util/tcl_krb5_hash.c
new file mode 100644
index 000000000..95a3451d9
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_krb5_hash.c
@@ -0,0 +1,163 @@
+/*
+ * All of the TCL krb5 functions which return (or place into output
+ * variables) structures or pointers to structures that can't be
+ * represented as tcl native types, do so by returning a handle for
+ * the appropriate structure. The handle is a string of the form
+ * "type$id", where "type" is the type of datum represented by the
+ * handle and "id" is a unique identifier for it. This handle can
+ * then be used later by the caller to refer to the object, and
+ * internally to retrieve the actually datum from the appropriate hash
+ * table.
+ *
+ * The functions in this file do four things:
+ *
+ * 1) Given a pointer to a datum and a string representing the type of
+ * datum to which the pointer refers, create a new handle for the
+ * datum, store the datum in the hash table using the new handle as
+ * its key, and return the new handle.
+ *
+ * 2) Given a handle, locate and return the appropriate hash table
+ * datum.
+ *
+ * 3) Given a handle, look through a table of types and unparse
+ * functions to figure out what function to call to get a string
+ * representation of the datum, call it with the appropriate pointer
+ * (obtained from the hash table) as an argument, and return the
+ * resulting string as the unparsed form of the datum.
+ *
+ * 4) Given a handle, remove that handle and its associated datum from
+ * the hash table (but don't free it -- it's assumed to have already
+ * been freed by the caller).
+ */
+
+#include <tcl.h>
+#include <assert.h>
+
+#define SEP_STR "$"
+
+static char *memory_error = "out of memory";
+
+/*
+ * Right now, we're only using one hash table. However, at some point
+ * in the future, we might decide to use a separate hash table for
+ * every type. Therefore, I'm putting this function in as an
+ * abstraction so it's the only thing we'll have to change if we
+ * decide to do that.
+ *
+ * Also, this function allows us to put in just one place the code for
+ * checking to make sure that the hash table exists and initializing
+ * it if it doesn't.
+ */
+
+static TclHashTable *get_hash_table(Tcl_Interp *interp,
+ char *type)
+{
+ static Tcl_HashTable *hash_table = 0;
+
+ if (! hash_table) {
+ if (! (hash_table = malloc(sizeof(*hash_table)))) {
+ Tcl_SetResult(interp, memory_error, TCL_STATIC);
+ return 0;
+ }
+ Tcl_InitHashTable(hash_table, TCL_STRING_KEYS);
+ }
+ return hash_table;
+}
+
+#define MAX_ID 999999999
+#define ID_BUF_SIZE 10
+
+static Tcl_HashEntry *get_new_handle(Tcl_Interp *interp,
+ char *type)
+{
+ static unsigned long int id_counter = 0;
+ Tcl_DString *handle;
+ char int_buf[ID_BUF_SIZE];
+
+ if (! (handle = malloc(sizeof(*handle)))) {
+ Tcl_SetResult(interp, memory_error, TCL_STATIC);
+ return 0;
+ }
+ Tcl_DStringInit(handle);
+
+ assert(id_counter <= MAX_ID);
+
+ sprintf(int_buf, "%d", id_counter++);
+
+ Tcl_DStringAppend(handle, type, -1);
+ Tcl_DStringAppend(handle, SEP_STR, -1);
+ Tcl_DStringAppend(handle, int_buf, -1);
+
+ return handle;
+}
+
+
+Tcl_DString *tcl_krb5_create_object(Tcl_Interp *interp,
+ char *type,
+ ClientData datum)
+{
+ Tcl_HashTable *table;
+ Tcl_DString *handle;
+ Tcl_HashEntry *entry;
+ int entry_created = 0;
+
+ if (! (table = get_hash_table(interp, type))) {
+ return 0;
+ }
+
+ if (! (handle = get_new_handle(interp, type))) {
+ return 0;
+ }
+
+ if (! (entry = Tcl_CreateHashEntry(table, handle, &entry_created))) {
+ Tcl_SetResult(interp, "error creating hash entry", TCL_STATIC);
+ Tcl_DStringFree(handle);
+ return TCL_ERROR;
+ }
+
+ assert(entry_created);
+
+ Tcl_SetHashValue(entry, datum);
+
+ return handle;
+}
+
+ClientData tcl_krb5_get_object(Tcl_Interp *interp,
+ char *handle)
+{
+ char *myhandle, *id_ptr;
+ Tcl_HashTable *table;
+ Tcl_HashEntry *entry;
+
+ if (! (myhandle = strdup(handle))) {
+ Tcl_SetResult(interp, memory_error, TCL_STATIC);
+ return 0;
+ }
+
+ if (! (id_ptr = index(myhandle, *SEP_STR))) {
+ free(myhandle);
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "malformatted handle \"", handle,
+ "\"", 0);
+ return 0;
+ }
+
+ *id_ptr = '\0';
+
+ if (! (table = get_hash_table(interp, myhandle))) {
+ free(myhandle);
+ return 0;
+ }
+
+ free(myhandle);
+
+ if (! (entry = Tcl_FindHashEntry(table, handle))) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "no object corresponding to handle \"",
+ handle, "\"", 0);
+ return 0;
+ }
+
+ return(Tcl_GetHashValue(entry));
+}
+
diff --git a/src/kadmin/testing/util/tcl_ovsec_kadm.c b/src/kadmin/testing/util/tcl_ovsec_kadm.c
new file mode 100644
index 000000000..0c6aaac9c
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_ovsec_kadm.c
@@ -0,0 +1,2016 @@
+#include <stdio.h>
+#include <string.h>
+#include <tcl.h>
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <malloc.h>
+#include <k5-int.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct flagval {
+ char *name;
+ krb5_flags val;
+};
+
+/* XXX This should probably be in the hash table like server_handle */
+static krb5_context context;
+
+struct flagval krb5_flags_array[] = {
+ {"KRB5_KDB_DISALLOW_POSTDATED", KRB5_KDB_DISALLOW_POSTDATED},
+ {"KRB5_KDB_DISALLOW_FORWARDABLE", KRB5_KDB_DISALLOW_FORWARDABLE},
+ {"KRB5_KDB_DISALLOW_TGT_BASED", KRB5_KDB_DISALLOW_TGT_BASED},
+ {"KRB5_KDB_DISALLOW_RENEWABLE", KRB5_KDB_DISALLOW_RENEWABLE},
+ {"KRB5_KDB_DISALLOW_PROXIABLE", KRB5_KDB_DISALLOW_PROXIABLE},
+ {"KRB5_KDB_DISALLOW_DUP_SKEY", KRB5_KDB_DISALLOW_DUP_SKEY},
+ {"KRB5_KDB_DISALLOW_ALL_TIX", KRB5_KDB_DISALLOW_ALL_TIX},
+ {"KRB5_KDB_REQUIRES_PRE_AUTH", KRB5_KDB_REQUIRES_PRE_AUTH},
+ {"KRB5_KDB_REQUIRES_HW_AUTH", KRB5_KDB_REQUIRES_HW_AUTH},
+ {"KRB5_KDB_REQUIRES_PWCHANGE", KRB5_KDB_REQUIRES_PWCHANGE},
+ {"KRB5_KDB_DISALLOW_SVR", KRB5_KDB_DISALLOW_SVR},
+ {"KRB5_KDB_PWCHANGE_SERVICE", KRB5_KDB_PWCHANGE_SERVICE}
+};
+
+struct flagval aux_attributes[] = {
+ {"OVSEC_KADM_POLICY", OVSEC_KADM_POLICY}
+};
+
+struct flagval principal_mask_flags[] = {
+ {"OVSEC_KADM_PRINCIPAL", OVSEC_KADM_PRINCIPAL},
+ {"OVSEC_KADM_PRINC_EXPIRE_TIME", OVSEC_KADM_PRINC_EXPIRE_TIME},
+ {"OVSEC_KADM_PW_EXPIRATION", OVSEC_KADM_PW_EXPIRATION},
+ {"OVSEC_KADM_LAST_PWD_CHANGE", OVSEC_KADM_LAST_PWD_CHANGE},
+ {"OVSEC_KADM_ATTRIBUTES", OVSEC_KADM_ATTRIBUTES},
+ {"OVSEC_KADM_MAX_LIFE", OVSEC_KADM_MAX_LIFE},
+ {"OVSEC_KADM_MOD_TIME", OVSEC_KADM_MOD_TIME},
+ {"OVSEC_KADM_MOD_NAME", OVSEC_KADM_MOD_NAME},
+ {"OVSEC_KADM_KVNO", OVSEC_KADM_KVNO},
+ {"OVSEC_KADM_MKVNO", OVSEC_KADM_MKVNO},
+ {"OVSEC_KADM_AUX_ATTRIBUTES", OVSEC_KADM_AUX_ATTRIBUTES},
+ {"OVSEC_KADM_POLICY", OVSEC_KADM_POLICY},
+ {"OVSEC_KADM_POLICY_CLR", OVSEC_KADM_POLICY_CLR}
+};
+
+struct flagval policy_mask_flags[] = {
+ {"OVSEC_KADM_POLICY", OVSEC_KADM_POLICY},
+ {"OVSEC_KADM_PW_MAX_LIFE", OVSEC_KADM_PW_MAX_LIFE},
+ {"OVSEC_KADM_PW_MIN_LIFE", OVSEC_KADM_PW_MIN_LIFE},
+ {"OVSEC_KADM_PW_MIN_LENGTH", OVSEC_KADM_PW_MIN_LENGTH},
+ {"OVSEC_KADM_PW_MIN_CLASSES", OVSEC_KADM_PW_MIN_CLASSES},
+ {"OVSEC_KADM_PW_HISTORY_NUM", OVSEC_KADM_PW_HISTORY_NUM},
+ {"OVSEC_KADM_REF_COUNT", OVSEC_KADM_REF_COUNT}
+};
+
+struct flagval priv_flags[] = {
+ {"OVSEC_KADM_PRIV_GET", OVSEC_KADM_PRIV_GET},
+ {"OVSEC_KADM_PRIV_ADD", OVSEC_KADM_PRIV_ADD},
+ {"OVSEC_KADM_PRIV_MODIFY", OVSEC_KADM_PRIV_MODIFY},
+ {"OVSEC_KADM_PRIV_DELETE", OVSEC_KADM_PRIV_DELETE}
+};
+
+
+static char *arg_error = "wrong # args";
+
+static Tcl_HashTable *struct_table = 0;
+
+static int put_server_handle(Tcl_Interp *interp, void *handle, char **name)
+{
+ int i = 1, newPtr = 0;
+ static char buf[20];
+ Tcl_HashEntry *entry;
+
+ if (! struct_table) {
+ if (! (struct_table =
+ malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ do {
+ /*
+ * Handles from ovsec_kadm_init() and kadm5_init() should not
+ * be mixed during unit tests, but the API would happily
+ * accept them. Making the hash entry names different in
+ * tcl_kadm.c and tcl_ovsec_kadm.c ensures that GET_HANDLE
+ * will fail if presented a handle from the other API.
+ */
+ sprintf(buf, "ovsec_kadm_handle%d", i);
+ entry = Tcl_CreateHashEntry(struct_table, buf, &newPtr);
+ i++;
+ } while (! newPtr);
+
+ Tcl_SetHashValue(entry, handle);
+
+ *name = buf;
+
+ return TCL_OK;
+}
+
+static int get_server_handle(Tcl_Interp *interp, char *name, void **handle)
+{
+ Tcl_HashEntry *entry;
+
+ if(!strcasecmp(name, "null"))
+ *handle = 0;
+ else {
+ if (! (struct_table &&
+ (entry = Tcl_FindHashEntry(struct_table, name)))) {
+ if (strncmp(name, "kadm5_handle", 12) == 0)
+ Tcl_AppendResult(interp, "kadm5 handle specified "
+ "for ovsec_kadm api: ", name, 0);
+ else
+ Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+ return TCL_ERROR;
+ }
+ *handle = (void *) Tcl_GetHashValue(entry);
+ }
+ return TCL_OK;
+}
+
+static int remove_server_handle(Tcl_Interp *interp, char *name)
+{
+ Tcl_HashEntry *entry;
+
+ if (! (struct_table &&
+ (entry = Tcl_FindHashEntry(struct_table, name)))) {
+ Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+ return TCL_ERROR;
+ }
+
+ Tcl_DeleteHashEntry(entry);
+ return TCL_OK;
+}
+
+#define GET_HANDLE(num_args, do_dostruct) \
+ void *server_handle; \
+ int dostruct = 0; \
+ char *whoami = argv[0]; \
+ argv++, argc--; \
+ if ((argc > 0) && (! strcmp(argv[0], "-struct"))) { \
+ if (! do_dostruct) { \
+ Tcl_AppendResult(interp, "-struct isn't a valid option for ", \
+ whoami, 0); \
+ return TCL_ERROR; \
+ } \
+ dostruct++; \
+ argv++, argc--; \
+ } \
+ if (argc != num_args + 1) { \
+ Tcl_AppendResult(interp, whoami, ": ", arg_error, 0); \
+ return TCL_ERROR; \
+ } \
+ { \
+ int tcl_ret; \
+ if ((tcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+ != TCL_OK) { \
+ return tcl_ret; \
+ } \
+ } \
+ argv++, argc--;
+
+static Tcl_HashTable *create_flag_table(struct flagval *flags, int size)
+{
+ Tcl_HashTable *table;
+ Tcl_HashEntry *entry;
+ int i;
+
+ if (! (table = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_InitHashTable(table, TCL_STRING_KEYS);
+
+ for (i = 0; i < size; i++) {
+ int newPtr;
+
+ if (! (entry = Tcl_CreateHashEntry(table, flags[i].name, &newPtr))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_SetHashValue(entry, &flags[i].val);
+ }
+
+ return table;
+}
+
+
+static Tcl_DString *unparse_str(char *in_str)
+{
+ Tcl_DString *str;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ if (! in_str) {
+ Tcl_DStringAppend(str, "null", -1);
+ }
+ else {
+ Tcl_DStringAppend(str, in_str, -1);
+ }
+
+ return str;
+}
+
+
+
+static int parse_str(Tcl_Interp *interp, char *in_str, char **out_str)
+{
+ if (! in_str) {
+ *out_str = 0;
+ }
+ else if (! strcasecmp(in_str, "null")) {
+ *out_str = 0;
+ }
+ else {
+ *out_str = in_str;
+ }
+ return TCL_OK;
+}
+
+
+static void set_ok(Tcl_Interp *interp, char *string)
+{
+ Tcl_SetResult(interp, "OK", TCL_STATIC);
+ Tcl_AppendElement(interp, "OVSEC_KADM_OK");
+ Tcl_AppendElement(interp, string);
+}
+
+
+
+static Tcl_DString *unparse_err(ovsec_kadm_ret_t code)
+{
+ char *code_string, *error_string;
+ Tcl_DString *dstring;
+
+ switch (code) {
+ case OVSEC_KADM_FAILURE: code_string = "OVSEC_KADM_FAILURE"; break;
+ case OVSEC_KADM_AUTH_GET: code_string = "OVSEC_KADM_AUTH_GET"; break;
+ case OVSEC_KADM_AUTH_ADD: code_string = "OVSEC_KADM_AUTH_ADD"; break;
+ case OVSEC_KADM_AUTH_MODIFY:
+ code_string = "OVSEC_KADM_AUTH_MODIFY"; break;
+ case OVSEC_KADM_AUTH_DELETE:
+ code_string = "OVSEC_KADM_AUTH_DELETE"; break;
+ case OVSEC_KADM_AUTH_INSUFFICIENT:
+ code_string = "OVSEC_KADM_AUTH_INSUFFICIENT"; break;
+ case OVSEC_KADM_BAD_DB: code_string = "OVSEC_KADM_BAD_DB"; break;
+ case OVSEC_KADM_DUP: code_string = "OVSEC_KADM_DUP"; break;
+ case OVSEC_KADM_RPC_ERROR: code_string = "OVSEC_KADM_RPC_ERROR"; break;
+ case OVSEC_KADM_NO_SRV: code_string = "OVSEC_KADM_NO_SRV"; break;
+ case OVSEC_KADM_BAD_HIST_KEY:
+ code_string = "OVSEC_KADM_BAD_HIST_KEY"; break;
+ case OVSEC_KADM_NOT_INIT: code_string = "OVSEC_KADM_NOT_INIT"; break;
+ case OVSEC_KADM_INIT: code_string = "OVSEC_KADM_INIT"; break;
+ case OVSEC_KADM_BAD_PASSWORD:
+ code_string = "OVSEC_KADM_BAD_PASSWORD"; break;
+ case OVSEC_KADM_UNK_PRINC: code_string = "OVSEC_KADM_UNK_PRINC"; break;
+ case OVSEC_KADM_UNK_POLICY: code_string = "OVSEC_KADM_UNK_POLICY"; break;
+ case OVSEC_KADM_BAD_MASK: code_string = "OVSEC_KADM_BAD_MASK"; break;
+ case OVSEC_KADM_BAD_CLASS: code_string = "OVSEC_KADM_BAD_CLASS"; break;
+ case OVSEC_KADM_BAD_LENGTH: code_string = "OVSEC_KADM_BAD_LENGTH"; break;
+ case OVSEC_KADM_BAD_POLICY: code_string = "OVSEC_KADM_BAD_POLICY"; break;
+ case OVSEC_KADM_BAD_HISTORY: code_string = "OVSEC_KADM_BAD_HISTORY"; break;
+ case OVSEC_KADM_BAD_PRINCIPAL:
+ code_string = "OVSEC_KADM_BAD_PRINCIPAL"; break;
+ case OVSEC_KADM_BAD_AUX_ATTR:
+ code_string = "OVSEC_KADM_BAD_AUX_ATTR"; break;
+ case OVSEC_KADM_PASS_Q_TOOSHORT:
+ code_string = "OVSEC_KADM_PASS_Q_TOOSHORT"; break;
+ case OVSEC_KADM_PASS_Q_CLASS:
+ code_string = "OVSEC_KADM_PASS_Q_CLASS"; break;
+ case OVSEC_KADM_PASS_Q_DICT:
+ code_string = "OVSEC_KADM_PASS_Q_DICT"; break;
+ case OVSEC_KADM_PASS_REUSE: code_string = "OVSEC_KADM_PASS_REUSE"; break;
+ case OVSEC_KADM_PASS_TOOSOON:
+ code_string = "OVSEC_KADM_PASS_TOOSOON"; break;
+ case OVSEC_KADM_POLICY_REF:
+ code_string = "OVSEC_KADM_POLICY_REF"; break;
+ case OVSEC_KADM_PROTECT_PRINCIPAL:
+ code_string = "OVSEC_KADM_PROTECT_PRINCIPAL"; break;
+ case OVSEC_KADM_BAD_SERVER_HANDLE:
+ code_string = "OVSEC_KADM_BAD_SERVER_HANDLE"; break;
+ case OVSEC_KADM_BAD_STRUCT_VERSION:
+ code_string = "OVSEC_KADM_BAD_STRUCT_VERSION"; break;
+ case OVSEC_KADM_OLD_STRUCT_VERSION:
+ code_string = "OVSEC_KADM_OLD_STRUCT_VERSION"; break;
+ case OVSEC_KADM_NEW_STRUCT_VERSION:
+ code_string = "OVSEC_KADM_NEW_STRUCT_VERSION"; break;
+ case OVSEC_KADM_BAD_API_VERSION:
+ code_string = "OVSEC_KADM_BAD_API_VERSION"; break;
+ case OVSEC_KADM_OLD_LIB_API_VERSION:
+ code_string = "OVSEC_KADM_OLD_LIB_API_VERSION"; break;
+ case OVSEC_KADM_OLD_SERVER_API_VERSION:
+ code_string = "OVSEC_KADM_OLD_SERVER_API_VERSION"; break;
+ case OVSEC_KADM_NEW_LIB_API_VERSION:
+ code_string = "OVSEC_KADM_NEW_LIB_API_VERSION"; break;
+ case OVSEC_KADM_NEW_SERVER_API_VERSION:
+ code_string = "OVSEC_KADM_NEW_SERVER_API_VERSION"; break;
+ case OVSEC_KADM_SECURE_PRINC_MISSING:
+ code_string = "OVSEC_KADM_SECURE_PRINC_MISSING"; break;
+ case KADM5_NO_RENAME_SALT:
+ code_string = "KADM5_NO_RENAME_SALT"; break;
+ case KADM5_BAD_CLIENT_PARAMS:
+ code_string = "KADM5_BAD_CLIENT_PARAMS"; break;
+ case KADM5_BAD_SERVER_PARAMS:
+ code_string = "KADM5_BAD_SERVER_PARAMS"; break;
+ case KADM5_AUTH_LIST:
+ code_string = "KADM5_AUTH_LIST"; break;
+ case KADM5_AUTH_CHANGEPW:
+ code_string = "KADM5_AUTH_CHANGEPW"; break;
+ case OSA_ADB_DUP: code_string = "OSA_ADB_DUP"; break;
+ case OSA_ADB_NOENT: code_string = "ENOENT"; break;
+ case OSA_ADB_DBINIT: code_string = "OSA_ADB_DBINIT"; break;
+ case OSA_ADB_BAD_POLICY: code_string = "Bad policy name"; break;
+ case OSA_ADB_BAD_PRINC: code_string = "Bad principal name"; break;
+ case OSA_ADB_BAD_DB: code_string = "Invalid database."; break;
+ case OSA_ADB_XDR_FAILURE: code_string = "OSA_ADB_XDR_FAILURE"; break;
+ case KRB5_KDB_INUSE: code_string = "KRB5_KDB_INUSE"; break;
+ case KRB5_KDB_UK_SERROR: code_string = "KRB5_KDB_UK_SERROR"; break;
+ case KRB5_KDB_UK_RERROR: code_string = "KRB5_KDB_UK_RERROR"; break;
+ case KRB5_KDB_UNAUTH: code_string = "KRB5_KDB_UNAUTH"; break;
+ case KRB5_KDB_NOENTRY: code_string = "KRB5_KDB_NOENTRY"; break;
+ case KRB5_KDB_ILL_WILDCARD: code_string = "KRB5_KDB_ILL_WILDCARD"; break;
+ case KRB5_KDB_DB_INUSE: code_string = "KRB5_KDB_DB_INUSE"; break;
+ case KRB5_KDB_DB_CHANGED: code_string = "KRB5_KDB_DB_CHANGED"; break;
+ case KRB5_KDB_TRUNCATED_RECORD:
+ code_string = "KRB5_KDB_TRUNCATED_RECORD"; break;
+ case KRB5_KDB_RECURSIVELOCK:
+ code_string = "KRB5_KDB_RECURSIVELOCK"; break;
+ case KRB5_KDB_NOTLOCKED: code_string = "KRB5_KDB_NOTLOCKED"; break;
+ case KRB5_KDB_BADLOCKMODE: code_string = "KRB5_KDB_BADLOCKMODE"; break;
+ case KRB5_KDB_DBNOTINITED: code_string = "KRB5_KDB_DBNOTINITED"; break;
+ case KRB5_KDB_DBINITED: code_string = "KRB5_KDB_DBINITED"; break;
+ case KRB5_KDB_ILLDIRECTION: code_string = "KRB5_KDB_ILLDIRECTION"; break;
+ case KRB5_KDB_NOMASTERKEY: code_string = "KRB5_KDB_NOMASTERKEY"; break;
+ case KRB5_KDB_BADMASTERKEY: code_string = "KRB5_KDB_BADMASTERKEY"; break;
+ case KRB5_KDB_INVALIDKEYSIZE:
+ code_string = "KRB5_KDB_INVALIDKEYSIZE"; break;
+ case KRB5_KDB_CANTREAD_STORED:
+ code_string = "KRB5_KDB_CANTREAD_STORED"; break;
+ case KRB5_KDB_BADSTORED_MKEY:
+ code_string = "KRB5_KDB_BADSTORED_MKEY"; break;
+ case KRB5_KDB_CANTLOCK_DB: code_string = "KRB5_KDB_CANTLOCK_DB"; break;
+ case KRB5_KDB_DB_CORRUPT: code_string = "KRB5_KDB_DB_CORRUPT"; break;
+ case KRB5_PARSE_ILLCHAR: code_string = "KRB5_PARSE_ILLCHAR"; break;
+ case KRB5_PARSE_MALFORMED: code_string = "KRB5_PARSE_MALFORMED"; break;
+ case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN"; break;
+ case KRB5_REALM_UNKNOWN: code_string = "KRB5_REALM_UNKNOWN"; break;
+ case KRB5_KDC_UNREACH: code_string = "KRB5_KDC_UNREACH"; break;
+ case KRB5_KDCREP_MODIFIED: code_string = "KRB5_KDCREP_MODIFIED"; break;
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY: code_string = "KRB5KRB_AP_ERR_BAD_INTEGRITY"; break;
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN"; break;
+ case EINVAL: code_string = "EINVAL"; break;
+ case ENOENT: code_string = "ENOENT"; break;
+ default: fprintf(stderr, "**** CODE %d ***\n", code); code_string = "UNKNOWN"; break;
+ }
+
+ error_string = (char *) error_message(code);
+
+ if (! (dstring = (Tcl_DString *) malloc(sizeof(Tcl_DString)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX Do we really want to exit? Ok if this is */
+ /* just a test program, but what about if it gets */
+ /* used for other things later? */
+ }
+
+ Tcl_DStringInit(dstring);
+
+ if (! (Tcl_DStringAppendElement(dstring, "ERROR") &&
+ Tcl_DStringAppendElement(dstring, code_string) &&
+ Tcl_DStringAppendElement(dstring, error_string))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ return dstring;
+}
+
+
+
+static void stash_error(Tcl_Interp *interp, krb5_error_code code)
+{
+ Tcl_DString *dstring = unparse_err(code);
+ Tcl_DStringResult(interp, dstring);
+ Tcl_DStringFree(dstring);
+ free(dstring);
+}
+
+
+
+static Tcl_DString *unparse_flags(struct flagval *array, int size,
+ krb5_int32 flags)
+{
+ int i;
+ Tcl_DString *str;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ for (i = 0; i < size; i++) {
+ if (flags & array[i].val) {
+ Tcl_DStringAppendElement(str, array[i].name);
+ }
+ }
+
+ return str;
+}
+
+
+static int parse_flags(Tcl_Interp *interp, Tcl_HashTable *table,
+ struct flagval *array, int size, char *str,
+ krb5_flags *flags)
+{
+ int tcl_ret, tmp, argc, i, retcode = TCL_OK;
+ char **argv;
+ Tcl_HashEntry *entry;
+
+ if ((tcl_ret = Tcl_GetInt(interp, str, &tmp)) == TCL_OK) {
+ *flags = tmp;
+ return TCL_OK;
+ }
+ Tcl_ResetResult(interp);
+
+ if ((tcl_ret = Tcl_SplitList(interp, str, &argc, &argv)) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (! table) {
+ table = create_flag_table(array, size);
+ }
+
+ *flags = 0;
+
+ for (i = 0; i < argc; i++) {
+ if (! (entry = Tcl_FindHashEntry(table, argv[i]))) {
+ Tcl_AppendResult(interp, "unknown krb5 flag ", argv[i], 0);
+ retcode = TCL_ERROR;
+ break;
+ }
+ *flags |= *(krb5_flags *) Tcl_GetHashValue(entry);
+ }
+
+ free(argv);
+ return(retcode);
+}
+
+static Tcl_DString *unparse_privs(krb5_flags flags)
+{
+ return unparse_flags(priv_flags, sizeof(priv_flags) /
+ sizeof(struct flagval), flags);
+}
+
+
+static Tcl_DString *unparse_krb5_flags(krb5_flags flags)
+{
+ return unparse_flags(krb5_flags_array, sizeof(krb5_flags_array) /
+ sizeof(struct flagval), flags);
+}
+
+static int parse_krb5_flags(Tcl_Interp *interp, char *str, krb5_flags *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, krb5_flags_array,
+ sizeof(krb5_flags_array) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+static Tcl_DString *unparse_aux_attributes(krb5_int32 flags)
+{
+ return unparse_flags(aux_attributes, sizeof(aux_attributes) /
+ sizeof(struct flagval), flags);
+}
+
+
+static int parse_aux_attributes(Tcl_Interp *interp, char *str, long *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, aux_attributes,
+ sizeof(aux_attributes) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+static int parse_principal_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, principal_mask_flags,
+ sizeof(principal_mask_flags) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+
+static int parse_policy_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+ krb5_flags tmp;
+ static Tcl_HashTable *table = 0;
+ int tcl_ret;
+
+ if ((tcl_ret = parse_flags(interp, table, policy_mask_flags,
+ sizeof(policy_mask_flags) /
+ sizeof(struct flagval),
+ str, &tmp)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ *flags = tmp;
+ return TCL_OK;
+}
+
+
+static Tcl_DString *unparse_principal_ent(ovsec_kadm_principal_ent_t princ)
+{
+ Tcl_DString *str, *tmp_dstring;
+ char *tmp;
+ char buf[20];
+ krb5_error_code krb5_ret;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ tmp = 0; /* It looks to me from looking at the library source */
+ /* code for krb5_parse_name that the pointer passed into */
+ /* it should be initialized to 0 if I want it do be */
+ /* allocated automatically. */
+ if (krb5_ret = krb5_unparse_name(context, princ->principal, &tmp)) {
+ /* XXX Do we want to return an error? Not sure. */
+ Tcl_DStringAppendElement(str, "[unparseable principal]");
+ }
+ else {
+ Tcl_DStringAppendElement(str, tmp);
+ free(tmp);
+ }
+
+ sprintf(buf, "%d", princ->princ_expire_time);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->last_pwd_change);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->pw_expiration);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ tmp = 0;
+ if (krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp)) {
+ /* XXX */
+ Tcl_DStringAppendElement(str, "[unparseable principal]");
+ }
+ else {
+ Tcl_DStringAppendElement(str, tmp);
+ free(tmp);
+ }
+
+ sprintf(buf, "%d", princ->mod_date);
+ Tcl_DStringAppendElement(str, buf);
+
+ tmp_dstring = unparse_krb5_flags(princ->attributes);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ sprintf(buf, "%d", princ->kvno);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", princ->mkvno);
+ Tcl_DStringAppendElement(str, buf);
+
+ /* XXX This may be dangerous, because the contents of the policy */
+ /* field are undefined if the POLICY bit isn't set. However, I */
+ /* think it's a bug for the field not to be null in that case */
+ /* anyway, so we should assume that it will be null so that we'll */
+ /* catch it if it isn't. */
+
+ tmp_dstring = unparse_str(princ->policy);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ tmp_dstring = unparse_aux_attributes(princ->aux_attributes);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ return str;
+}
+
+
+
+static int parse_principal_ent(Tcl_Interp *interp, char *list,
+ ovsec_kadm_principal_ent_t *out_princ)
+{
+ ovsec_kadm_principal_ent_t princ;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ int argc;
+ char **argv;
+ int tmp;
+ int retcode = TCL_OK;
+
+ if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (argc != 12) {
+ sprintf(interp->result, "wrong # args in principal structure (%d should be 12)",
+ argc);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if (! (princ = malloc(sizeof *princ))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ if ((krb5_ret = krb5_parse_name(context, argv[0], &princ->principal)) != 0) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ /*
+ * All of the numerical values parsed here are parsed into an
+ * "int" and then assigned into the structure in case the actual
+ * width of the field in the Kerberos structure is different from
+ * the width of an integer.
+ */
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing princ_expire_time");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->princ_expire_time = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing last_pwd_change");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->last_pwd_change = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_expiration");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->pw_expiration = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing max_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->max_life = tmp;
+
+ if ((krb5_ret = krb5_parse_name(context, argv[5], &princ->mod_name)) != 0) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing mod_name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mod_date");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->mod_date = tmp;
+
+ if ((tcl_ret = parse_krb5_flags(interp, argv[7], &princ->attributes))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing attributes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[8], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing kvno");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->kvno = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[9], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing mkvno");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ princ->mkvno = tmp;
+
+ if ((tcl_ret = parse_str(interp, argv[10], &princ->policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if(princ->policy != NULL) {
+ if(!(princ->policy = strdup(princ->policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1);
+ }
+ }
+
+ if ((tcl_ret = parse_aux_attributes(interp, argv[11],
+ &princ->aux_attributes)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing aux_attributes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+finished:
+ free(argv);
+ *out_princ = princ;
+ return retcode;
+}
+
+
+static void free_principal_ent(ovsec_kadm_principal_ent_t *princ)
+{
+ krb5_free_principal(context, (*princ)->principal);
+ krb5_free_principal(context, (*princ)->mod_name);
+ free(*princ);
+ *princ = 0;
+}
+
+static Tcl_DString *unparse_policy_ent(ovsec_kadm_policy_ent_t policy)
+{
+ Tcl_DString *str, *tmp_dstring;
+ char buf[20];
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ tmp_dstring = unparse_str(policy->policy);
+ Tcl_DStringAppendElement(str, tmp_dstring->string);
+ Tcl_DStringFree(tmp_dstring);
+ free(tmp_dstring);
+
+ sprintf(buf, "%d", policy->pw_min_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_max_life);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_length);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_min_classes);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_history_num);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->policy_refcnt);
+ Tcl_DStringAppendElement(str, buf);
+
+ return str;
+}
+
+
+
+static int parse_policy_ent(Tcl_Interp *interp, char *list,
+ ovsec_kadm_policy_ent_t *out_policy)
+{
+ ovsec_kadm_policy_ent_t policy;
+ int tcl_ret;
+ int argc;
+ char **argv;
+ int tmp;
+ int retcode = TCL_OK;
+
+ if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (argc != 7) {
+ sprintf(interp->result, "wrong # args in policy structure (%d should be 7)",
+ argc);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if (! (policy = malloc(sizeof *policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy->policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if(policy->policy != NULL) {
+ if (! (policy->policy = strdup(policy->policy))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ }
+
+ /*
+ * All of the numerical values parsed here are parsed into an
+ * "int" and then assigned into the structure in case the actual
+ * width of the field in the Kerberos structure is different from
+ * the width of an integer.
+ */
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_life = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_max_life");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_max_life = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_length");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_length = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_min_classes");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_min_classes = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[5], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_history_num");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_history_num = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy_refcnt");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->policy_refcnt = tmp;
+
+finished:
+ free(argv);
+ *out_policy = policy;
+ return retcode;
+}
+
+
+static void free_policy_ent(ovsec_kadm_policy_ent_t *policy)
+{
+ free(*policy);
+ *policy = 0;
+}
+
+static Tcl_DString *unparse_keytype(krb5_enctype enctype)
+{
+ Tcl_DString *str;
+ char buf[50];
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ switch (enctype) {
+ /* XXX is this right? */
+ case ENCTYPE_NULL: Tcl_DStringAppend(str, "ENCTYPE_NULL", -1); break;
+ case ENCTYPE_DES_CBC_CRC:
+ Tcl_DStringAppend(str, "ENCTYPE_DES_CBC_CRC", -1); break;
+ default:
+ sprintf(buf, "UNKNOWN KEYTYPE (0x%x)", enctype);
+ Tcl_DStringAppend(str, buf, -1);
+ break;
+ }
+
+ return str;
+}
+
+
+static Tcl_DString *unparse_keyblock(krb5_keyblock *keyblock)
+{
+ Tcl_DString *str;
+ Tcl_DString *keytype;
+ int i;
+
+ if (! (str = malloc(sizeof(*str)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+
+ Tcl_DStringInit(str);
+
+ keytype = unparse_keytype(keyblock->enctype);
+ Tcl_DStringAppendElement(str, keytype->string);
+ Tcl_DStringFree(keytype);
+ free(keytype);
+ if (keyblock->length == 0) {
+ Tcl_DStringAppendElement(str, "0x00");
+ }
+ else {
+ Tcl_DStringAppendElement(str, "0x");
+ for (i = 0; i < keyblock->length; i++) {
+ char buf[3];
+ sprintf(buf, "%02x", (int) keyblock->contents[i]);
+ Tcl_DStringAppend(str, buf, -1);
+ }
+ }
+
+ return str;
+}
+
+
+
+int tcl_ovsec_kadm_init(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ ovsec_kadm_ret_t ret;
+ char *client_name, *pass, *service_name, *realm;
+ int tcl_ret;
+ krb5_ui_4 struct_version, api_version;
+ char *handle_var;
+ void *server_handle;
+ char *handle_name;
+ char *whoami = argv[0];
+
+ argv++, argc--;
+
+ krb5_init_context(&context);
+
+ if (argc != 7) {
+ Tcl_AppendResult(interp, whoami, ": ", arg_error, 0);
+ return TCL_ERROR;
+ }
+
+ if (((tcl_ret = parse_str(interp, argv[0], &client_name)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[1], &pass)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[2], &service_name)) != TCL_OK) ||
+ ((tcl_ret = parse_str(interp, argv[3], &realm)) != TCL_OK) ||
+ ((tcl_ret = Tcl_GetInt(interp, argv[4], (int *) &struct_version)) !=
+ TCL_OK) ||
+ ((tcl_ret = Tcl_GetInt(interp, argv[5], (int *) &api_version)) !=
+ TCL_OK)) {
+ return tcl_ret;
+ }
+
+ handle_var = argv[6];
+
+ if (! (handle_var && *handle_var)) {
+ Tcl_SetResult(interp, "must specify server handle variable name",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ ret = ovsec_kadm_init(client_name, pass, service_name, realm,
+ struct_version, api_version, &server_handle);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = put_server_handle(interp, server_handle, &handle_name))
+ != TCL_OK) {
+ return tcl_ret;
+ }
+
+ if (! Tcl_SetVar(interp, handle_var, handle_name, TCL_LEAVE_ERR_MSG)) {
+ return TCL_ERROR;
+ }
+
+ set_ok(interp, "OV Admin system initialized.");
+ return TCL_OK;
+}
+
+
+
+int tcl_ovsec_kadm_destroy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ ovsec_kadm_ret_t ret;
+ int tcl_ret;
+
+ GET_HANDLE(0, 0);
+
+ ret = ovsec_kadm_destroy(server_handle);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = remove_server_handle(interp, argv[-1])) != TCL_OK) {
+ return tcl_ret;
+ }
+
+ set_ok(interp, "OV Admin system deinitialized.");
+ return TCL_OK;
+}
+
+int tcl_ovsec_kadm_create_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+ char *princ_string;
+ ovsec_kadm_principal_ent_t princ = 0;
+ krb5_int32 mask;
+ char *pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+
+ GET_HANDLE(3, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing principal");
+ return tcl_ret;
+ }
+
+ if (princ_string &&
+ ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[2], &pw)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[3], &override_qual)) !=
+ TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+#endif
+
+#ifdef OVERRIDE
+ ret = ovsec_kadm_create_principal(server_handle, princ, mask, pw,
+ override_qual);
+#else
+ ret = ovsec_kadm_create_principal(server_handle, princ, mask, pw);
+#endif
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ else {
+ set_ok(interp, "Principal created.");
+ }
+
+finished:
+ if (princ) {
+ free_principal_ent(&princ);
+ }
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_delete_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ ovsec_kadm_ret_t ret;
+ int tcl_ret;
+ char *name;
+
+ GET_HANDLE(1, 0);
+
+ if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+ return tcl_ret;
+ if(name != NULL) {
+ if (krb5_ret = krb5_parse_name(context, name, &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal");
+ return TCL_ERROR;
+ }
+ } else princ = NULL;
+ ret = ovsec_kadm_delete_principal(server_handle, princ);
+
+ if(princ != NULL)
+ krb5_free_principal(context, princ);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Principal deleted.");
+ return TCL_OK;
+ }
+}
+
+
+
+int tcl_ovsec_kadm_modify_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *princ_string;
+ ovsec_kadm_principal_ent_t princ = 0;
+ int tcl_ret;
+ krb5_int32 mask;
+ int retcode = TCL_OK;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing principal");
+ return tcl_ret;
+ }
+
+ if (princ_string &&
+ ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_modify_principal(server_handle, princ, mask);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Principal modified.");
+ }
+
+finished:
+ if (princ) {
+ free_principal_ent(&princ);
+ }
+ return retcode;
+}
+
+
+int tcl_ovsec_kadm_rename_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal source, target;
+ krb5_error_code krb5_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &source)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing source");
+ return TCL_ERROR;
+ }
+
+ if (krb5_ret = krb5_parse_name(context, argv[1], &target)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing target");
+ krb5_free_principal(context, source);
+ return TCL_ERROR;
+ }
+
+ ret = ovsec_kadm_rename_principal(server_handle, source, target);
+
+ if (ret == OVSEC_KADM_OK) {
+ set_ok(interp, "Principal renamed.");
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+ krb5_free_principal(context, source);
+ krb5_free_principal(context, target);
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_chpass_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ char *pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ int retcode = TCL_OK;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_chpass_principal(server_handle,
+ princ, pw, override_qual);
+#else
+ ret = ovsec_kadm_chpass_principal(server_handle, princ, pw);
+#endif
+
+ if (ret == OVSEC_KADM_OK) {
+ set_ok(interp, "Password changed.");
+ goto finished;
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_chpass_principal_util(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ char *new_pw;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+ char *pw_ret, *pw_ret_var;
+ char msg_ret[1024], *msg_ret_var;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(4, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &new_pw)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing new password");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#endif
+ if ((tcl_ret = parse_str(interp, argv[3], &pw_ret_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_ret variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[4], &msg_ret_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing msg_ret variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_chpass_principal_util(server_handle, princ, new_pw,
+#ifdef OVERRIDE
+ override_qual,
+#endif
+ pw_ret_var ? &pw_ret : 0,
+ msg_ret_var ? msg_ret : 0);
+
+ if (ret == OVSEC_KADM_OK) {
+ if (pw_ret_var &&
+ (! Tcl_SetVar(interp, pw_ret_var, pw_ret,
+ TCL_LEAVE_ERR_MSG))) {
+ Tcl_AppendElement(interp, "while setting pw_ret variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ if (msg_ret_var &&
+ (! Tcl_SetVar(interp, msg_ret_var, msg_ret,
+ TCL_LEAVE_ERR_MSG))) {
+ Tcl_AppendElement(interp,
+ "while setting msg_ret variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Password changed.");
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_randkey_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_keyblock *keyblock;
+ char *keyblock_var;
+ Tcl_DString *keyblock_dstring = 0;
+#ifdef OVERRIDE
+ int override_qual;
+#endif
+ krb5_error_code krb5_ret;
+ ovsec_kadm_ret_t ret;
+ int tcl_ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 0);
+
+ if (krb5_ret = krb5_parse_name(context, argv[0], &princ)) {
+ stash_error(interp, krb5_ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &keyblock_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing keyblock variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+#ifdef OVERRIDE
+ if ((tcl_ret = Tcl_GetBoolean(interp, argv[2], &override_qual))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing override_qual");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_randkey_principal(server_handle,
+ princ, keyblock_var ? &keyblock : 0,
+ override_qual);
+#else
+ ret = ovsec_kadm_randkey_principal(server_handle,
+ princ, keyblock_var ? &keyblock : 0);
+#endif
+
+ if (ret == OVSEC_KADM_OK) {
+ if (keyblock_var) {
+ keyblock_dstring = unparse_keyblock(keyblock);
+ if (! Tcl_SetVar(interp, keyblock_var,
+ keyblock_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting keyblock variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ }
+ set_ok(interp, "Key randomized.");
+
+ }
+ else {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ krb5_free_principal(context, princ);
+ if (keyblock_dstring) {
+ Tcl_DStringFree(keyblock_dstring);
+ free(keyblock_dstring);
+ }
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_get_principal(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ ovsec_kadm_principal_ent_t ent;
+ Tcl_DString *ent_dstring = 0;
+ char *ent_var;
+ char *name;
+ krb5_error_code krb5_ret;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 1);
+
+ if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+ return tcl_ret;
+ if(name != NULL) {
+ if (krb5_ret = krb5_parse_name(context, name, &princ)) {
+ stash_error(interp, ret);
+ Tcl_AppendElement(interp, "while parsing principal name");
+ return TCL_ERROR;
+ }
+ } else princ = NULL;
+
+ if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry variable name");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_get_principal(server_handle, princ, ent_var ? &ent : 0);
+
+ if (ret == OVSEC_KADM_OK) {
+ if (ent_var) {
+ if (dostruct) {
+ char buf[20];
+ int i = 1, newPtr = 0;
+ Tcl_HashEntry *entry;
+
+ if (! struct_table) {
+ if (! (struct_table =
+ malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ do {
+ sprintf(buf, "principal%d", i);
+ entry = Tcl_CreateHashEntry(struct_table, buf,
+ &newPtr);
+ i++;
+ } while (! newPtr);
+
+ Tcl_SetHashValue(entry, ent);
+ if (! Tcl_SetVar(interp, ent_var, buf,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ Tcl_DeleteHashEntry(entry);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Principal structure retrieved.");
+ }
+ else {
+ ent_dstring = unparse_principal_ent(ent);
+ if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Principal retrieved.");
+ }
+ }
+ }
+ else {
+ ent = 0;
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ if (ent_dstring) {
+ Tcl_DStringFree(ent_dstring);
+ free(ent_dstring);
+ }
+ if(princ != NULL)
+ krb5_free_principal(context, princ);
+ if (ent && ((! dostruct) || (retcode != TCL_OK))) {
+ if ((ret = ovsec_kadm_free_principal_ent(server_handle, ent)) &&
+ (retcode == TCL_OK)) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ }
+ return retcode;
+}
+
+int tcl_ovsec_kadm_create_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+ char *policy_string;
+ ovsec_kadm_policy_ent_t policy = 0;
+ krb5_int32 mask;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ return tcl_ret;
+ }
+
+ if (policy_string &&
+ ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = tcl_ret;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_create_policy(server_handle, policy, mask);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ else {
+ set_ok(interp, "Policy created.");
+ }
+
+finished:
+ if (policy) {
+ free_policy_ent(&policy);
+ }
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_delete_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ krb5_principal princ;
+ krb5_error_code krb5_ret;
+ ovsec_kadm_ret_t ret;
+ char *policy;
+ int tcl_ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ ret = ovsec_kadm_delete_policy(server_handle, policy);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Policy deleted.");
+ return TCL_OK;
+ }
+}
+
+
+
+int tcl_ovsec_kadm_modify_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *policy_string;
+ ovsec_kadm_policy_ent_t policy = 0;
+ int tcl_ret;
+ krb5_int32 mask;
+ int retcode = TCL_OK;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(2, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy");
+ return tcl_ret;
+ }
+
+ if (policy_string &&
+ ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+ != TCL_OK)) {
+ return tcl_ret;
+ }
+
+ if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+
+ ret = ovsec_kadm_modify_policy(server_handle, policy, mask);
+
+ if (ret != OVSEC_KADM_OK) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ else {
+ set_ok(interp, "Policy modified.");
+ }
+
+finished:
+ if (policy) {
+ free_policy_ent(&policy);
+ }
+ return retcode;
+}
+
+
+int tcl_ovsec_kadm_get_policy(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ ovsec_kadm_policy_ent_t ent;
+ Tcl_DString *ent_dstring = 0;
+ char *policy;
+ char *ent_var;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+ int retcode = TCL_OK;
+
+ GET_HANDLE(2, 1);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &policy)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing policy name");
+ return TCL_ERROR;
+ }
+
+ if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry variable name");
+ return TCL_ERROR;
+ }
+
+ ret = ovsec_kadm_get_policy(server_handle, policy, ent_var ? &ent : 0);
+
+ if (ret == OVSEC_KADM_OK) {
+ if (ent_var) {
+ if (dostruct) {
+ char buf[20];
+ int i = 1, newPtr = 0;
+ Tcl_HashEntry *entry;
+
+ if (! struct_table) {
+ if (! (struct_table =
+ malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ do {
+ sprintf(buf, "policy%d", i);
+ entry = Tcl_CreateHashEntry(struct_table, buf,
+ &newPtr);
+ i++;
+ } while (! newPtr);
+
+ Tcl_SetHashValue(entry, ent);
+ if (! Tcl_SetVar(interp, ent_var, buf,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ Tcl_DeleteHashEntry(entry);
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Policy structure retrieved.");
+ }
+ else {
+ ent_dstring = unparse_policy_ent(ent);
+ if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+ TCL_LEAVE_ERR_MSG)) {
+ Tcl_AppendElement(interp,
+ "while setting entry variable");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ set_ok(interp, "Policy retrieved.");
+ }
+ }
+ }
+ else {
+ ent = 0;
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+
+finished:
+ if (ent_dstring) {
+ Tcl_DStringFree(ent_dstring);
+ free(ent_dstring);
+ }
+ if (ent && ((! dostruct) || (retcode != TCL_OK))) {
+ if ((ret = ovsec_kadm_free_policy_ent(server_handle, ent)) &&
+ (retcode == TCL_OK)) {
+ stash_error(interp, ret);
+ retcode = TCL_ERROR;
+ }
+ }
+ return retcode;
+}
+
+
+
+int tcl_ovsec_kadm_free_principal_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ ovsec_kadm_principal_ent_t ent;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &ent_name)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry name");
+ return TCL_ERROR;
+ }
+
+ if ((! ent_name) &&
+ (ret = ovsec_kadm_free_principal_ent(server_handle, 0))) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ Tcl_HashEntry *entry;
+
+ if (strncmp(ent_name, "principal", sizeof("principal")-1)) {
+ Tcl_AppendResult(interp, "invalid principal handle \"",
+ ent_name, "\"", 0);
+ return TCL_ERROR;
+ }
+ if (! struct_table) {
+ if (! (struct_table = malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+ Tcl_AppendResult(interp, "principal handle \"", ent_name,
+ "\" not found", 0);
+ return TCL_ERROR;
+ }
+
+ ent = Tcl_GetHashValue(entry);
+
+ if (ret = ovsec_kadm_free_principal_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Principal freed.");
+ return TCL_OK;
+}
+
+
+int tcl_ovsec_kadm_free_policy_ent(ClientData clientData,
+ Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ char *ent_name;
+ ovsec_kadm_policy_ent_t ent;
+ int tcl_ret;
+ ovsec_kadm_ret_t ret;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &ent_name)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing entry name");
+ return TCL_ERROR;
+ }
+
+ if ((! ent_name) &&
+ (ret = ovsec_kadm_free_policy_ent(server_handle, 0))) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ else {
+ Tcl_HashEntry *entry;
+
+ if (strncmp(ent_name, "policy", sizeof("policy")-1)) {
+ Tcl_AppendResult(interp, "invalid principal handle \"",
+ ent_name, "\"", 0);
+ return TCL_ERROR;
+ }
+ if (! struct_table) {
+ if (! (struct_table = malloc(sizeof(*struct_table)))) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(1); /* XXX */
+ }
+ Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+ }
+
+ if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+ Tcl_AppendResult(interp, "policy handle \"", ent_name,
+ "\" not found", 0);
+ return TCL_ERROR;
+ }
+
+ ent = Tcl_GetHashValue(entry);
+
+ if (ret = ovsec_kadm_free_policy_ent(server_handle, ent)) {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+ Tcl_DeleteHashEntry(entry);
+ }
+ set_ok(interp, "Policy freed.");
+ return TCL_OK;
+}
+
+
+int tcl_ovsec_kadm_get_privs(ClientData clientData, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ int tcl_ret;
+ char *set_ret;
+ ovsec_kadm_ret_t ret;
+ char *priv_var;
+ long privs;
+
+ GET_HANDLE(1, 0);
+
+ if ((tcl_ret = parse_str(interp, argv[0], &priv_var)) != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing privs variable name");
+ return TCL_ERROR;
+ }
+
+ ret = ovsec_kadm_get_privs(server_handle, priv_var ? &privs : 0);
+
+ if (ret == OVSEC_KADM_OK) {
+ if (priv_var) {
+ Tcl_DString *str = unparse_privs(privs);
+ set_ret = Tcl_SetVar(interp, priv_var, str->string,
+ TCL_LEAVE_ERR_MSG);
+ Tcl_DStringFree(str);
+ free(str);
+ if (! set_ret) {
+ Tcl_AppendElement(interp, "while setting priv variable");
+ return TCL_ERROR;
+ }
+ }
+ set_ok(interp, "Privileges retrieved.");
+ return TCL_OK;
+ }
+ else {
+ stash_error(interp, ret);
+ return TCL_ERROR;
+ }
+}
+
+
+void Tcl_ovsec_kadm_init(Tcl_Interp *interp)
+{
+ char buf[20];
+
+ Tcl_SetVar(interp, "OVSEC_KADM_ADMIN_SERVICE",
+ OVSEC_KADM_ADMIN_SERVICE, TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp, "OVSEC_KADM_CHANGEPW_SERVICE",
+ OVSEC_KADM_CHANGEPW_SERVICE, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", OVSEC_KADM_STRUCT_VERSION);
+ Tcl_SetVar(interp, "OVSEC_KADM_STRUCT_VERSION", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", OVSEC_KADM_API_VERSION_1);
+ Tcl_SetVar(interp, "OVSEC_KADM_API_VERSION_1", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", OVSEC_KADM_API_VERSION_MASK);
+ Tcl_SetVar(interp, "OVSEC_KADM_API_VERSION_MASK", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", OVSEC_KADM_STRUCT_VERSION_MASK);
+ Tcl_SetVar(interp, "OVSEC_KADM_STRUCT_VERSION_MASK", buf,
+ TCL_GLOBAL_ONLY);
+
+ Tcl_CreateCommand(interp, "ovsec_kadm_init", tcl_ovsec_kadm_init, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_destroy", tcl_ovsec_kadm_destroy, 0,
+ 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_create_principal",
+ tcl_ovsec_kadm_create_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_delete_principal",
+ tcl_ovsec_kadm_delete_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_modify_principal",
+ tcl_ovsec_kadm_modify_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_rename_principal",
+ tcl_ovsec_kadm_rename_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_chpass_principal",
+ tcl_ovsec_kadm_chpass_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_chpass_principal_util",
+ tcl_ovsec_kadm_chpass_principal_util, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_randkey_principal",
+ tcl_ovsec_kadm_randkey_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_get_principal",
+ tcl_ovsec_kadm_get_principal, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_create_policy",
+ tcl_ovsec_kadm_create_policy, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_delete_policy",
+ tcl_ovsec_kadm_delete_policy, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_modify_policy",
+ tcl_ovsec_kadm_modify_policy, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_get_policy",
+ tcl_ovsec_kadm_get_policy, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_free_principal_ent",
+ tcl_ovsec_kadm_free_principal_ent, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_free_policy_ent",
+ tcl_ovsec_kadm_free_policy_ent, 0, 0);
+ Tcl_CreateCommand(interp, "ovsec_kadm_get_privs",
+ tcl_ovsec_kadm_get_privs, 0, 0);
+}
diff --git a/src/kadmin/testing/util/tcl_ovsec_kadm_syntax b/src/kadmin/testing/util/tcl_ovsec_kadm_syntax
new file mode 100644
index 000000000..3fc77fbcb
--- /dev/null
+++ b/src/kadmin/testing/util/tcl_ovsec_kadm_syntax
@@ -0,0 +1,57 @@
+Here's a brief summary of the syntax of the tcl versions of the
+ovsec_kadm commands:
+
+string Can be a string or "null" which will turn into a null pointer
+principal_ent A 12-field list in the order of the principal_ent
+ structure: {string number number number number string
+ number mask number number string mask}
+ It can also be "null", like a string, to indicate that
+ a null structure pointer should be used.
+mask Either a number, representing the actual value of the
+ mask, or a sequence of symbols in a list. Example:
+ {PRINCIPAL ATTRIBUTES} is a valid principal mask.
+boolean "1", "0", "true", "false", etc.
+varname The name of a Tcl variable, or "null" to not assign.
+policy_ent Similar to principal_ent, but with seven fields,
+ instead of 12. The first is a string, and the rest
+ are numbers.
+
+init
+ client_name:string pass:string service_name:string
+ realm:string struct_version:int api_version:int
+ server_handle_ret:varname
+destroy
+ server_handle:string
+create_principal
+ server_handle:string principal:principal_ent
+ mask:principal_mask password:string
+delete_principal
+ server_handle:string name:string
+modify_principal
+ server_handle:string principal_principal_ent
+ mask:principal_mask
+rename_principal
+ server_handle:string source:string target:string
+chpass_principal
+ server_handle:string name:string password:string
+chpass_principal_util
+ server_handle:string name:string password:string
+ pw_ret:varname msg_ret:varname
+randkey_principal
+ server_handle:string name:string keyblock_var:varname
+get_principal [-struct]
+ server_handle:string name:string princ_var:varname
+create_policy
+ server_handle:string policy:policy_ent mask:policy_mask
+delete_policy
+ server_handle:string name:string
+modify_policy
+ server_handle:string policy:policy_ent mask:policy_mask
+get_policy [-struct]
+ server_handle:string name:string policy_var:varname
+free_principal_ent
+ server_handle:string handle:string
+free_policy_ent
+ server_handle:string handle:string
+get_privs
+ server_handle:string privs:priv_var
diff --git a/src/kadmin/testing/util/test.c b/src/kadmin/testing/util/test.c
new file mode 100644
index 000000000..75a0fc25f
--- /dev/null
+++ b/src/kadmin/testing/util/test.c
@@ -0,0 +1,32 @@
+#include <tcl.h>
+
+#define IS_TCL_7_5 ((TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705)
+
+#if IS_TCL_7_5
+int
+main(argc, argv)
+ int argc; /* Number of command-line arguments. */
+ char **argv; /* Values of command-line arguments. */
+{
+ Tcl_Main(argc, argv, Tcl_AppInit);
+ return 0; /* Needed only to prevent compiler warning. */
+}
+#else
+/*
+ * The following variable is a special hack that allows applications
+ * to be linked using the procedure "main" from the Tcl library. The
+ * variable generates a reference to "main", which causes main to
+ * be brought in from the library (and all of Tcl with it).
+ */
+
+extern int main();
+int *tclDummyMainPtr = (int *) main;
+#endif
+
+int Tcl_AppInit(Tcl_Interp *interp)
+{
+ Tcl_ovsec_kadm_init(interp);
+ Tcl_kadm5_init(interp);
+
+ return(TCL_OK);
+}