summaryrefslogtreecommitdiffstats
path: root/src/kadmin/export
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/export')
-rw-r--r--src/kadmin/export/ChangeLog19
-rw-r--r--src/kadmin/export/Makefile.in20
-rw-r--r--src/kadmin/export/Makefile.ov24
-rw-r--r--src/kadmin/export/configure.in12
-rw-r--r--src/kadmin/export/export.c242
-rw-r--r--src/kadmin/export/export_err.et19
-rw-r--r--src/kadmin/export/local.h15
-rw-r--r--src/kadmin/export/ovsec_adm_export.c159
-rw-r--r--src/kadmin/export/unit-test/ChangeLog5
-rw-r--r--src/kadmin/export/unit-test/Makefile.ov19
-rw-r--r--src/kadmin/export/unit-test/add-to-db.sh55
-rw-r--r--src/kadmin/export/unit-test/config/unix.exp36
-rw-r--r--src/kadmin/export/unit-test/dotest.sh75
-rw-r--r--src/kadmin/export/unit-test/export.0/dotest.exp29
-rw-r--r--src/kadmin/export/unit-test/export.0/output.exp43
-rw-r--r--src/kadmin/export/unit-test/export.0/usage.exp25
-rw-r--r--src/kadmin/export/unit-test/helpers.exp126
17 files changed, 923 insertions, 0 deletions
diff --git a/src/kadmin/export/ChangeLog b/src/kadmin/export/ChangeLog
new file mode 100644
index 0000000000..97a8078c42
--- /dev/null
+++ b/src/kadmin/export/ChangeLog
@@ -0,0 +1,19 @@
+Thu Jul 18 20:39:32 1996 Marc Horowitz <marc@mit.edu>
+
+ * configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Mon Jul 15 16:51:51 1996 Marc Horowitz <marc@mit.edu>
+
+ * export.c (print_princ): return should return a value.
+
+ * configure.in (USE_GSSAPI_LIBRARY): shared libraries require all
+ symbols to be resolved, so this needs to be here.
+
+Wed Jul 10 01:26:18 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in, configure.in: added autoconf support
+
+Tue Jul 9 16:45:52 1996 Marc Horowitz <marc@mit.edu>
+
+ * export.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
+
diff --git a/src/kadmin/export/Makefile.in b/src/kadmin/export/Makefile.in
new file mode 100644
index 0000000000..5fa282d89e
--- /dev/null
+++ b/src/kadmin/export/Makefile.in
@@ -0,0 +1,20 @@
+CFLAGS = $(CCOPTS) $(DEFS) -I. $(LOCALINCLUDE)
+
+PROG = kadm5_export
+OBJS = ovsec_adm_export.o export.o export_err.o
+
+all:: $(PROG)
+
+export_err.c export_err.h: $(srcdir)/export_err.et
+
+export.o: export_err.h
+ovsec_adm_export.o: export_err.h
+
+$(PROG): $(OBJS) $(DEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) $(PROG) $(OBJS)
diff --git a/src/kadmin/export/Makefile.ov b/src/kadmin/export/Makefile.ov
new file mode 100644
index 0000000000..83e8c7219d
--- /dev/null
+++ b/src/kadmin/export/Makefile.ov
@@ -0,0 +1,24 @@
+TOP = ..
+include $(TOP)/config.mk/template
+# CFLAGS := $(CFLAGS) -Wall
+
+# The next line *shouldn't* work, because the : should be a ::.
+# However, it does work, and if I change it to :: gmake does really
+# weird things.
+ovsec_adm_export: export_err.h
+
+depend:: export_err.h
+
+PROG := kadm5_export
+OBJS := ovsec_adm_export.o export.o export_err.o
+SRCS := ovsec_adm_export.c export.c export_err.et
+ETABLES := export_err.et
+
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBKDB5) $(LIBKRB5_ALL) $(LIBDYN) $(LIBDB)
+
+expand ErrorTables
+expand InstallAdmin
+expand Depend
+
+SUBDIRS = unit-test
+expand SubdirTarget
diff --git a/src/kadmin/export/configure.in b/src/kadmin/export/configure.in
new file mode 100644
index 0000000000..992d591a11
--- /dev/null
+++ b/src/kadmin/export/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(ovsec_adm_export.c)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_AWK
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+KRB5_LIBRARIES
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/export/export.c b/src/kadmin/export/export.c
new file mode 100644
index 0000000000..3d41c4d9d7
--- /dev/null
+++ b/src/kadmin/export/export.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+
+#include <kadm5/adb.h>
+#include "export_err.h"
+#include "local.h"
+
+extern int errno;
+
+void print_key_data(FILE *f, krb5_key_data *key_data)
+{
+ int c;
+
+ fprintf(f, "%d\t%d\t", key_data->key_data_type[0],
+ key_data->key_data_length[0]);
+ for(c = 0; c < key_data->key_data_length[0]; c++)
+ fprintf(f, "%02x ",
+ key_data->key_data_contents[0][c]);
+}
+
+/*
+ * Function: print_princ
+ *
+ * Purpose: output osa_adb_princ_ent data in a human
+ * readable format (which is a format suitable for
+ * ovsec_adm_import consumption)
+ *
+ * Arguments:
+ * data (input) pointer to a structure containing a FILE *
+ * and a record counter.
+ * entry (input) entry to get dumped.
+ * <return value> void
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * writes data to the specified file pointerp.
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+krb5_error_code print_princ(krb5_pointer data, krb5_db_entry *kdb)
+{
+ char *princstr;
+ int x, y, foundcrc, ret;
+ struct retdata *d;
+ krb5_tl_data tl_data;
+ osa_princ_ent_rec adb;
+ XDR xdrs;
+
+ d = (struct retdata *) data;
+
+ /*
+ * XXX Currently, lookup_tl_data always returns zero; it sets
+ * tl_data->tl_data_length to zero if the type isn't found.
+ * This should be fixed...
+ */
+ /*
+ * XXX Should this function do nothing for a principal with no
+ * admin data, or print a record of "default" values? See
+ * comment in server_kdb.c to help decide.
+ */
+ tl_data.tl_data_type = KRB5_TL_KADM_DATA;
+ if ((ret = krb5_dbe_lookup_tl_data(d->context, kdb, &tl_data))
+ || (tl_data.tl_data_length == 0))
+ return(0);
+
+ memset(&adb, 0, sizeof(adb));
+ xdrmem_create(&xdrs, tl_data.tl_data_contents,
+ tl_data.tl_data_length, XDR_DECODE);
+ if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) {
+ xdr_destroy(&xdrs);
+ return(OSA_ADB_XDR_FAILURE);
+ }
+ xdr_destroy(&xdrs);
+
+ krb5_unparse_name(d->context, kdb->princ, &princstr);
+ fprintf(d->fp, "princ\t%s\t", princstr);
+ if(adb.policy == NULL)
+ fputc('\t', d->fp);
+ else
+ fprintf(d->fp, "%s\t", adb.policy);
+ fprintf(d->fp, "%x\t%d\t%d\t%d", adb.aux_attributes,
+ adb.old_key_len,adb.old_key_next, adb.admin_history_kvno);
+
+ for (x = 0; x < adb.old_key_len; x++) {
+ if (! d->ovsec_compat)
+ fprintf(d->fp, "\t%d", adb.old_keys[x].n_key_data);
+
+ foundcrc = 0;
+ for (y = 0; y < adb.old_keys[x].n_key_data; y++) {
+ krb5_key_data *key_data = &adb.old_keys[x].key_data[y];
+
+ if (d->ovsec_compat) {
+ if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC)
+ continue;
+ if (foundcrc) {
+ fprintf(stderr, error_message(EXPORT_DUP_DESCRC),
+ princstr);
+ continue;
+ }
+ foundcrc++;
+ }
+ fputc('\t', d->fp);
+ print_key_data(d->fp, key_data);
+ }
+ if (d->ovsec_compat && !foundcrc)
+ fprintf(stderr, error_message(EXPORT_NO_DESCRC), princstr);
+ }
+
+ d->count++;
+ fputc('\n', d->fp);
+ free(princstr);
+ return(0);
+}
+
+/*
+ * Function: print_policy
+ *
+ * Purpose: Print the contents of a policy entry in a human readable format.
+ * This format is also suitable for consumption for dbimport.
+ *
+ * Arguments:
+ * data (input) a pointer to a structure containing a FILE *
+ * and a record counter.
+ * entry (input) policy entry
+ * <return value> void
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * writes data to file
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+
+void
+print_policy(void *data, osa_policy_ent_t entry)
+{
+ struct retdata *d;
+
+ d = (struct retdata *) data;
+ fprintf(d->fp, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
+ entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+ entry->pw_min_classes, entry->pw_history_num,
+ entry->policy_refcnt);
+ d->count++;
+ return;
+}
+
+/*
+ * Function: export_principal
+ *
+ * Purpose: interates through the principal database with the
+ * osa_adb_iter_princ function which calls the print_princ
+ * routine with the FILE * of our filename. If the file
+ * name that gets passed in is NULL then we use stdout.
+ *
+ * Arguments:
+ * d (input) pointer to retdata.
+ * <return value> error code. 0 if sucsessful.
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * calls osa_adb_iter_princ which calls print_princ
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+osa_adb_ret_t
+export_principal(struct retdata *d, kadm5_config_params *params)
+{
+ int ret;
+
+ if (ret = krb5_db_set_name(d->context, params->dbname))
+ return ret;
+
+ if (ret = krb5_db_init(d->context))
+ return ret;
+
+ if (ret = krb5_dbm_db_iterate(d->context, print_princ, d))
+ return ret;
+
+ if (ret = krb5_db_fini(d->context))
+ return ret;
+
+ return 0;
+}
+
+/*
+ * Function: export_policy
+ *
+ * Purpose: iterates through the policy database with the
+ * osa_adb_iter_policy function which calls the print_policy
+ * routine with the FILE * of our filename. If the file name
+ * that gets passed in is NULL then we use stdout.
+ *
+ * Arguments:
+ * d (input) a pointer to retdata
+ * <return value> error code 0 if sucsessfull.
+ *
+ * Requires:
+ * nuttin
+ *
+ * Effects:
+ * calls osa_adb_iter_policy which calls print_policy
+ *
+ * Modifies:
+ * nuttin
+ *
+ */
+osa_adb_ret_t
+export_policy(struct retdata *d, osa_adb_policy_t db)
+{
+ osa_adb_ret_t ret;
+
+ if((ret = osa_adb_iter_policy(db, print_policy, (void *) d))
+ != OSA_ADB_OK) {
+ return ret;
+ }
+ return OSA_ADB_OK;
+}
diff --git a/src/kadmin/export/export_err.et b/src/kadmin/export/export_err.et
new file mode 100644
index 0000000000..6c99a47b07
--- /dev/null
+++ b/src/kadmin/export/export_err.et
@@ -0,0 +1,19 @@
+error_table exp
+error_code EXPORT_NO_ERR, "Database export complete, %d record%s processed.\n"
+error_code EXPORT_UNK_OPTION, "Unknown Option\nUsage: ovsec_adm_export [filename]"
+error_code EXPORT_OUTPUT_OPEN, "while opening output file"
+error_code EXPORT_OUTPUT_CHMOD, "while changing mode of file"
+error_code EXPORT_OUTPUT_STAT, "while trying to stat file"
+error_code EXPORT_DATABASE_OPEN, "while opening database"
+error_code EXPORT_PRINCIPAL, "while exporting principal database"
+error_code EXPORT_POLICY, "while exporting policy database"
+error_code EXPORT_LOCK, "while locking database"
+error_code EXPORT_UNLOCK, "while unlocking database"
+error_code EXPORT_CLOSE, "while closing database"
+error_code EXPORT_SINGLE_RECORD, ""
+error_code EXPORT_PLURAL_RECORDS, "s"
+error_code EXPORT_NO_DESCRC, "Warning! No DES-CBC-CRC key for principal %s, cannot generate ovsec_adm_export-compatible record; skipping."
+error_code EXPORT_DUP_DESCRC, "Warning! Multiple DES-CBC-CRC keys for principal %s; skipping duplicates."
+error_code EXPORT_GET_CONFIG, "while retrieving configuration parameters"
+end
+
diff --git a/src/kadmin/export/local.h b/src/kadmin/export/local.h
new file mode 100644
index 0000000000..3ec895ab24
--- /dev/null
+++ b/src/kadmin/export/local.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+struct retdata {
+ krb5_context context;
+ FILE *fp;
+ int count;
+ int ovsec_compat;
+};
+
+osa_adb_ret_t export_principal(struct retdata *, kadm5_config_params *);
+osa_adb_ret_t export_policy(struct retdata *d, osa_adb_policy_t);
diff --git a/src/kadmin/export/ovsec_adm_export.c b/src/kadmin/export/ovsec_adm_export.c
new file mode 100644
index 0000000000..ded21ba558
--- /dev/null
+++ b/src/kadmin/export/ovsec_adm_export.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <kadm5/adb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "export_err.h"
+#include "local.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *filename;
+ struct retdata d;
+ struct stat statb;
+ int ret, fd;
+ time_t now;
+ char *whoami = argv[0];
+ osa_adb_policy_t policy_db;
+ kadm5_config_params params;
+
+ memset(&params, 0, sizeof(params));
+ memset(&d, 0, sizeof(d));
+
+ filename = NULL;
+ initialize_exp_error_table();
+ initialize_adb_error_table();
+ krb5_init_context(&d.context);
+ krb5_init_ets(d.context);
+
+ while(--argc) {
+ if(*++argv == NULL)
+ break;
+ if(!strcmp(*argv, "-princ")) {
+ params.dbname = *++argv;
+ params.mask |= KADM5_CONFIG_DBNAME;
+ continue;
+ }
+ if(!strcmp(*argv, "-policy")) {
+ params.admin_dbname = *++argv;
+ params.mask |= KADM5_CONFIG_ADBNAME;
+ continue;
+ }
+ if(!strcmp(*argv, "-ovsec")) {
+ d.ovsec_compat++;
+ continue;
+ }
+ if (*argv[0] == '-') {
+ com_err(whoami, EXPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ if(filename == NULL)
+ filename = *argv;
+ else {
+ com_err(whoami, EXPORT_UNK_OPTION, NULL);
+ exit(2);
+ }
+ }
+
+ if (ret = kadm5_get_config_params(d.context, NULL, NULL, &params,
+ &params)) {
+ com_err(whoami, ret, error_message(EXPORT_GET_CONFIG));
+ exit(2);
+ }
+#define REQUIRED_MASK (KADM5_CONFIG_DBNAME | \
+ KADM5_CONFIG_ADBNAME)
+ if ((params.mask & REQUIRED_MASK) != REQUIRED_MASK) {
+ com_err(whoami, KADM5_BAD_SERVER_PARAMS,
+ error_message(EXPORT_GET_CONFIG));
+ exit(2);
+ }
+
+ if(filename != NULL) {
+ if((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0400)) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_OPEN), filename);
+ exit(2);
+ }
+ if(fstat(fd, &statb) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_STAT), filename);
+ exit(2);
+ }
+ if(S_ISREG(statb.st_mode)) {
+ int mask = umask(0);
+ (void) umask(mask);
+ if (fchmod(fd, (0400 & ~mask)) == -1) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_CHMOD), filename);
+ exit(2);
+ }
+ }
+ if ((d.fp = fdopen(fd, "w")) == NULL) {
+ com_err(whoami, errno, "%s (%s)",
+ error_message(EXPORT_OUTPUT_OPEN), filename);
+ exit(2);
+ }
+ } else d.fp = stdout;
+
+ if((ret = osa_adb_open_policy(&policy_db, &params)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_DATABASE_OPEN));
+ exit(2);
+ }
+ if ((ret = osa_adb_get_lock(policy_db, OSA_ADB_SHARED) != OSA_ADB_OK)) {
+ com_err(argv[0], ret, error_message(EXPORT_LOCK));
+ exit(2);
+ }
+
+ d.count = 0;
+
+ now = time(NULL);
+ if (d.ovsec_compat)
+ fprintf(d.fp, "OpenV*Secure V1.0\t%s", ctime(&now));
+ else
+ fprintf(d.fp, "Kerberos KADM5 database V2.0\t%s",
+ ctime(&now));
+
+ if ((ret = export_policy(&d, policy_db)) != OSA_ADB_OK) {
+ com_err(whoami, ret, "%s (%s)", error_message(EXPORT_POLICY),
+ params.admin_dbname);
+ exit(2);
+ }
+ if ((ret = export_principal(&d, &params)) !=
+ OSA_ADB_OK) {
+ com_err(whoami, ret, "%s (%s)", error_message(EXPORT_PRINCIPAL),
+ params.dbname);
+ exit(2);
+ }
+ fprintf(d.fp, "End of Database\t%d\trecords\n", d.count);
+
+ if ((ret = osa_adb_release_lock(policy_db)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_UNLOCK));
+ exit(2);
+ }
+ if ((ret = osa_adb_close_policy(policy_db)) != OSA_ADB_OK) {
+ com_err(argv[0], ret, error_message(EXPORT_CLOSE));
+ exit(2);
+ }
+
+ fprintf(stderr, error_message(EXPORT_NO_ERR), d.count,
+ (d.count == 1) ? error_message(EXPORT_SINGLE_RECORD) :
+ error_message(EXPORT_PLURAL_RECORDS));
+ exit(0);
+}
+
+
+
diff --git a/src/kadmin/export/unit-test/ChangeLog b/src/kadmin/export/unit-test/ChangeLog
new file mode 100644
index 0000000000..5db33c7c53
--- /dev/null
+++ b/src/kadmin/export/unit-test/ChangeLog
@@ -0,0 +1,5 @@
+Mon Jul 15 16:55:03 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.ov (unit-test-body), dotest.sh: ovsec_adm_*port is now
+ kadm5_*port
+
diff --git a/src/kadmin/export/unit-test/Makefile.ov b/src/kadmin/export/unit-test/Makefile.ov
new file mode 100644
index 0000000000..25b1bf6c70
--- /dev/null
+++ b/src/kadmin/export/unit-test/Makefile.ov
@@ -0,0 +1,19 @@
+#
+# $Id$
+#
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+unit-test:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-setup::
+ $(SAVE_FILES)
+ $(FIX_CONF_FILES)
+ $(INITDB)
+
+unit-test-body::
+ $(RUNTEST) EXPORT=../kadm5_export --tool export
+
+unit-test-cleanup::
+ $(RESTORE_FILES)
diff --git a/src/kadmin/export/unit-test/add-to-db.sh b/src/kadmin/export/unit-test/add-to-db.sh
new file mode 100644
index 0000000000..c505415463
--- /dev/null
+++ b/src/kadmin/export/unit-test/add-to-db.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+REALM=SECURE-TEST.OV.COM; export REALM
+DUMMY=${TESTDIR=$TOP/testing}; export TESTDIR
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL
+
+$SRVTCL <<'EOF'
+global r
+
+source $env(TCLUTIL)
+set r $env(REALM)
+
+proc newpol { pname } {
+ puts stdout [ovsec_kadm_create_policy $server_handle [simple_policy "$pname"] {OVSEC_KADM_POLICY}]
+}
+
+proc newprinc { name } {
+ global r
+ puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal "$name@$r"] {OVSEC_KADM_PRINCIPAL} $name]
+}
+
+proc chpass { princ pass } {
+ global server_handle
+ puts stdout [ovsec_kadm_chpass_principal $server_handle "$princ" "$pass"]
+}
+
+puts stdout [ovsec_kadm_init $env(SRVTCL) mrroot null $r $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle]
+
+puts stdout [ovsec_kadm_create_policy $server_handle "export_pwhist 0 0 0 0 10 0" {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}]
+
+### Commented out since this isn't going to work for the december beta
+#newprinc "export_with space"
+#newprinc "export_with\"dquote"
+#newprinc "export_with\nnewline"
+
+puts stdout [ovsec_kadm_create_principal $server_handle [princ_w_pol export_hist1@$r export_pwhist] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} hist1]
+
+chpass export_hist1@$r hist1_a
+
+puts stdout [ovsec_kadm_create_principal $server_handle [princ_w_pol export_hist10@$r export_pwhist] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} hist10]
+
+chpass export_hist10@$r hist10_a
+chpass export_hist10@$r hist10_b
+chpass export_hist10@$r hist10_c
+chpass export_hist10@$r hist10_d
+chpass export_hist10@$r hist10_e
+chpass export_hist10@$r hist10_f
+chpass export_hist10@$r hist10_g
+chpass export_hist10@$r hist10_h
+chpass export_hist10@$r hist10_i
+
+puts stdout [ovsec_kadm_destroy $server_handle]
+
+EOF
diff --git a/src/kadmin/export/unit-test/config/unix.exp b/src/kadmin/export/unit-test/config/unix.exp
new file mode 100644
index 0000000000..e8d852f899
--- /dev/null
+++ b/src/kadmin/export/unit-test/config/unix.exp
@@ -0,0 +1,36 @@
+#
+# export_version -- extract and print the version number of export
+#
+
+proc export_version {} {
+ global EXPORT
+ set tmp [exec ident $EXPORT]
+ if [regexp {Header: .*export.c,v ([0-9]+\.[0-9]+)} $tmp \
+ dummy version] then {
+ clone_output "$EXPORT version $version\n"
+ } else {
+ clone_output "$EXPORT version <unknown>\n"
+ }
+}
+#
+# export_load -- loads the program
+#
+proc export_load {} {
+ #
+}
+
+# export_exit -- clean up and exit
+proc export_exit {} {
+ #
+}
+
+#
+# export_start -- start export running
+#
+proc export_start { args } {
+ global EXPORT
+ global spawn_id
+
+ verbose "% $EXPORT $args" 1
+ eval spawn $EXPORT $args
+}
diff --git a/src/kadmin/export/unit-test/dotest.sh b/src/kadmin/export/unit-test/dotest.sh
new file mode 100644
index 0000000000..53d4fe0abb
--- /dev/null
+++ b/src/kadmin/export/unit-test/dotest.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${BSDDB_DUMP=$TESTDIR/util/bsddb_dump}
+DUMMY=${KDB5_EDIT=$TOP/../admin/edit/kdb5_edit}
+
+DPRINC=/tmp/dbdump.princ
+DPOL=/tmp/dbdump.policy
+
+DPRINC1=$DPRINC.1
+DPRINC2=$DPRINC.2
+
+DPOL1=$DPOL.1
+DPOL2=$DPOL.2
+
+DEXPORT=/tmp/dbexport
+
+./add-to-db.sh
+
+rm -f $DEXPORT
+../kadm5_export > $DEXPORT
+
+if $KDB5_EDIT -R ddb | sort > $DPRINC1; then
+ :
+else
+ echo "error dumping princ.1"
+fi
+if $BSDDB_DUMP /krb5/kadb5 | sort > $DPOL1; then
+ :
+else
+ echo "error dumping policy.1"
+fi
+
+rm -f /krb5/kadb5*
+touch /krb5/ovsec_adm.lock
+
+../../import/kadm5_import < $DEXPORT
+
+if $KDB5_EDIT -R ddb | sort > $DPRINC2; then
+ :
+else
+ echo "error dumping princ.2"
+fi
+if $BSDDB_DUMP /krb5/kadb5 | sort > $DPOL2; then
+ :
+else
+ echo "error dumping policy.2"
+fi
+
+
+status=0
+
+if test -s $DPRINC1 && \
+ test -s $DPRINC2 && \
+ cmp -s $DPRINC1 $DPRINC2; then
+ echo "export/import principal db succeeded"
+else
+ echo "export/import principal db failed"
+ status=1
+fi
+
+if test -s $DPOL1 && \
+ test -s $DPOL2 && \
+ cmp -s $DPOL1 $DPOL2; then
+ echo "export/import policy db succeeded"
+else
+ echo "export/import policy db failed"
+ status=1
+fi
+
+if [ $status -eq 0 ]; then
+ rm -f $DPRINC* $DPOL* $DEXPORT
+fi
+
+exit $status
diff --git a/src/kadmin/export/unit-test/export.0/dotest.exp b/src/kadmin/export/unit-test/export.0/dotest.exp
new file mode 100644
index 0000000000..93ac21250f
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/dotest.exp
@@ -0,0 +1,29 @@
+#
+# $Id$
+#
+
+verbose "starting test: dotest.sh"
+
+spawn ./dotest.sh
+
+set timeout 60
+
+expect {
+ -re "error dumping (princ|policy)\.(\[12\])"
+ { fail $expect_out(0,string); exp_continue }
+ -re "export/import (principal|policy) db (failed|succeeded)"
+ {
+ if {![string compare $expect_out(2,string) failed]} {
+ fail $expect_out(0,string)
+ } else {
+ pass $expect_out(0,string)
+ }
+ exp_continue
+ }
+ eof break
+ timeout { fail "timeout"; close }
+}
+
+set w [wait]
+
+verbose "% Exit $w"
diff --git a/src/kadmin/export/unit-test/export.0/output.exp b/src/kadmin/export/unit-test/export.0/output.exp
new file mode 100644
index 0000000000..6e0d4144b7
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/output.exp
@@ -0,0 +1,43 @@
+#
+# $Id$
+#
+
+set timeout 30
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+exec rm -f /tmp/dbexport
+
+export_win "B.25: General success" /tmp/dbexport
+
+check_mode "B.26" /tmp/dbexport 0400
+
+if {[catch "exec chmod 666 /tmp/dbexport" output]} {
+ unresolved "B.27: can't chmod /tmp/dbexport: $output"
+} else {
+ export_win "prep for B.27" /tmp/dbexport
+ check_mode "B.27" /tmp/dbexport 0400
+ exec rm -f /tmp/dbexport
+}
+
+proc test28 {} {
+ if {[catch "file stat /dev/null stats" output]} {
+ unresolved "B.28: can't stat /dev/null: $output"
+ return
+ }
+ set stats(mode) [expr $stats(mode) & 07777]
+ if {$stats(mode) == [expr 0400]} {
+ if {[catch "exec chmod 666 /dev/null" output]} {
+ unresolved "B.28: can't chmod /dev/null: $output"
+ return
+ }
+ set stats(mode) [expr 0666]
+ }
+ export_win "prep for B.28" /dev/null
+ check_mode "B.28" /dev/null $stats(mode)
+}
+test28
diff --git a/src/kadmin/export/unit-test/export.0/usage.exp b/src/kadmin/export/unit-test/export.0/usage.exp
new file mode 100644
index 0000000000..9a592c9b8d
--- /dev/null
+++ b/src/kadmin/export/unit-test/export.0/usage.exp
@@ -0,0 +1,25 @@
+#
+# $Id$
+#
+
+set timeout 30
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+export_lose "A.9: output file not writable" /foo/bar/baz \
+ "No such file or directory while opening output file"
+
+export_lose "A.10: two arguments" {foo bar} \
+ "Usage:"
+
+# XXX this depends on this being the last test run
+
+system {rm /krb5/kadb5}
+
+export_lose "A.2: /krb5 doesn't exist" /tmp/dbexport \
+ "No such file or directory while opening database"
+
diff --git a/src/kadmin/export/unit-test/helpers.exp b/src/kadmin/export/unit-test/helpers.exp
new file mode 100644
index 0000000000..c53630f4be
--- /dev/null
+++ b/src/kadmin/export/unit-test/helpers.exp
@@ -0,0 +1,126 @@
+#
+# $Id$
+#
+
+if {[info commands exp_version] != {}} {
+ set exp_version_4 [regexp {^4} [exp_version]]
+} else {
+ set exp_version_4 [regexp {^4} [expect_version]]
+}
+
+# Backward compatibility until we're using expect 5 everywhere
+if {$exp_version_4} {
+ global wait_error_index wait_errno_index wait_status_index
+ set wait_error_index 0
+ set wait_errno_index 1
+ set wait_status_index 1
+} else {
+ set wait_error_index 2
+ set wait_errno_index 3
+ set wait_status_index 3
+}
+
+proc myfail { comment } {
+ global mytest_name
+ global mytest_status
+ wait
+ fail "$mytest_name: $comment"
+ set mytest_status 1
+}
+
+proc mypass {} {
+}
+
+##
+## When you expect on an id, and eof is detected, the spawn_id is closed.
+## It may be waited for, but calling expect or close on this id is an ERROR!
+##
+
+proc mytest { name kpargs status args } {
+ global spawn_id
+ global timeout
+ global mytest_name
+ global mytest_status
+ global wait_error_index wait_errno_index wait_status_index
+
+ verbose "starting test: $name"
+
+ set mytest_name "$name"
+
+ eval export_start $kpargs
+
+ # at the end, eof is success
+
+ lappend args { eof { if {[regexp "\[\r\n\]$" $expect_out(buffer)] == 0} { myfail "final status message not newline-terminated" } } }
+
+ # for each test argument....
+ # rep invariant: when this foreach ends, the id is close'd, but
+ # not wait'ed.
+
+ foreach test $args {
+ set mytest_status 0
+
+ # treat the arg as an expect parameter
+ # if failure, the process will be closed and waited.
+
+ uplevel 1 "expect {
+ $test
+ timeout { close; myfail \"timeout\"}
+ eof { myfail \"eof read before expected message string\" }
+ }"
+
+ if {$mytest_status == 1} { return }
+ }
+
+ # at this point, the id is closed and we can wait on it.
+
+ set ret [wait]
+ verbose "% Exit $ret" 1
+ if {[lindex $ret $wait_error_index] == -1} {
+ fail "$name: wait returned error [lindex $ret $wait_errno_index]"
+ } else {
+ if { ((![string compare $status zero]) &&
+ ([lindex $ret $wait_status_index] == 0)) ||
+ ((![string compare $status nonzero]) &&
+ ([lindex $ret $wait_status_index] != 0)) } {
+ pass "$name"
+ } else {
+ fail "$name: unexpected return status [lindex $ret $wait_status_index], should be $status"
+ }
+ }
+}
+
+proc export_win { name args } {
+ mytest "$name" "$args" zero {
+ -re "Database export complete, \[0-9\]+ records processed."
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
+proc export_lose { name args error } {
+ mytest "$name" "$args" nonzero {
+ -re "Database export complete, \[0-9\]+ records processed."
+ { close; myfail "unexpected success" }
+ -re "ovsec_adm_export: .*$error"
+ { mypass }
+ eof
+ { myfail "error: $expect_out(buffer)" }
+ }
+}
+
+proc check_mode { test file mode } {
+ if {[catch "file stat $file stats" output]} {
+ unresolved "$test: can't stat $file: $output"
+ } else {
+ set stats(mode) [format "%o" [expr $stats(mode) & 07777]]
+ set mode [format "%o" [expr $mode]]
+ if {$stats(mode) != $mode} {
+ fail "$test: wrong mode ($stats(mode) should be $mode)"
+ } else {
+ verbose "$test: file $file has mode $mode"
+ pass $test
+ }
+ }
+}