summaryrefslogtreecommitdiffstats
path: root/src/kadmin/testing
diff options
context:
space:
mode:
authorMarc Horowitz <marc@mit.edu>1996-07-22 20:49:46 +0000
committerMarc Horowitz <marc@mit.edu>1996-07-22 20:49:46 +0000
commitedf8b4d8a6a665c2aa150993cd813ea6c5cf12e1 (patch)
tree6c2974a97b448c040fa4a31708ec5e02f187526c /src/kadmin/testing
parent013bb1391582ed9e653ae706e398ddb8d08cfcc9 (diff)
downloadkrb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.gz
krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.xz
krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.zip
this commit includes all the changes on the OV_9510_INTEGRATION and
OV_MERGE branches. This includes, but is not limited to, the new openvision admin system, and major changes to gssapi to add functionality, and bring the implementation in line with rfc1964. before committing, the code was built and tested for netbsd and solaris. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@8774 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kadmin/testing')
-rw-r--r--src/kadmin/testing/Makefile.ov8
-rw-r--r--src/kadmin/testing/proto/ChangeLog9
-rw-r--r--src/kadmin/testing/proto/kdc.conf.proto20
-rw-r--r--src/kadmin/testing/proto/krb5.conf.proto17
-rw-r--r--src/kadmin/testing/proto/ovsec_adm.dict3
-rw-r--r--src/kadmin/testing/scripts/ChangeLog15
-rw-r--r--src/kadmin/testing/scripts/Makefile.ov19
-rw-r--r--src/kadmin/testing/scripts/compare_dump.pl.in242
-rw-r--r--src/kadmin/testing/scripts/compare_dump.plin242
-rw-r--r--src/kadmin/testing/scripts/find-make.sh18
-rw-r--r--src/kadmin/testing/scripts/fixup-conf-files.pl.in344
-rw-r--r--src/kadmin/testing/scripts/fixup-conf-files.plin344
-rw-r--r--src/kadmin/testing/scripts/init_db181
-rw-r--r--src/kadmin/testing/scripts/make-host-keytab.pl.in138
-rw-r--r--src/kadmin/testing/scripts/make-host-keytab.plin138
-rw-r--r--src/kadmin/testing/scripts/qualname18
-rw-r--r--src/kadmin/testing/scripts/save_files.sh67
-rw-r--r--src/kadmin/testing/scripts/simple_dump.pl.in88
-rw-r--r--src/kadmin/testing/scripts/simple_dump.plin88
-rw-r--r--src/kadmin/testing/scripts/start_servers70
-rw-r--r--src/kadmin/testing/scripts/start_servers_local196
-rw-r--r--src/kadmin/testing/scripts/stop_servers84
-rw-r--r--src/kadmin/testing/scripts/stop_servers_local49
-rw-r--r--src/kadmin/testing/scripts/verify_xrunner_report.pl.in38
-rw-r--r--src/kadmin/testing/scripts/verify_xrunner_report.plin38
-rw-r--r--src/kadmin/testing/tcl/util.t61
-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
34 files changed, 7216 insertions, 0 deletions
diff --git a/src/kadmin/testing/Makefile.ov b/src/kadmin/testing/Makefile.ov
new file mode 100644
index 000000000..206bd8551
--- /dev/null
+++ b/src/kadmin/testing/Makefile.ov
@@ -0,0 +1,8 @@
+# $Id$
+
+TOP = ..
+include $(TOP)/config.mk/template
+
+SUBDIRS=util scripts
+
+expand SubdirTarget
diff --git a/src/kadmin/testing/proto/ChangeLog b/src/kadmin/testing/proto/ChangeLog
new file mode 100644
index 000000000..71959a3b0
--- /dev/null
+++ b/src/kadmin/testing/proto/ChangeLog
@@ -0,0 +1,9 @@
+Mon Jul 15 17:11:35 1996 Marc Horowitz <marc@mit.edu>
+
+ * krb5.conf.proto: specify a default_keytab_name in /krb5
+
+Fri Jul 12 14:46:17 1996 Marc Horowitz <marc@mit.edu>
+
+ * kdc.conf.proto: put the stash file in /krb5, so that the root
+ dir does not need to be writeable. also, the admin system
+ requires a reference in the conf file to admin_keytab
diff --git a/src/kadmin/testing/proto/kdc.conf.proto b/src/kadmin/testing/proto/kdc.conf.proto
new file mode 100644
index 000000000..798d6c51b
--- /dev/null
+++ b/src/kadmin/testing/proto/kdc.conf.proto
@@ -0,0 +1,20 @@
+[kdcdefaults]
+ kdc_ports = 1750
+
+[realms]
+ __REALM__ = {
+ profile = /krb5/krb5.conf
+ database_name = /krb5/kdb5
+ admin_database_name = /krb5/kadb5
+ admin_database_lockfile = /krb5/ovsec_adm.lock
+ admin_keytab = /krb5/ovsec_adm.srvtab
+ key_stash_file = /krb5/.k5.__REALM__
+ acl_file = /krb5/ovsec_adm.acl
+ dict_file = /krb5/ovsec_adm.dict
+ kadmind_port = 1751
+ max_life = 10h 0m 0s
+ max_renewable_life = 7d 0h 0m 0s
+ master_key_type = des-cbc-crc
+ supported_enctypes = des-cbc-crc:normal des-cbc-crc:v4
+ }
+
diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
new file mode 100644
index 000000000..6e0c4687d
--- /dev/null
+++ b/src/kadmin/testing/proto/krb5.conf.proto
@@ -0,0 +1,17 @@
+[libdefaults]
+ default_realm = __REALM__
+ default_keytab_name = FILE:/krb5/v5srvtab
+
+[realms]
+ __REALM__ = {
+ kdc = localhost:1750
+ admin_server = localhost:1751
+ }
+
+[domain_realm]
+ localhost = __REALM__
+
+[logging]
+ admin_server = SYSLOG=ERR:LOCAL6
+ kdc = SYSLOG=ERR:LOCAL6
+ default = SYSLOG=ERR:LOCAL6
diff --git a/src/kadmin/testing/proto/ovsec_adm.dict b/src/kadmin/testing/proto/ovsec_adm.dict
new file mode 100644
index 000000000..b54e3a85e
--- /dev/null
+++ b/src/kadmin/testing/proto/ovsec_adm.dict
@@ -0,0 +1,3 @@
+Abyssinia
+Discordianism
+foo
diff --git a/src/kadmin/testing/scripts/ChangeLog b/src/kadmin/testing/scripts/ChangeLog
new file mode 100644
index 000000000..5d7069186
--- /dev/null
+++ b/src/kadmin/testing/scripts/ChangeLog
@@ -0,0 +1,15 @@
+Fri Jul 12 14:48:20 1996 Marc Horowitz <marc@mit.edu>
+
+ * stop_servers_local (true, false): use the path to find these,
+ instead of looking in /bin explicitly.
+
+ * start_servers_local (/usr/tmp): /usr/tmp doesn't exist on some
+ systems. Check for that and /var/tmp, and use the one which
+ exists. (true, false): use the path to find these, instead of
+ looking in /bin explicitly.
+
+ * make-host-keytab.pl.in: perl5 requires that @ in strings be
+ backwhacked. (EDIT_KEYTAB): ovsec_adm_keytab is now kadm5_keytab.
+
+ * init_db: kadmin_create should be kdb5_create
+
diff --git a/src/kadmin/testing/scripts/Makefile.ov b/src/kadmin/testing/scripts/Makefile.ov
new file mode 100644
index 000000000..335b636e7
--- /dev/null
+++ b/src/kadmin/testing/scripts/Makefile.ov
@@ -0,0 +1,19 @@
+# $Id$
+
+TOP = ../..
+include $(TOP)/config.mk/template
+
+GEN_SCRIPTS = compare_dump.pl fixup-conf-files.pl make-host-keytab.pl \
+ simple_dump.pl verify_xrunner_report.pl
+
+all:: $(GEN_SCRIPTS)
+
+%.pl: %.pl.in
+ -rm -f $@.tmp
+ echo "#!$(PERL)" > $@.tmp
+ sed 1d $@.in >> $@.tmp
+ chmod +x $@.tmp
+ mv $@.tmp $@
+
+clean::
+ -rm -f $(GEN_SCRIPTS) *.tmp
diff --git a/src/kadmin/testing/scripts/compare_dump.pl.in b/src/kadmin/testing/scripts/compare_dump.pl.in
new file mode 100644
index 000000000..df93df4a0
--- /dev/null
+++ b/src/kadmin/testing/scripts/compare_dump.pl.in
@@ -0,0 +1,242 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+# $debug = 1;
+
+sub usage { die "usage: $0 before after changes\n";}
+
+sub unique {
+ local(@list) = @_;
+ local(%ary);
+
+ print "unique? ",join(" ",@list),"\n" if $debug;
+
+ foreach (@list) {
+ return(0) if $ary{$_}++;
+ }
+
+ 1;
+}
+
+$before = shift(@ARGV) || &usage;
+$debug++ if $before =~ /^-d/;
+$before = shift(@ARGV) || &usage if $debug;
+$after = shift(@ARGV) || &usage;
+$changes = shift(@ARGV) || &usage;
+@ARGV && &usage;
+
+%policy =
+ (
+ "FIRST",2,
+ "pw_min_life",2,
+ "pw_max_life",3,
+ "pw_min_length",4,
+ "pw_min_classes",5,
+ "pw_history_num",6,
+ "policy_refcnt",7,
+ "LAST",7,
+ );
+
+%princ =
+ (
+ "FIRST",2,
+ "kvno",2,
+ "mod_name",3,
+ "max_life",4,
+ "princ_expire_time",5,
+ "expiration",5,
+ "pw_expiration",6,
+ "attributes",7,
+ "policy",8,
+ "aux_attributes",9,
+ "LAST",9,
+ );
+
+%keytab =
+ (
+ "LAST",-1,
+ );
+
+sub re { # @_ = ($cnt, $line)
+ local($cnt, $line) = @_;
+ local(@fields) = split(' ',$line);
+
+ @list = ('\S+') x $cnt;
+ for $f (@fields[3..$#fields]) {
+ ($f =~ /=/) || die "Bad field: $f in $_";
+ if (!defined($this{$`})) { die "Bad parameter $` in $_"; }
+
+ if (($list[$this{$`}] = $') eq '\S+') {
+ $list[$this{$`}] = '[^\s]+';
+ }
+ }
+
+ join('\s+',@list)."\$";
+}
+
+open(CHANGES, $changes) || die "Couldn't open $changes: $!\n";
+
+while(<CHANGES>) {
+ next if s/^\s*\#\#\!\s*\#//;
+ next if !s/^\s*\#\#\!\s*//;
+
+ split;
+
+ if ($_[1] =~ /princ/) {
+ %this = %princ;
+ $this = "princ";
+ } elsif ($_[1] =~ /policy/) {
+ %this = %policy;
+ $this = "policy";
+ } elsif ($_[1] =~ /keytab/) {
+ %this = %keytab;
+ $this = $_[1];
+ } else {
+ die "Bad line: $_";
+ }
+
+ $cnt = $this{"LAST"}+1;
+
+ if ($_[0] =~ /add/) {
+ $diff{"+$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /delete/) {
+ $diff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /changefrom/) {
+ $diff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /changeto/) {
+ $ndiff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } else {
+ die "Bad line: $_";
+ }
+}
+
+close(CHANGES);
+
+if ($debug) {
+ for (keys %diff) {
+ print " %diff: \"$_\" /$diff{$_}/\n";
+ }
+
+ for (keys %ndiff) {
+ print "%ndiff: \"$_\" /$ndiff{$_}/\n";
+ }
+
+ print "\n";
+}
+
+open(DIFF,"gdiff -u0 $before $after|") || die "Couldn't diff: $!\n";
+
+$warnings = 0;
+
+while(<DIFF>) {
+ next if /^\+{3}/;
+ next if /^\-{3}/;
+ next if /^@@/;
+
+ print "LINE: $_" if $debug;
+
+ split;
+
+ $key = "$_[0]\t$_[1]";
+ $re = $diff{$key};
+
+ delete $diff{$key};
+
+ print "%diff: \"$key\" /$re/\n" if $debug;
+
+ if (!$re) {
+ warn "Unexpected: \"$key\"\n";
+ $warnings++;
+ next;
+ }
+
+ if (!/$re/) {
+ warn "Failed: $key\n";
+ $warnings++;
+ next;
+ }
+
+ if ($new = $ndiff{$key}) {
+ delete $ndiff{$key};
+
+ @new = split(/\\s\+/, $new);
+ for ($i=1;$i<@new;$i++) {
+ print "NEW: $new[$i]\n" if $debug;
+
+ if ($new[$i] ne '\S+') {
+ $_[$i] = $new[$i];
+ }
+ }
+ $_[0] =~ s/^\-//;
+ $key =~ s/^\-/\+/;
+
+ $diff{$key} = join("\t",@_);
+ }
+}
+
+close(DIFF);
+
+open(BEFORE, $before) || die "Couldn't open $before: $!\n";
+
+while(<BEFORE>) {
+ next if !/^keytab/;
+
+ split;
+
+ if (!$seen{$key = $_[0]." ".$_[1]}++) {
+ $key =~ s/-\d+$//;
+ $ktkeys{$key} .= " ".$_[2];
+ $kttimes{$key} .= " ".$_[3];
+ }
+}
+
+close(BEFORE);
+
+open(AFTER, $after) || die "Couldn't open $after: $!\n";
+
+while(<AFTER>) {
+ next if !/^keytab/;
+
+ split;
+
+ if (!$seen{$key = $_[0]." ".$_[1]}++) {
+ $key =~ s/-\d+$//;
+ $ktkeys{$key} .= " ".$_[2];
+ $kttimes{$key} .= " ".$_[3];
+ }
+}
+
+close(AFTER);
+
+for (keys %diff) {
+ warn "Unseen: \"$_\" /$diff{$_}/\n";
+ $warnings++;
+}
+
+for (keys %ndiff) {
+ warn "Unseen changes: \"$_\" /$ndiff{$_}/\n";
+ $warnings++;
+}
+
+for (keys %ktkeys) {
+ if (!&unique(split(' ',$ktkeys{$_}))) {
+ warn "Some keys not unique for $_\n";
+ $warnings++;
+ }
+}
+
+for (keys %kttimes) {
+ if (!&unique(split(' ',$kttimes{$_}))) {
+ warn "Some timestamps not unique for $_\n";
+ $warnings++;
+ }
+}
+
+if ($warnings) {
+ warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/src/kadmin/testing/scripts/compare_dump.plin b/src/kadmin/testing/scripts/compare_dump.plin
new file mode 100644
index 000000000..df93df4a0
--- /dev/null
+++ b/src/kadmin/testing/scripts/compare_dump.plin
@@ -0,0 +1,242 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+# $debug = 1;
+
+sub usage { die "usage: $0 before after changes\n";}
+
+sub unique {
+ local(@list) = @_;
+ local(%ary);
+
+ print "unique? ",join(" ",@list),"\n" if $debug;
+
+ foreach (@list) {
+ return(0) if $ary{$_}++;
+ }
+
+ 1;
+}
+
+$before = shift(@ARGV) || &usage;
+$debug++ if $before =~ /^-d/;
+$before = shift(@ARGV) || &usage if $debug;
+$after = shift(@ARGV) || &usage;
+$changes = shift(@ARGV) || &usage;
+@ARGV && &usage;
+
+%policy =
+ (
+ "FIRST",2,
+ "pw_min_life",2,
+ "pw_max_life",3,
+ "pw_min_length",4,
+ "pw_min_classes",5,
+ "pw_history_num",6,
+ "policy_refcnt",7,
+ "LAST",7,
+ );
+
+%princ =
+ (
+ "FIRST",2,
+ "kvno",2,
+ "mod_name",3,
+ "max_life",4,
+ "princ_expire_time",5,
+ "expiration",5,
+ "pw_expiration",6,
+ "attributes",7,
+ "policy",8,
+ "aux_attributes",9,
+ "LAST",9,
+ );
+
+%keytab =
+ (
+ "LAST",-1,
+ );
+
+sub re { # @_ = ($cnt, $line)
+ local($cnt, $line) = @_;
+ local(@fields) = split(' ',$line);
+
+ @list = ('\S+') x $cnt;
+ for $f (@fields[3..$#fields]) {
+ ($f =~ /=/) || die "Bad field: $f in $_";
+ if (!defined($this{$`})) { die "Bad parameter $` in $_"; }
+
+ if (($list[$this{$`}] = $') eq '\S+') {
+ $list[$this{$`}] = '[^\s]+';
+ }
+ }
+
+ join('\s+',@list)."\$";
+}
+
+open(CHANGES, $changes) || die "Couldn't open $changes: $!\n";
+
+while(<CHANGES>) {
+ next if s/^\s*\#\#\!\s*\#//;
+ next if !s/^\s*\#\#\!\s*//;
+
+ split;
+
+ if ($_[1] =~ /princ/) {
+ %this = %princ;
+ $this = "princ";
+ } elsif ($_[1] =~ /policy/) {
+ %this = %policy;
+ $this = "policy";
+ } elsif ($_[1] =~ /keytab/) {
+ %this = %keytab;
+ $this = $_[1];
+ } else {
+ die "Bad line: $_";
+ }
+
+ $cnt = $this{"LAST"}+1;
+
+ if ($_[0] =~ /add/) {
+ $diff{"+$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /delete/) {
+ $diff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /changefrom/) {
+ $diff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } elsif ($_[0] =~ /changeto/) {
+ $ndiff{"-$this\t$_[2]"} = &re($cnt,$_);
+ } else {
+ die "Bad line: $_";
+ }
+}
+
+close(CHANGES);
+
+if ($debug) {
+ for (keys %diff) {
+ print " %diff: \"$_\" /$diff{$_}/\n";
+ }
+
+ for (keys %ndiff) {
+ print "%ndiff: \"$_\" /$ndiff{$_}/\n";
+ }
+
+ print "\n";
+}
+
+open(DIFF,"gdiff -u0 $before $after|") || die "Couldn't diff: $!\n";
+
+$warnings = 0;
+
+while(<DIFF>) {
+ next if /^\+{3}/;
+ next if /^\-{3}/;
+ next if /^@@/;
+
+ print "LINE: $_" if $debug;
+
+ split;
+
+ $key = "$_[0]\t$_[1]";
+ $re = $diff{$key};
+
+ delete $diff{$key};
+
+ print "%diff: \"$key\" /$re/\n" if $debug;
+
+ if (!$re) {
+ warn "Unexpected: \"$key\"\n";
+ $warnings++;
+ next;
+ }
+
+ if (!/$re/) {
+ warn "Failed: $key\n";
+ $warnings++;
+ next;
+ }
+
+ if ($new = $ndiff{$key}) {
+ delete $ndiff{$key};
+
+ @new = split(/\\s\+/, $new);
+ for ($i=1;$i<@new;$i++) {
+ print "NEW: $new[$i]\n" if $debug;
+
+ if ($new[$i] ne '\S+') {
+ $_[$i] = $new[$i];
+ }
+ }
+ $_[0] =~ s/^\-//;
+ $key =~ s/^\-/\+/;
+
+ $diff{$key} = join("\t",@_);
+ }
+}
+
+close(DIFF);
+
+open(BEFORE, $before) || die "Couldn't open $before: $!\n";
+
+while(<BEFORE>) {
+ next if !/^keytab/;
+
+ split;
+
+ if (!$seen{$key = $_[0]." ".$_[1]}++) {
+ $key =~ s/-\d+$//;
+ $ktkeys{$key} .= " ".$_[2];
+ $kttimes{$key} .= " ".$_[3];
+ }
+}
+
+close(BEFORE);
+
+open(AFTER, $after) || die "Couldn't open $after: $!\n";
+
+while(<AFTER>) {
+ next if !/^keytab/;
+
+ split;
+
+ if (!$seen{$key = $_[0]." ".$_[1]}++) {
+ $key =~ s/-\d+$//;
+ $ktkeys{$key} .= " ".$_[2];
+ $kttimes{$key} .= " ".$_[3];
+ }
+}
+
+close(AFTER);
+
+for (keys %diff) {
+ warn "Unseen: \"$_\" /$diff{$_}/\n";
+ $warnings++;
+}
+
+for (keys %ndiff) {
+ warn "Unseen changes: \"$_\" /$ndiff{$_}/\n";
+ $warnings++;
+}
+
+for (keys %ktkeys) {
+ if (!&unique(split(' ',$ktkeys{$_}))) {
+ warn "Some keys not unique for $_\n";
+ $warnings++;
+ }
+}
+
+for (keys %kttimes) {
+ if (!&unique(split(' ',$kttimes{$_}))) {
+ warn "Some timestamps not unique for $_\n";
+ $warnings++;
+ }
+}
+
+if ($warnings) {
+ warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/src/kadmin/testing/scripts/find-make.sh b/src/kadmin/testing/scripts/find-make.sh
new file mode 100644
index 000000000..904730dfa
--- /dev/null
+++ b/src/kadmin/testing/scripts/find-make.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+POSSIBILITIES='
+/usr/local/bin/gmake
+/usr/local/bin/make
+'
+
+for file in $POSSIBILITIES; do
+ if [ -f $file ]; then
+ echo $file
+ exit 0
+ fi
+done
+
+echo gmake
+echo '$0 could not find make!' 1>&2
+exit 1
+
diff --git a/src/kadmin/testing/scripts/fixup-conf-files.pl.in b/src/kadmin/testing/scripts/fixup-conf-files.pl.in
new file mode 100644
index 000000000..d7834d1c7
--- /dev/null
+++ b/src/kadmin/testing/scripts/fixup-conf-files.pl.in
@@ -0,0 +1,344 @@
+#!/usr/local/bin/perl
+#
+# Usage: fixup-conf-files.pl [-server hostname]
+
+$verbose = $ENV{'VERBOSE_TEST'};
+$archos = $ENV{'ARCH_OS'};
+
+$REALM = "SECURE-TEST.OV.COM";
+
+sub replace {
+ local($old, $new, $backup) = @_;
+ local($dev, $ino, $mode);
+
+ $new = $old.".new" if !$new;
+ $backup = $old.".bak" if !$backup;
+
+ chmod($mode,$new) if (($dev, $ino, $mode) = stat($old));
+
+ unlink($backup);
+ link($old, $backup) || die "couldn't make backup link: $backup: $!\n"
+ if -e $old;
+ rename($new, $old) || die "couldn't rename $old to $new: $!\n";
+}
+
+if (@ARGV == 2 && $ARGV[0] eq "-server") {
+ $servername = $ARGV[1];
+} elsif (@ARGV != 0) {
+ print STDERR "Usage: $0 fixup-conf-files.pl [-server hostname]\n";
+}
+
+sub canonicalize_name {
+ local($hostname) = @_;
+ local($d, $addr, $addrtype);
+
+ ($host,$d,$addrtype,$d,$addr) = gethostbyname($hostname);
+ die "couldn't get hostname $hostname\n" if !$host;
+ ($host) = gethostbyaddr($addr,$addrtype);
+ die "couldn't reverse-resolve $hostname\n" if !$host;
+ return $host;
+}
+
+## Get server's canonical hostname.
+if ($servername) {
+ $serverhost = $servername;
+} else {
+ chop ($serverhost = `hostname`);
+}
+$serverhost = &canonicalize_name($serverhost);
+
+## Get local canonical hostname
+chop($localhost=`hostname`);
+$localhost = &canonicalize_name($localhost);
+
+## parse krb.conf
+
+if (open(KCONF, "/etc/athena/krb.conf")) {
+ chop($hrealm = <KCONF>);
+
+ $confok = 0;
+
+ while(<KCONF>) {
+ $confs .= $_ if !/^$REALM\s+/o;
+ $confok = 1 if /^$REALM\s+$serverhost\s+admin\s+server$/oi;
+ }
+
+ close(KCONF);
+}
+
+## rewrite krb.conf if necessary.
+
+if (($hrealm ne $REALM) || !$confok) {
+ print "Rewriting /etc/athena/krb.conf...\n" if $verbose;
+
+ open(KCONF, ">/etc/athena/krb.conf.new") ||
+ die "couldn't open /etc/athena/krb.conf.new: $!\n";
+
+ print KCONF "$REALM\n";
+ print KCONF "$REALM $serverhost admin server\n";
+ print KCONF $confs;
+
+ close(KCONF);
+
+ &replace("/etc/athena/krb.conf");
+}
+
+## parse krb.realms
+
+if (open(KREALMS, "/etc/athena/krb.realms")) {
+ $serverrealmok = 0;
+ $localrealmok = 0;
+
+ while(<KREALMS>) {
+ $realms .= $_
+ if !/^$serverhost\s+$REALM$/oi && !/^$localhost\s+$REALM$/oi;
+ $serverrealmok = 1 if /^$serverhost\s+$REALM$/oi;
+ $localrealmok = 1 if /^$localhost\s+$REALM$/oi;
+ }
+
+ close(KREALMS);
+}
+
+## rewrite krb.realms if necessary.
+
+if (!$serverrealmok || !$localrealmok) {
+ print "Rewriting /etc/athean/krb.realms...\n" if $verbose;
+
+ open(KREALMS, ">/etc/athena/krb.realms.new") ||
+ die "couldn't open /etc/athena/krb.realms.new: $!\n";
+
+ print KREALMS "$serverhost $REALM\n";
+ print KREALMS "$localhost $REALM\n" if ($localhost ne $serverhost);
+ print KREALMS $realms;
+
+ close(KREALMS);
+
+ &replace("/etc/athena/krb.realms");
+}
+
+# ## read /etc/passwd
+#
+# open(PASSWD, "/etc/passwd") || die "couldn't open /etc/passwd: $!\n";
+#
+# $passok = 0;
+#
+# if ($archos ne "solaris2.3") {
+# %mypass =
+# (
+# "root", crypt("testroot","St"),
+# "testenc", crypt("notath","HJ"),
+# "testuser", "KERBEROS5",
+# "pol1", "KERBEROS5",
+# "pol2", "KERBEROS5",
+# "pol3", "KERBEROS5",
+# );
+# } else {
+# %mypass =
+# (
+# "root", "x",
+# "testenc", "x",
+# "testuser", "x",
+# "pol1", "x",
+# "pol2", "x",
+# "pol3", "x",
+# );
+# %myshadow =
+# (
+# "root", crypt("testroot","St"),
+# "testenc", crypt("notath","HJ"),
+# "testuser", "KERBEROS5",
+# "pol1", "KERBEROS5",
+# "pol2", "KERBEROS5",
+# "pol3", "KERBEROS5",
+# );
+# }
+#
+# $chpw = 0;
+#
+# while(<PASSWD>) {
+# if (/^([^:]+):([^:]+):/ && $mypass{$1}) {
+# $users{$1}++;
+# if ($2 ne $mypass{$1}) {
+# s/^([^:]+):([^:]+):/$1:$mypass{$1}:/;
+# $chpw++;
+# }
+# }
+# $pass .= $_;
+# }
+#
+# $passok = 1;
+#
+# for (keys %mypass) {
+# if (!$users{$_}) {
+# $pass .= "$_:$mypass{$_}:32765:101::/tmp:/bin/csh\n";
+# $passok = 0;
+# }
+# }
+# close(PASSWD);
+#
+# ## rewrite passwd if necessary.
+#
+# if ($chpw || !$passok) {
+# print "Rewriting /etc/passwd...\n" if $verbose;
+#
+# open(PASSWD, ">/etc/passwd.new") ||
+# die "couldn't open /etc/passwd.new: $!\n";
+#
+# print PASSWD $pass;
+#
+# close(PASSWD);
+#
+# &replace("/etc/passwd");
+# }
+#
+# if ($archos eq "solaris2.3") {
+#
+# ## read /etc/shadow
+#
+# open(SHADOW, "/etc/shadow") || die "couldn't open /etc/shadow: $!\n";
+#
+# $shadowok = 0;
+# $chpw = 0;
+# %users = ();
+#
+# while(<SHADOW>) {
+# if (/^([^:]+):([^:]+):/ && $myshadow{$1}) {
+# $users{$1}++;
+# if ($2 ne $myshadow{$1}) {
+# s/^([^:]+):([^:]+):/$1:$myshadow{$1}:/;
+# $chpw++;
+# }
+# }
+# $shadow .= $_;
+# }
+#
+# $shadowok = 1;
+#
+# for (keys %myshadow) {
+# if (!$users{$_}) {
+# $shadow .= "$_:$myshadow{$_}:6445::::::\n";
+# $shadowok = 0;
+# }
+# }
+# close(SHADOW);
+#
+# ## rewrite shadow if necessary.
+#
+# if ($chpw || !$shadowok) {
+# print "Rewriting /etc/shadow...\n" if $verbose;
+#
+# open(SHADOW, ">/etc/shadow.new") ||
+# die "couldn't open /etc/shadow.new: $!\n";
+#
+# print SHADOW $shadow;
+#
+# close(SHADOW);
+#
+# &replace("/etc/shadow");
+# }
+# }
+#
+# if ($archos eq "aix3.2") {
+#
+# ## read /etc/security/passwd
+#
+# open(SHADOW, "/etc/security/passwd") || die "couldn't open /etc/security/passwd: $!\n";
+#
+# $shadowok = 0;
+# %users = ();
+#
+# while(<SHADOW>) {
+# if (/^([^:]+):\s*$/ && $mypass{$1}) {
+# $user = $1;
+# $users{$user}++;
+# # arrange for the user to have a password entry and none other
+# while (<SHADOW>) {
+# last if (!/=/);
+# }
+# $shadow .= "$user:\n\tpassword = KERBEROS5\n\n";
+# } else {
+# $shadow .= $_;
+# }
+# }
+#
+# $shadowok = 1;
+#
+# for (keys %mypass) {
+# if (!$users{$_}) {
+# $shadow .= "$_:\n\tpassword = KERBEROS5\n\n";
+# $shadowok = 0;
+# }
+# }
+# close(SHADOW);
+#
+# ## rewrite shadow if necessary.
+#
+# if (!$shadowok) {
+# print "Rewriting /etc/security/passwd...\n" if $verbose;
+#
+# open(SHADOW, ">/etc/security/passwd.new") ||
+# die "couldn't open /etc/security/passwd.new: $!\n";
+#
+# print SHADOW $shadow;
+#
+# close(SHADOW);
+#
+# &replace("/etc/security/passwd");
+# }
+# }
+#
+# open(SERVICES, "/etc/services") || die "couldn't open /etc/services: $!\n";
+# open(NEW_SERVICES, ">/etc/services.new") ||
+# die "couldn't open /etc/services.new: $!\n";
+#
+# print "Rewriting /etc/services...\n" if $verbose;
+#
+# @needed_services = ('klogin', 'kshell', 'kerberos', 'kerberos-sec',
+# 'kerberos5', 'kerberos4', 'kerberos_master',
+# 'passwd_server', 'eklogin', 'krb5_prop',
+# 'kerberos_adm', 'kerberos-adm');
+# for (@needed_services) {
+# $needed_services{$_}++;
+# }
+#
+# while (<SERVICES>) {
+# m/^\s*([^\#\s][^\s]+)/;
+# if ($needed_services{$1}) {
+# print "+ Commenting out old entry: $1\n" if $verbose;
+# print NEW_SERVICES "# $_";
+# } else {
+# print NEW_SERVICES $_;
+# }
+# }
+#
+# close(SERVICES);
+#
+# print NEW_SERVICES <<EOF || die "writing to /etc/services.new: $!\n";
+#
+# klogin 543/tcp # Kerberos authenticated rlogin
+# kshell 544/tcp cmd # and remote shell
+# kerberos 88/udp kdc # Kerberos authentication--udp
+# kerberos 88/tcp kdc # Kerberos authentication--tcp
+# kerberos-sec 750/udp # Kerberos authentication--udp
+# kerberos-sec 750/tcp # Kerberos authentication--tcp
+# kerberos5 88/udp kdc # Kerberos authentication--udp
+# kerberos5 88/tcp kdc # Kerberos authentication--tcp
+# kerberos4 750/udp # Kerberos authentication--udp
+# kerberos4 750/tcp # Kerberos authentication--tcp
+# kerberos_master 751/udp # Kerberos authentication
+# kerberos_master 751/tcp # Kerberos authentication
+# passwd_server 752/udp # Kerberos passwd server
+# eklogin 2105/tcp # Kerberos encrypted rlogin
+# krb5_prop 754/tcp # Kerberos slave propagation
+# kerberos_adm 752/tcp # Kerberos 5 admin/changepw
+# kerberos-adm 752/tcp # Kerberos 5 admin/changepw
+# EOF
+#
+# close(NEW_SERVICES) || die "error closing /etc/services.new: $!\n";
+#
+# rename("/etc/services", "/etc/services.old") ||
+# die "couldn't rename /etc/services to /etc/services.old: $!\n";
+# rename("/etc/services.new", "/etc/services") ||
+# die "couldn't rename /etc/services.new to /etc/services: $!\n";
+# unlink("/etc/services.old") || die "couldn't unlink /etc/services: $!\n";
+#
diff --git a/src/kadmin/testing/scripts/fixup-conf-files.plin b/src/kadmin/testing/scripts/fixup-conf-files.plin
new file mode 100644
index 000000000..d7834d1c7
--- /dev/null
+++ b/src/kadmin/testing/scripts/fixup-conf-files.plin
@@ -0,0 +1,344 @@
+#!/usr/local/bin/perl
+#
+# Usage: fixup-conf-files.pl [-server hostname]
+
+$verbose = $ENV{'VERBOSE_TEST'};
+$archos = $ENV{'ARCH_OS'};
+
+$REALM = "SECURE-TEST.OV.COM";
+
+sub replace {
+ local($old, $new, $backup) = @_;
+ local($dev, $ino, $mode);
+
+ $new = $old.".new" if !$new;
+ $backup = $old.".bak" if !$backup;
+
+ chmod($mode,$new) if (($dev, $ino, $mode) = stat($old));
+
+ unlink($backup);
+ link($old, $backup) || die "couldn't make backup link: $backup: $!\n"
+ if -e $old;
+ rename($new, $old) || die "couldn't rename $old to $new: $!\n";
+}
+
+if (@ARGV == 2 && $ARGV[0] eq "-server") {
+ $servername = $ARGV[1];
+} elsif (@ARGV != 0) {
+ print STDERR "Usage: $0 fixup-conf-files.pl [-server hostname]\n";
+}
+
+sub canonicalize_name {
+ local($hostname) = @_;
+ local($d, $addr, $addrtype);
+
+ ($host,$d,$addrtype,$d,$addr) = gethostbyname($hostname);
+ die "couldn't get hostname $hostname\n" if !$host;
+ ($host) = gethostbyaddr($addr,$addrtype);
+ die "couldn't reverse-resolve $hostname\n" if !$host;
+ return $host;
+}
+
+## Get server's canonical hostname.
+if ($servername) {
+ $serverhost = $servername;
+} else {
+ chop ($serverhost = `hostname`);
+}
+$serverhost = &canonicalize_name($serverhost);
+
+## Get local canonical hostname
+chop($localhost=`hostname`);
+$localhost = &canonicalize_name($localhost);
+
+## parse krb.conf
+
+if (open(KCONF, "/etc/athena/krb.conf")) {
+ chop($hrealm = <KCONF>);
+
+ $confok = 0;
+
+ while(<KCONF>) {
+ $confs .= $_ if !/^$REALM\s+/o;
+ $confok = 1 if /^$REALM\s+$serverhost\s+admin\s+server$/oi;
+ }
+
+ close(KCONF);
+}
+
+## rewrite krb.conf if necessary.
+
+if (($hrealm ne $REALM) || !$confok) {
+ print "Rewriting /etc/athena/krb.conf...\n" if $verbose;
+
+ open(KCONF, ">/etc/athena/krb.conf.new") ||
+ die "couldn't open /etc/athena/krb.conf.new: $!\n";
+
+ print KCONF "$REALM\n";
+ print KCONF "$REALM $serverhost admin server\n";
+ print KCONF $confs;
+
+ close(KCONF);
+
+ &replace("/etc/athena/krb.conf");
+}
+
+## parse krb.realms
+
+if (open(KREALMS, "/etc/athena/krb.realms")) {
+ $serverrealmok = 0;
+ $localrealmok = 0;
+
+ while(<KREALMS>) {
+ $realms .= $_
+ if !/^$serverhost\s+$REALM$/oi && !/^$localhost\s+$REALM$/oi;
+ $serverrealmok = 1 if /^$serverhost\s+$REALM$/oi;
+ $localrealmok = 1 if /^$localhost\s+$REALM$/oi;
+ }
+
+ close(KREALMS);
+}
+
+## rewrite krb.realms if necessary.
+
+if (!$serverrealmok || !$localrealmok) {
+ print "Rewriting /etc/athean/krb.realms...\n" if $verbose;
+
+ open(KREALMS, ">/etc/athena/krb.realms.new") ||
+ die "couldn't open /etc/athena/krb.realms.new: $!\n";
+
+ print KREALMS "$serverhost $REALM\n";
+ print KREALMS "$localhost $REALM\n" if ($localhost ne $serverhost);
+ print KREALMS $realms;
+
+ close(KREALMS);
+
+ &replace("/etc/athena/krb.realms");
+}
+
+# ## read /etc/passwd
+#
+# open(PASSWD, "/etc/passwd") || die "couldn't open /etc/passwd: $!\n";
+#
+# $passok = 0;
+#
+# if ($archos ne "solaris2.3") {
+# %mypass =
+# (
+# "root", crypt("testroot","St"),
+# "testenc", crypt("notath","HJ"),
+# "testuser", "KERBEROS5",
+# "pol1", "KERBEROS5",
+# "pol2", "KERBEROS5",
+# "pol3", "KERBEROS5",
+# );
+# } else {
+# %mypass =
+# (
+# "root", "x",
+# "testenc", "x",
+# "testuser", "x",
+# "pol1", "x",
+# "pol2", "x",
+# "pol3", "x",
+# );
+# %myshadow =
+# (
+# "root", crypt("testroot","St"),
+# "testenc", crypt("notath","HJ"),
+# "testuser", "KERBEROS5",
+# "pol1", "KERBEROS5",
+# "pol2", "KERBEROS5",
+# "pol3", "KERBEROS5",
+# );
+# }
+#
+# $chpw = 0;
+#
+# while(<PASSWD>) {
+# if (/^([^:]+):([^:]+):/ && $mypass{$1}) {
+# $users{$1}++;
+# if ($2 ne $mypass{$1}) {
+# s/^([^:]+):([^:]+):/$1:$mypass{$1}:/;
+# $chpw++;
+# }
+# }
+# $pass .= $_;
+# }
+#
+# $passok = 1;
+#
+# for (keys %mypass) {
+# if (!$users{$_}) {
+# $pass .= "$_:$mypass{$_}:32765:101::/tmp:/bin/csh\n";
+# $passok = 0;
+# }
+# }
+# close(PASSWD);
+#
+# ## rewrite passwd if necessary.
+#
+# if ($chpw || !$passok) {
+# print "Rewriting /etc/passwd...\n" if $verbose;
+#
+# open(PASSWD, ">/etc/passwd.new") ||
+# die "couldn't open /etc/passwd.new: $!\n";
+#
+# print PASSWD $pass;
+#
+# close(PASSWD);
+#
+# &replace("/etc/passwd");
+# }
+#
+# if ($archos eq "solaris2.3") {
+#
+# ## read /etc/shadow
+#
+# open(SHADOW, "/etc/shadow") || die "couldn't open /etc/shadow: $!\n";
+#
+# $shadowok = 0;
+# $chpw = 0;
+# %users = ();
+#
+# while(<SHADOW>) {
+# if (/^([^:]+):([^:]+):/ && $myshadow{$1}) {
+# $users{$1}++;
+# if ($2 ne $myshadow{$1}) {
+# s/^([^:]+):([^:]+):/$1:$myshadow{$1}:/;
+# $chpw++;
+# }
+# }
+# $shadow .= $_;
+# }
+#
+# $shadowok = 1;
+#
+# for (keys %myshadow) {
+# if (!$users{$_}) {
+# $shadow .= "$_:$myshadow{$_}:6445::::::\n";
+# $shadowok = 0;
+# }
+# }
+# close(SHADOW);
+#
+# ## rewrite shadow if necessary.
+#
+# if ($chpw || !$shadowok) {
+# print "Rewriting /etc/shadow...\n" if $verbose;
+#
+# open(SHADOW, ">/etc/shadow.new") ||
+# die "couldn't open /etc/shadow.new: $!\n";
+#
+# print SHADOW $shadow;
+#
+# close(SHADOW);
+#
+# &replace("/etc/shadow");
+# }
+# }
+#
+# if ($archos eq "aix3.2") {
+#
+# ## read /etc/security/passwd
+#
+# open(SHADOW, "/etc/security/passwd") || die "couldn't open /etc/security/passwd: $!\n";
+#
+# $shadowok = 0;
+# %users = ();
+#
+# while(<SHADOW>) {
+# if (/^([^:]+):\s*$/ && $mypass{$1}) {
+# $user = $1;
+# $users{$user}++;
+# # arrange for the user to have a password entry and none other
+# while (<SHADOW>) {
+# last if (!/=/);
+# }
+# $shadow .= "$user:\n\tpassword = KERBEROS5\n\n";
+# } else {
+# $shadow .= $_;
+# }
+# }
+#
+# $shadowok = 1;
+#
+# for (keys %mypass) {
+# if (!$users{$_}) {
+# $shadow .= "$_:\n\tpassword = KERBEROS5\n\n";
+# $shadowok = 0;
+# }
+# }
+# close(SHADOW);
+#
+# ## rewrite shadow if necessary.
+#
+# if (!$shadowok) {
+# print "Rewriting /etc/security/passwd...\n" if $verbose;
+#
+# open(SHADOW, ">/etc/security/passwd.new") ||
+# die "couldn't open /etc/security/passwd.new: $!\n";
+#
+# print SHADOW $shadow;
+#
+# close(SHADOW);
+#
+# &replace("/etc/security/passwd");
+# }
+# }
+#
+# open(SERVICES, "/etc/services") || die "couldn't open /etc/services: $!\n";
+# open(NEW_SERVICES, ">/etc/services.new") ||
+# die "couldn't open /etc/services.new: $!\n";
+#
+# print "Rewriting /etc/services...\n" if $verbose;
+#
+# @needed_services = ('klogin', 'kshell', 'kerberos', 'kerberos-sec',
+# 'kerberos5', 'kerberos4', 'kerberos_master',
+# 'passwd_server', 'eklogin', 'krb5_prop',
+# 'kerberos_adm', 'kerberos-adm');
+# for (@needed_services) {
+# $needed_services{$_}++;
+# }
+#
+# while (<SERVICES>) {
+# m/^\s*([^\#\s][^\s]+)/;
+# if ($needed_services{$1}) {
+# print "+ Commenting out old entry: $1\n" if $verbose;
+# print NEW_SERVICES "# $_";
+# } else {
+# print NEW_SERVICES $_;
+# }
+# }
+#
+# close(SERVICES);
+#
+# print NEW_SERVICES <<EOF || die "writing to /etc/services.new: $!\n";
+#
+# klogin 543/tcp # Kerberos authenticated rlogin
+# kshell 544/tcp cmd # and remote shell
+# kerberos 88/udp kdc # Kerberos authentication--udp
+# kerberos 88/tcp kdc # Kerberos authentication--tcp
+# kerberos-sec 750/udp # Kerberos authentication--udp
+# kerberos-sec 750/tcp # Kerberos authentication--tcp
+# kerberos5 88/udp kdc # Kerberos authentication--udp
+# kerberos5 88/tcp kdc # Kerberos authentication--tcp
+# kerberos4 750/udp # Kerberos authentication--udp
+# kerberos4 750/tcp # Kerberos authentication--tcp
+# kerberos_master 751/udp # Kerberos authentication
+# kerberos_master 751/tcp # Kerberos authentication
+# passwd_server 752/udp # Kerberos passwd server
+# eklogin 2105/tcp # Kerberos encrypted rlogin
+# krb5_prop 754/tcp # Kerberos slave propagation
+# kerberos_adm 752/tcp # Kerberos 5 admin/changepw
+# kerberos-adm 752/tcp # Kerberos 5 admin/changepw
+# EOF
+#
+# close(NEW_SERVICES) || die "error closing /etc/services.new: $!\n";
+#
+# rename("/etc/services", "/etc/services.old") ||
+# die "couldn't rename /etc/services to /etc/services.old: $!\n";
+# rename("/etc/services.new", "/etc/services") ||
+# die "couldn't rename /etc/services.new to /etc/services: $!\n";
+# unlink("/etc/services.old") || die "couldn't unlink /etc/services: $!\n";
+#
diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
new file mode 100644
index 000000000..c53ff96c1
--- /dev/null
+++ b/src/kadmin/testing/scripts/init_db
@@ -0,0 +1,181 @@
+#!/bin/sh
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+if $VERBOSE; then
+ REDIRECT=
+else
+ REDIRECT='>/dev/null'
+fi
+
+# Requires that /krb5, /etc/krb.conf, and .k5.$REALM be world-writeable.
+
+if [ "$TOP" = "" ]; then
+ echo "init_db: Environment variable \$TOP must point to top of build tree" 1>&2
+ exit 1
+fi
+
+IROOT=$TOP/..
+ADMIN=$TOP/create:$IROOT/admin/stash:$IROOT/admin/destroy
+BIN=$IROOT/bin
+ETC=$IROOT/etc
+SBIN=$TOP/keytab:$TOP/server
+DUMMY=${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
+DUMMY=${LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+
+PATH=$ADMIN:$BIN:$ETC:$SBIN:$PATH; export PATH
+
+rm -rf /krb5/*
+if [ -d /krb5 ]; then
+ true
+else
+ mkdir /krb5
+fi
+
+# touch /krb5/syslog
+# for pid in `$PS_ALL | awk '/syslogd/ && !/awk/ {print $2}'` ; do
+# case "$pid" in
+# xxx) ;;
+# *)
+# if $VERBOSE; then $PS_PID$pid | grep -v COMMAND; fi
+# kill -1 $pid
+# ;;
+# esac
+# done
+
+sed -e "s/__REALM__/$REALM/" < $TESTDIR/proto/krb5.conf.proto > /krb5/krb5.conf
+sed -e "s/__REALM__/$REALM/" < $TESTDIR/proto/kdc.conf.proto > /krb5/kdc.conf
+
+kdb5_create -P mrroot -s -r $REALM $REDIRECT
+
+cp $TESTDIR/proto/ovsec_adm.dict /krb5/ovsec_adm.dict
+
+eval $SRVTCL <<'EOF' $REDIRECT
+source $env(TCLUTIL)
+set r $env(REALM)
+
+set cmds {
+ {ovsec_kadm_init $env(SRVTCL) mrroot null $r $OVSEC_KADM_STRUCT_VERSION \
+ $OVSEC_KADM_API_VERSION_1 server_handle}
+
+ {ovsec_kadm_create_policy $server_handle "test-pol 0 10000 8 2 3 0" \
+ {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH OVSEC_KADM_PW_MIN_CLASSES OVSEC_KADM_PW_MAX_LIFE OVSEC_KADM_PW_HISTORY_NUM}}
+ {ovsec_kadm_create_policy $server_handle "once-a-min 30 0 0 0 0 0" \
+ {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE}}
+ {ovsec_kadm_create_policy $server_handle "dict-only 0 0 0 0 0 0" \
+ {OVSEC_KADM_POLICY}}
+ {ovsec_kadm_create_policy $server_handle [simple_policy test-pol-nopw] \
+ {OVSEC_KADM_POLICY}}
+
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal testuser@$r] {OVSEC_KADM_PRINCIPAL} notathena}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal test1@$r] {OVSEC_KADM_PRINCIPAL} test1}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal test2@$r] {OVSEC_KADM_PRINCIPAL} test2}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal test3@$r] {OVSEC_KADM_PRINCIPAL} test3}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/get@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/modify@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/delete@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/none@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/rename@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/mod-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/mod-delete@$r] {OVSEC_KADM_PRINCIPAL} \
+ admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/get-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/get-delete@$r] {OVSEC_KADM_PRINCIPAL} \
+ admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/get-mod@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/no-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal admin/no-delete@$r] {OVSEC_KADM_PRINCIPAL} admin}
+ {ovsec_kadm_create_principal $server_handle \
+ [princ_w_pol pol1@$r test-pol] {OVSEC_KADM_PRINCIPAL \
+ OVSEC_KADM_POLICY} pol111111}
+ {ovsec_kadm_create_principal $server_handle \
+ [princ_w_pol pol2@$r once-a-min] {OVSEC_KADM_PRINCIPAL \
+ OVSEC_KADM_POLICY} pol222222}
+ {ovsec_kadm_create_principal $server_handle \
+ [princ_w_pol pol3@$r dict-only] {OVSEC_KADM_PRINCIPAL \
+ OVSEC_KADM_POLICY} pol333333}
+ {ovsec_kadm_create_principal $server_handle \
+ [princ_w_pol admin/get-pol@$r test-pol-nopw] \
+ {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} StupidAdmin}
+ {ovsec_kadm_create_principal $server_handle \
+ [princ_w_pol admin/pol@$r test-pol-nopw] {OVSEC_KADM_PRINCIPAL \
+ OVSEC_KADM_POLICY} StupidAdmin}
+
+ {ovsec_kadm_create_principal $server_handle \
+ [simple_principal changepw/kerberos] \
+ {OVSEC_KADM_PRINCIPAL} {XXX THIS IS WRONG}}
+
+ {ovsec_kadm_destroy $server_handle}
+}
+
+foreach cmd $cmds {
+ if {[catch $cmd output]} {
+ puts stderr "Error! Command: $cmd\nError: $output"
+ exit 1
+ } else {
+ puts stdout $output
+ }
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ echo "Error in $SRVTCL!" 1>&2
+ exit 1
+fi
+
+cat > /krb5/ovsec_adm.acl <<EOF
+admin@$REALM admcil
+admin/get@$REALM il
+admin/modify@$REALM mc
+admin/delete@$REALM d
+admin/add@$REALM a
+admin/get-pol@$REALM il
+admin/rename@$REALM adil
+admin/mod-add@$REALM amc
+admin/mod-delete@$REALM mcd
+admin/get-add@$REALM ail
+admin/get-delete@$REALM ild
+admin/get-mod@$REALM ilmc
+admin/no-add@$REALM mcdil
+admin/no-delete@$REALM amcil
+changepw/kerberos@$REALM cil
+
+EOF
+
+eval $LOCAL_MAKE_KEYTAB -princ kadmin/admin -princ kadmin/changepw -princ ovsec_adm/admin -princ ovsec_adm/changepw /krb5/ovsec_adm.srvtab $REDIRECT
+
+# Create /krb5/setup.csh to make it easy to run other programs against
+# the test db
+cat > /krb5/setup.csh <<EOF
+setenv KRB5_CONFIG $KRB5_CONFIG
+setenv KRB5_KDC_PROFILE $KRB5_KDC_PROFILE
+setenv KRB5_KTNAME $KRB5_KTNAME
+EOF
+
diff --git a/src/kadmin/testing/scripts/make-host-keytab.pl.in b/src/kadmin/testing/scripts/make-host-keytab.pl.in
new file mode 100644
index 000000000..14d7b10b5
--- /dev/null
+++ b/src/kadmin/testing/scripts/make-host-keytab.pl.in
@@ -0,0 +1,138 @@
+#!/usr/local/bin/perl
+
+$server = undef;
+@princs = ();
+$top = undef;
+
+($whoami = $0) =~ s,.*/,,;
+$usage = "Usage: $whoami [ -server server ] [ -princ principal ]
+ [ -top dirname ] [ -verbose ] filename
+ Server defaults to the local host.
+ Default principals are host/hostname\@SECURE-TEST.OV.COM and
+ test/hostname\@SECURE-TEST.OV.COM.
+ If any principals are specified, the default principals are
+ not added to the srvtab.
+ The string \"xCANONHOSTx\" in a principal specification will be
+ replaced by the canonical host name of the local host.";
+
+@ORIG_ARGV = @ARGV;
+
+while (($_ = $ARGV[0]) && /^-/) {
+ shift;
+ if (/^-server$/) {
+ ($server = shift) || die "Missing argument to $_ option.\n$usage\n";
+ }
+ elsif (/^-princ$/) {
+ ($princ = shift) || die "Missing argument to $_ option.\n$usage\n";
+ push(@princs, $princ);
+ }
+ elsif (/^-top$/) {
+ ($top = shift) || die "Missing argument to $_ option.\n$usage\n";
+ }
+ elsif (/^-verbose$/) {
+ $verbose++;
+ }
+ elsif (/^--$/) {
+ last;
+ }
+ else {
+ die "Unknown option $_.\n$usage\n";
+ }
+}
+
+@princs = ("host/xCANONHOSTx\@SECURE-TEST.OV.COM",
+ "test/xCANONHOSTx\@SECURE-TEST.OV.COM")
+ if (! @princs);
+
+$ktfile = shift(@ARGV) || die "need a keytab file\n";
+
+$verbose++ if ($ENV{'VERBOSE_TEST'});
+
+print "In $0 @ORIG_ARGV...\n" if ($verbose);
+
+chop ($canonhost = `hostname`);
+
+($canonhost,$aliases,$addrtype,$length,@addrs) = gethostbyname($canonhost);
+die "couldn't get canonical hostname\n" if !($canonhost && @addrs);
+($canonhost) = gethostbyaddr($addrs[0],$addrtype);
+die "couldn't get canonical hostname\n" if (!$canonhost);
+
+for (@princs) {
+ s/xCANONHOSTx/$canonhost/g;
+}
+
+die "Neither \$TOP nor \$TESTDIR is set, and -top not specified.\n"
+ if (! ($top || $ENV{'TOP'} || $ENV{'TESTDIR'}));
+
+$top = $ENV{'TOP'} if (! $top);
+$TESTDIR = ($ENV{'TESTDIR'} || "$top/testing");
+$MAKE_KEYTAB = ($ENV{'MAKE_KEYTAB'} || "$TESTDIR/scripts/$whoami");
+$SRVTCL = ($ENV{'SRVTCL'} || "$TESTDIR/util/ovsec_kadm_srv_tcl");
+$TCLUTIL = ($ENV{'TCLUTIL'} || "$TESTDIR/tcl/util.t");
+# This'll be wrong sometimes
+$RSH_CMD = ($ENV{'RSH_CMD'} || '/usr/ucb/rsh');
+$EDIT_KEYTAB = ($ENV{'EDIT_KEYTAB'} || "$top/keytab/kadm5_keytab.local");
+
+if ($server) {
+# XXX Using /usr/ucb/rsh for now.
+
+# Strip command line options because we're adding our own.
+
+ $MAKE_KEYTAB =~ s/ .*//;
+
+ if ($ENV{'TOP'} && ($top ne $ENV{'TOP'})) {
+# Replace the old TOP with the new one where necessary
+ for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+ eval "\$$_ =~ s/^\$ENV{'TOP'}/\$top/;";
+ }
+
+# Make the paths as short as possible so our command line isn't too long.
+# for ('SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+# eval "\$$_ =~ s/^\$TESTDIR/\\\\\\\$TESTDIR/;";
+# }
+# for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+# eval "\$$_ =~ s/^\$top/\\\\\\\$TOP/;";
+# }
+ }
+
+ $cmd = "cd $top; \\`testing/scripts/find-make.sh\\` execute TOP=$top ";
+ $cmd .= "VERBOSE_TEST=$verbose " if ($verbose);
+ $cmd .= "TESTDIR=$TESTDIR ";
+ $cmd .= "SRVTCL=$SRVTCL ";
+ $cmd .= "TCLUTIL=$TCLUTIL ";
+
+ $cmd .= "CMD='$MAKE_KEYTAB ";
+ for (@princs) {
+ $cmd .= "-princ $_ ";
+ }
+ $cmd .= " /tmp/make-keytab.$canonhost.$$'";#';
+
+ $cmd = "$RSH_CMD $server -l root -n \"$cmd\"";
+
+ $cmd2 = "$RSH_CMD $server -l root -n \"cat /tmp/make-keytab.$canonhost.$$\" > $ktfile";
+
+ $cmd3 = "$RSH_CMD $server -l root -n \"rm /tmp/make-keytab.$canonhost.$$\"";
+
+ for ($cmd, $cmd2, $cmd3) {
+ print "$_\n" if ($verbose);
+
+ system($_) && die "Couldn't run $_: $!.\n";
+ }
+}
+else {
+ $redirect = "> /dev/null" if (! $verbose);
+
+ $cmd = "$EDIT_KEYTAB -k $ktfile";
+ $cmd .= " -q" if (! $verbose);
+ $cmd .= " -a -c";
+ for (@princs) {
+ if (system "$cmd $_") {
+ sleep(1);
+ die "Error in system($cmd $_)\n";
+ }
+ }
+}
+
+if (! -f $ktfile) {
+ die "$ktfile not created.\n";
+}
diff --git a/src/kadmin/testing/scripts/make-host-keytab.plin b/src/kadmin/testing/scripts/make-host-keytab.plin
new file mode 100644
index 000000000..14d7b10b5
--- /dev/null
+++ b/src/kadmin/testing/scripts/make-host-keytab.plin
@@ -0,0 +1,138 @@
+#!/usr/local/bin/perl
+
+$server = undef;
+@princs = ();
+$top = undef;
+
+($whoami = $0) =~ s,.*/,,;
+$usage = "Usage: $whoami [ -server server ] [ -princ principal ]
+ [ -top dirname ] [ -verbose ] filename
+ Server defaults to the local host.
+ Default principals are host/hostname\@SECURE-TEST.OV.COM and
+ test/hostname\@SECURE-TEST.OV.COM.
+ If any principals are specified, the default principals are
+ not added to the srvtab.
+ The string \"xCANONHOSTx\" in a principal specification will be
+ replaced by the canonical host name of the local host.";
+
+@ORIG_ARGV = @ARGV;
+
+while (($_ = $ARGV[0]) && /^-/) {
+ shift;
+ if (/^-server$/) {
+ ($server = shift) || die "Missing argument to $_ option.\n$usage\n";
+ }
+ elsif (/^-princ$/) {
+ ($princ = shift) || die "Missing argument to $_ option.\n$usage\n";
+ push(@princs, $princ);
+ }
+ elsif (/^-top$/) {
+ ($top = shift) || die "Missing argument to $_ option.\n$usage\n";
+ }
+ elsif (/^-verbose$/) {
+ $verbose++;
+ }
+ elsif (/^--$/) {
+ last;
+ }
+ else {
+ die "Unknown option $_.\n$usage\n";
+ }
+}
+
+@princs = ("host/xCANONHOSTx\@SECURE-TEST.OV.COM",
+ "test/xCANONHOSTx\@SECURE-TEST.OV.COM")
+ if (! @princs);
+
+$ktfile = shift(@ARGV) || die "need a keytab file\n";
+
+$verbose++ if ($ENV{'VERBOSE_TEST'});
+
+print "In $0 @ORIG_ARGV...\n" if ($verbose);
+
+chop ($canonhost = `hostname`);
+
+($canonhost,$aliases,$addrtype,$length,@addrs) = gethostbyname($canonhost);
+die "couldn't get canonical hostname\n" if !($canonhost && @addrs);
+($canonhost) = gethostbyaddr($addrs[0],$addrtype);
+die "couldn't get canonical hostname\n" if (!$canonhost);
+
+for (@princs) {
+ s/xCANONHOSTx/$canonhost/g;
+}
+
+die "Neither \$TOP nor \$TESTDIR is set, and -top not specified.\n"
+ if (! ($top || $ENV{'TOP'} || $ENV{'TESTDIR'}));
+
+$top = $ENV{'TOP'} if (! $top);
+$TESTDIR = ($ENV{'TESTDIR'} || "$top/testing");
+$MAKE_KEYTAB = ($ENV{'MAKE_KEYTAB'} || "$TESTDIR/scripts/$whoami");
+$SRVTCL = ($ENV{'SRVTCL'} || "$TESTDIR/util/ovsec_kadm_srv_tcl");
+$TCLUTIL = ($ENV{'TCLUTIL'} || "$TESTDIR/tcl/util.t");
+# This'll be wrong sometimes
+$RSH_CMD = ($ENV{'RSH_CMD'} || '/usr/ucb/rsh');
+$EDIT_KEYTAB = ($ENV{'EDIT_KEYTAB'} || "$top/keytab/kadm5_keytab.local");
+
+if ($server) {
+# XXX Using /usr/ucb/rsh for now.
+
+# Strip command line options because we're adding our own.
+
+ $MAKE_KEYTAB =~ s/ .*//;
+
+ if ($ENV{'TOP'} && ($top ne $ENV{'TOP'})) {
+# Replace the old TOP with the new one where necessary
+ for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+ eval "\$$_ =~ s/^\$ENV{'TOP'}/\$top/;";
+ }
+
+# Make the paths as short as possible so our command line isn't too long.
+# for ('SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+# eval "\$$_ =~ s/^\$TESTDIR/\\\\\\\$TESTDIR/;";
+# }
+# for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+# eval "\$$_ =~ s/^\$top/\\\\\\\$TOP/;";
+# }
+ }
+
+ $cmd = "cd $top; \\`testing/scripts/find-make.sh\\` execute TOP=$top ";
+ $cmd .= "VERBOSE_TEST=$verbose " if ($verbose);
+ $cmd .= "TESTDIR=$TESTDIR ";
+ $cmd .= "SRVTCL=$SRVTCL ";
+ $cmd .= "TCLUTIL=$TCLUTIL ";
+
+ $cmd .= "CMD='$MAKE_KEYTAB ";
+ for (@princs) {
+ $cmd .= "-princ $_ ";
+ }
+ $cmd .= " /tmp/make-keytab.$canonhost.$$'";#';
+
+ $cmd = "$RSH_CMD $server -l root -n \"$cmd\"";
+
+ $cmd2 = "$RSH_CMD $server -l root -n \"cat /tmp/make-keytab.$canonhost.$$\" > $ktfile";
+
+ $cmd3 = "$RSH_CMD $server -l root -n \"rm /tmp/make-keytab.$canonhost.$$\"";
+
+ for ($cmd, $cmd2, $cmd3) {
+ print "$_\n" if ($verbose);
+
+ system($_) && die "Couldn't run $_: $!.\n";
+ }
+}
+else {
+ $redirect = "> /dev/null" if (! $verbose);
+
+ $cmd = "$EDIT_KEYTAB -k $ktfile";
+ $cmd .= " -q" if (! $verbose);
+ $cmd .= " -a -c";
+ for (@princs) {
+ if (system "$cmd $_") {
+ sleep(1);
+ die "Error in system($cmd $_)\n";
+ }
+ }
+}
+
+if (! -f $ktfile) {
+ die "$ktfile not created.\n";
+}
diff --git a/src/kadmin/testing/scripts/qualname b/src/kadmin/testing/scripts/qualname
new file mode 100644
index 000000000..3d047c550
--- /dev/null
+++ b/src/kadmin/testing/scripts/qualname
@@ -0,0 +1,18 @@
+#!/afs/athena/contrib/perl/p
+
+if ($#ARGV == -1) {
+ chop($hostname = `hostname`);
+} else {
+ $hostname = $ARGV[0];
+}
+
+if (! (($type,$addr) = (gethostbyname($hostname))[2,4])) {
+ print STDERR "No such host: $hostname\n";
+ exit(1);
+}
+if (! ($qualname = (gethostbyaddr($addr,$type))[0])) {
+ print STDERR "No address information for host $hostname\n";
+ exit(1);
+}
+print "$qualname\n";
+
diff --git a/src/kadmin/testing/scripts/save_files.sh b/src/kadmin/testing/scripts/save_files.sh
new file mode 100644
index 000000000..b9fc37319
--- /dev/null
+++ b/src/kadmin/testing/scripts/save_files.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+while [ $# -gt 0 ] ; do
+ case $1 in
+ -start_servers)
+ start_servers=$1
+ ;;
+ esac
+ shift
+done
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+# files="/etc/inetd.conf /etc/syslog.conf /etc/krb.conf \
+# /etc/krb.realms /etc/passwd /etc/services /etc/v5srvtab \
+# /etc/rc.local /etc/shadow /etc/security/passwd /.k5login \
+# /.secure/etc/passwd /etc/athena/inetd.conf"
+
+files="/etc/krb.conf /etc/krb.realms /etc/athena/krb.conf \
+ /etc/athena/krb.realms /etc/v5srvtab"
+
+name=`basename $0`
+
+make_dne_name()
+{
+ dne_name="/tmp/"`echo $1 | sed -e 's,/,#,g'`".did-not-exist"
+}
+
+for f in $files ; do
+ if [ "$name" = "save_files.sh" ]; then
+ if [ -f $f.pre-secure ]; then
+ if $VERBOSE; then
+ echo "Warning! $f.pre-secure exists, not saving."
+ fi
+ elif [ ! -f $f ]; then
+ make_dne_name $f
+ cp /dev/null $dne_name
+ else
+ cp $f $f.pre-secure
+ fi
+ else
+ make_dne_name $f
+ if [ -f $dne_name ]; then
+ rm -f $f $dne_name
+ elif [ ! -f $f.pre-secure ]; then
+ if [ "x$start_servers" = "x" ]; then
+ echo "Warning! $f.pre-secure does not exist!" 1>&2
+ fi
+ else
+ if cp $f.pre-secure $f; then
+ rm $f.pre-secure
+ else
+ echo "Warning! cp failed!" 1>&2
+ fi
+ fi
+ fi
+done
+
+# DUMMY=${INETD:=/etc/inetd}
+# if $VERBOSE; then
+# echo "Killing and restarting $INETD"
+# fi
+# kill `$PS_ALL | awk '/inetd/ && !/awk/ {print $2}'`
+# $INETD
diff --git a/src/kadmin/testing/scripts/simple_dump.pl.in b/src/kadmin/testing/scripts/simple_dump.pl.in
new file mode 100644
index 000000000..ea94ab2d1
--- /dev/null
+++ b/src/kadmin/testing/scripts/simple_dump.pl.in
@@ -0,0 +1,88 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+## ovsec_adm_export format
+## [0]"policy" [1]name [2]pw_min_life [3]pw_max_life [4]pw_min_length [5]pw_min_classes [6]pw_history_num [7]policy_refcnt
+## [0]"princ" [1]name [2]policy [3]aux_attributes [4]old_key_len [5]admin_history_kvno [6..]old_keys
+$oaevers = "1.0";
+
+open(SORT, "|sort") || die "Couldn't open pipe to sort for output: $!\n";
+
+open(OAE, "$ENV{'TOP'}/install/admin/ovsec_adm_export|") ||
+ die "Couldn't get oae: $!\n";
+
+$header = <OAE>;
+
+die "Not ovsec_adm_export output\n"
+ if ($header !~ /^OpenV\*Secure V(\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected oae version $oaevers, got $stdinvers instead.\n"
+ if $stdinvers ne $oaevers;
+
+while(<OAE>) {
+ if (/^End of Database/) {
+ last;
+ } elsif (/^policy/) {
+ print SORT;
+ } elsif (/^princ/) {
+ split(/\t/);
+
+ $_[2] = "\"\"" if !$_[2];
+
+ $_[3] = hex("0x".$_[3]);
+
+ $princ{$_[1]} = sprintf("%s\t0x%04x",@_[2,3]);
+ }
+}
+
+## kdb_edit ddb format
+## [0]strlen(principal) [1]strlen(mod_name) [2]key.length [3]alt_key.length [4]salt_length [5]alt_salt_length [6]principal [7]key.key_type [8]key.contents [9]kvno [10]max_life [11]max_renewable_life [12]mkvno [13]expiration [14]pw_expiration [15]last_pwd_change [16]last_success [17]last_failed [18]fail_auth_count [19]mod_name [20]mod_date [21]attributes [22]salt_type [23]salt [24]alt_key.contents [25]alt_salt [26..33]expansion*8;
+$ddbvers = "2.0";
+
+open(DDB, "$ENV{'TOP'}/install/admin/kdb5_edit -r SECURE-TEST.OV.COM -R ddb|") ||
+ die "Couldn't get ddb: $!\n";
+
+$header = <DDB>;
+
+die "Not a kdb5_edit ddb\n"
+ if ($header !~ /^kdb5_edit load_dump version (\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected ddb version $ddbvers, got $stdinvers instead.\n"
+ if $stdinvers ne $ddbvers;
+
+## [6]principal [9]kvno [19]mod_name [10]max_life [13]expiration [14]pw_expiration [21]attributes // [2]policy [3]aux_attributes
+
+while(<DDB>) {
+ split;
+
+ print SORT join("\t","princ",(@_)[6,9,19,10,13,14],
+ sprintf("0x%04x",$_[21]),
+ $princ{$_[6]}),"\n";
+}
+
+close(DDB);
+
+for $keytab (@ARGV) {
+ open(KLIST, "$ENV{'TOP'}/install/bin/klist -k -t -K FILE:$keytab|") ||
+ die "Couldn't list $keytab: $!\n";
+
+ $dummy = <KLIST>;
+ $dummy = <KLIST>;
+ $dummy = <KLIST>;
+
+ while(<KLIST>) {
+ s/^\s+//;
+ split;
+ printf(SORT "keytab:FILE:%s\t%s-%s\t%s\t%s,%s\n",$keytab,
+ @_[3,0,4,1,2]);
+ }
+}
+
+close(SORT);
diff --git a/src/kadmin/testing/scripts/simple_dump.plin b/src/kadmin/testing/scripts/simple_dump.plin
new file mode 100644
index 000000000..ea94ab2d1
--- /dev/null
+++ b/src/kadmin/testing/scripts/simple_dump.plin
@@ -0,0 +1,88 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+## ovsec_adm_export format
+## [0]"policy" [1]name [2]pw_min_life [3]pw_max_life [4]pw_min_length [5]pw_min_classes [6]pw_history_num [7]policy_refcnt
+## [0]"princ" [1]name [2]policy [3]aux_attributes [4]old_key_len [5]admin_history_kvno [6..]old_keys
+$oaevers = "1.0";
+
+open(SORT, "|sort") || die "Couldn't open pipe to sort for output: $!\n";
+
+open(OAE, "$ENV{'TOP'}/install/admin/ovsec_adm_export|") ||
+ die "Couldn't get oae: $!\n";
+
+$header = <OAE>;
+
+die "Not ovsec_adm_export output\n"
+ if ($header !~ /^OpenV\*Secure V(\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected oae version $oaevers, got $stdinvers instead.\n"
+ if $stdinvers ne $oaevers;
+
+while(<OAE>) {
+ if (/^End of Database/) {
+ last;
+ } elsif (/^policy/) {
+ print SORT;
+ } elsif (/^princ/) {
+ split(/\t/);
+
+ $_[2] = "\"\"" if !$_[2];
+
+ $_[3] = hex("0x".$_[3]);
+
+ $princ{$_[1]} = sprintf("%s\t0x%04x",@_[2,3]);
+ }
+}
+
+## kdb_edit ddb format
+## [0]strlen(principal) [1]strlen(mod_name) [2]key.length [3]alt_key.length [4]salt_length [5]alt_salt_length [6]principal [7]key.key_type [8]key.contents [9]kvno [10]max_life [11]max_renewable_life [12]mkvno [13]expiration [14]pw_expiration [15]last_pwd_change [16]last_success [17]last_failed [18]fail_auth_count [19]mod_name [20]mod_date [21]attributes [22]salt_type [23]salt [24]alt_key.contents [25]alt_salt [26..33]expansion*8;
+$ddbvers = "2.0";
+
+open(DDB, "$ENV{'TOP'}/install/admin/kdb5_edit -r SECURE-TEST.OV.COM -R ddb|") ||
+ die "Couldn't get ddb: $!\n";
+
+$header = <DDB>;
+
+die "Not a kdb5_edit ddb\n"
+ if ($header !~ /^kdb5_edit load_dump version (\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected ddb version $ddbvers, got $stdinvers instead.\n"
+ if $stdinvers ne $ddbvers;
+
+## [6]principal [9]kvno [19]mod_name [10]max_life [13]expiration [14]pw_expiration [21]attributes // [2]policy [3]aux_attributes
+
+while(<DDB>) {
+ split;
+
+ print SORT join("\t","princ",(@_)[6,9,19,10,13,14],
+ sprintf("0x%04x",$_[21]),
+ $princ{$_[6]}),"\n";
+}
+
+close(DDB);
+
+for $keytab (@ARGV) {
+ open(KLIST, "$ENV{'TOP'}/install/bin/klist -k -t -K FILE:$keytab|") ||
+ die "Couldn't list $keytab: $!\n";
+
+ $dummy = <KLIST>;
+ $dummy = <KLIST>;
+ $dummy = <KLIST>;
+
+ while(<KLIST>) {
+ s/^\s+//;
+ split;
+ printf(SORT "keytab:FILE:%s\t%s-%s\t%s\t%s,%s\n",$keytab,
+ @_[3,0,4,1,2]);
+ }
+}
+
+close(SORT);
diff --git a/src/kadmin/testing/scripts/start_servers b/src/kadmin/testing/scripts/start_servers
new file mode 100644
index 000000000..2e395faf8
--- /dev/null
+++ b/src/kadmin/testing/scripts/start_servers
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Usage: start_servers [hostname [path]]
+#
+# This script turns a host into a OpenV*Secure primary server for the
+# realm SECURE-TEST.OV.COM. If no arguments are specified,
+# the local host is affected. Otherwise, the host hostname is
+# affected; the path argument is the top of the Secure install tree on
+# that host, and if it is not specified the current canonical value of
+# TOP is used.
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${SAVE_FILES=$TESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${START_SERVERS_LOCAL=$TESTDIR/scripts/start_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=/usr/ucb/rsh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+local=1
+
+if [ $# -gt 0 ]; then
+ if [ $# != 1 -a $# != 2 ]; then
+ echo "Usage: $0 [hostname [path]]" 1>&2
+ exit 1
+ fi
+
+ local=0
+ hostname=$1
+ if [ $# = 1 ]; then
+ rempath=`sh -c "cd $TOP && pwd"`
+ else
+ rempath=$2
+ fi
+fi
+
+if [ $local = 0 ]; then
+ $SAVE_FILES || exit 1
+ $FIX_CONF_FILES -server $hostname || exit 1
+
+# Using /usr/ucb/rsh and getting rid of "-k $REALM" until we get
+# around to fixing the fact that Kerberos rsh doesn't strip out "-k
+# REALM" when falling back.
+
+ START_SERVERS_LOCAL=`echo $START_SERVERS_LOCAL|sed "s%$TOP%$rempath%"`
+ CMD="$RSH_CMD $hostname -l root -n \
+ \"cd $rempath; \\\`testing/scripts/find-make.sh\\\` execute VERBOSE_TEST=$VERBOSE_TEST \
+ TOP=$rempath \
+ CMD='$START_SERVERS_LOCAL $rempath'\""
+
+ if $VERBOSE; then
+ echo "+++"
+ echo "+++ Begin execution of start_servers_local on $hostname"
+ echo "+++"
+ echo $CMD
+ fi
+ eval $CMD
+ if $VERBOSE; then
+ echo "+++"
+ echo "+++ End execution of start_servers_local on $hostname"
+ echo "+++"
+ fi
+else
+ $START_SERVERS_LOCAL
+fi
+
diff --git a/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
new file mode 100644
index 000000000..a9c8e7957
--- /dev/null
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -0,0 +1,196 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${SAVE_FILES=$TESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${INITDB=$TESTDIR/scripts/init_db}
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+DUMMY=${STOP_SERVERS_LOCAL=$TESTDIR/scripts/stop_servers_local}
+
+if [ -d /usr/tmp ]; then
+ usrtmp=/usr/tmp
+else
+ usrtmp=/var/tmp
+fi
+
+$STOP_SERVERS_LOCAL -start_servers
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+if $VERBOSE; then
+ REDIRECT=
+else
+ REDIRECT='>/dev/null'
+fi
+
+v4files=false
+while :; do
+ case $1 in
+ -keysalt)
+ shift
+ if [ $# -gt 0 ]; then
+ keysalts="$keysalts $1"
+ else
+ break
+ fi
+ ;;
+ -kdcport)
+ shift
+ if [ $# -gt 0 ]; then
+ kdcport=$1
+ else
+ break
+ fi
+ ;;
+ -v4files)
+ if [ "`whoami`" != "root" ]; then
+ echo "You must be root to use -v4files!" 1>&2
+ exit 1
+ fi
+ v4files=true
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
+if [ $# -gt 1 ]; then
+ echo "Usage: $0 [-kdcport port] [-keysalts tuple] ... [top]" 1>&2
+ exit 1
+elif [ $# = 1 ]; then
+ TOP=$1
+ export TOP
+fi
+
+# fixup the system config files
+if $v4files; then
+ $SAVE_FILES || exit 1
+ $FIX_CONF_FILES || exit 1
+fi
+
+# create a fresh db
+
+$INITDB "$keysalts" || exit 1
+
+# Post-process the config files based on our arguments
+if [ "$keysalts" != "" ]; then
+ sedcmd="s/\([ ]*supported_enctypes =\).*/\1 $keysalts/"
+ sed -e "$sedcmd" < /krb5/kdc.conf > /krb5/kdc.conf.new
+ mv /krb5/kdc.conf.new /krb5/kdc.conf
+fi
+if [ "$kdcport" != "" ] ; then
+ sedcmd="s/\(kdc_ports = .*\)[ ]*/\1, $kdcport/"
+ sed -e "$sedcmd" < /krb5/kdc.conf > /krb5/kdc.conf.new
+ mv /krb5/kdc.conf.new /krb5/kdc.conf
+fi
+
+# allow admin to krlogin as root (for cleanup)
+DUMMY=${REALM=SECURE-TEST.OV.COM}; export REALM
+hostname=`hostname`
+QUALNAME=`$TOP/testing/scripts/qualname $hostname`; export QUALNAME
+
+eval $SRVTCL <<'EOF' $REDIRECT
+source $env(TOP)/testing/tcl/util.t
+set r $env(REALM)
+set q $env(QUALNAME)
+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_principal $server_handle \
+ [simple_principal host/$q@$r] {OVSEC_KADM_PRINCIPAL} notathena]
+puts stdout [ovsec_kadm_destroy $server_handle]
+EOF
+
+# rm -f /etc/v5srvtab
+# eval $LOCAL_MAKE_KEYTAB -princ host/xCANONHOSTx /etc/v5srvtab $REDIRECT
+
+# run the servers (from the build tree)
+
+adm_start_file=/tmp/adm_server_start.$$
+kdc_start_file=/tmp/kdc_server_start.$$
+
+rm -f $kdc_start_file
+
+(trap "" 2; cd $TOP/../kdc; ./krb5kdc; touch $kdc_start_file) \
+ < /dev/null > $usrtmp/kdc-log 2>&1 &
+
+s=10
+max_s=60
+sofar_s=0
+timewait_s=300
+
+while true; do
+ rm -f $adm_start_file
+
+ (sleep 5; cd $TOP/server; ./kadmind $ovadm_args; \
+ touch $adm_start_file) < /dev/null > $usrtmp/kadm-log 2>&1 &
+
+ # wait until they start
+
+ while [ $sofar_s -le $max_s ]; do
+ if $VERBOSE; then
+ echo "Sleeping for $s seconds to allow servers" \
+ "to start..."
+ fi
+
+ sofar_s=`expr $sofar_s + $s`
+
+ sleep $s
+
+ if [ -f $adm_start_file -a -f $kdc_start_file ]; then
+ break
+ fi
+
+ done
+
+ if [ $sofar_s -le $max_s ]; then
+ if $VERBOSE; then
+ LOG_USER='log_user 1'
+ else
+ LOG_USER='log_user 0'
+ fi
+ if expect <<EOF
+ $LOG_USER
+ spawn telnet localhost 1751
+ expect {
+ "Connection refused" {
+ close
+ wait
+ exit 1
+ }
+ "Connected" {
+ send "close\n"
+ close
+ wait
+ exit 0
+ }
+ default {
+ catch {close}
+ wait
+ exit 1
+ }
+ }
+EOF
+ then
+ rm -f $kdc_start_file $adm_start_file
+ break
+ else
+ if $VERBOSE; then
+ echo "Could not connect to Admin server;" \
+ "attempting restart ($sofar_s" \
+ "seconds so far)."
+ fi
+ max_s=$timewait_s
+ continue
+ fi
+ else
+ echo "Admin server or KDC failed to start after $sofar_s" \
+ "seconds." 1>&2
+ exit 1
+ fi
+done
diff --git a/src/kadmin/testing/scripts/stop_servers b/src/kadmin/testing/scripts/stop_servers
new file mode 100644
index 000000000..fc5372dd4
--- /dev/null
+++ b/src/kadmin/testing/scripts/stop_servers
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Usage: stop_servers [hostname [path]]
+#
+# This script turns a host into a OpenV*Secure primary server for the
+# realm SECURE-TEST.OV.COM. If no arguments are specified,
+# the local host is affected. Otherwise, the host hostname is
+# affected; the path argument is the top of the Secure install tree on
+# that host, and if it is not specified the current canonical value of
+# TOP is used.
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${STOP_SERVERS_LOCAL=$TESTDIR/scripts/stop_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=/usr/ucb/rsh}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+local=1
+
+if [ $# -gt 0 ]; then
+ if [ $# != 1 -a $# != 2 ]; then
+ echo "Usage: $0 [hostname [path]]" 1>&2
+ exit 1
+ fi
+
+ local=0
+ hostname=$1
+ if [ $# = 1 ]; then
+ rempath=`sh -c "cd $TOP && pwd"`
+ else
+ rempath=$2
+ fi
+fi
+
+if [ $local = 0 ]; then
+ if $VERBOSE; then
+ echo "+++ Stopping servers on remote host $hostname..."
+ fi
+
+# $FIX_CONF_FILES -server $hostname
+#
+# KRB5CCNAME=FILE:/tmp/krb5cc_stop_servers; export KRB5CCNAME
+#
+# expect <<EOF
+#spawn kinit admin
+#expect {
+# -re "Password for admin@SECURE-TEST.OV.COM" {
+# send "admin\n"
+# }
+#}
+#expect { eof { } }
+#EOF
+
+# Using /usr/ucb/rsh and getting rid of "-k REALM" until we get around
+# to fixing the fact that Kerberos rsh doesn't strip out "-k REALM"
+# when falling back.
+
+ STOP_SERVERS_LOCAL=`echo $STOP_SERVERS_LOCAL | sed "s%$TOP%$rempath%"`
+ CMD="$RSH_CMD $hostname -l root -n\
+ \"cd $rempath; \\\`testing/scripts/find-make.sh\\\` execute VERBOSE_TEST=$VERBOSE_TEST \
+ TOP=$rempath \
+ CMD='$STOP_SERVERS_LOCAL $rempath'\""
+ if $VERBOSE; then
+ echo "+++"
+ echo "+++ Begin execution of stop_servers_local on $hostname"
+ echo "+++"
+ echo $CMD
+ fi
+ eval $CMD
+ if $VERBOSE; then
+ echo "+++"
+ echo "+++ End execution of stop_servers_local on $hostname"
+ echo "+++"
+ fi
+ $RESTORE_FILES
+else
+ $STOP_SERVERS_LOCAL
+fi
diff --git a/src/kadmin/testing/scripts/stop_servers_local b/src/kadmin/testing/scripts/stop_servers_local
new file mode 100644
index 000000000..c0a97ef27
--- /dev/null
+++ b/src/kadmin/testing/scripts/stop_servers_local
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+
+# If it's set, set it to true
+VERBOSE=${VERBOSE_TEST:+true}
+# Otherwise, set it to false
+DUMMY=${VERBOSE:=false}
+
+v4files=false
+while [ $# -gt 0 ] ; do
+ case $1 in
+ -start_servers)
+ start_servers=$1
+ ;;
+ -v4files)
+ v4files=true
+ ;;
+ *)
+ TOP=$1
+ export TOP
+ ;;
+ esac
+ shift
+done
+
+# kill any running servers.
+
+if $VERBOSE; then echo "Killing servers:"; fi
+
+for pid in xxx \
+ `$PS_ALL | grep krb5kdc | grep -v grep | awk '{print $2}'` \
+ `$PS_ALL | grep kadmind | grep -v grep | awk '{print $2}'` \
+ ; do
+ case "$pid" in
+ xxx)
+ ;;
+ *)
+ if $VERBOSE; then $PS_PID$pid | grep -v COMMAND; fi
+ kill $pid
+ ;;
+ esac
+done
+
+# restore saved system config files
+if $v4files; then
+ $RESTORE_FILES $start_servers
+fi
diff --git a/src/kadmin/testing/scripts/verify_xrunner_report.pl.in b/src/kadmin/testing/scripts/verify_xrunner_report.pl.in
new file mode 100644
index 000000000..9d83c3ea2
--- /dev/null
+++ b/src/kadmin/testing/scripts/verify_xrunner_report.pl.in
@@ -0,0 +1,38 @@
+#!/usr/local/bin/perl
+
+sub usage { die "usage: $0 reportfile\n"; }
+
+$report = shift(@ARGV) || die &usage;
+
+open(REPORT, $report) || die "Couldn't open $report: $!\n";
+
+while(<REPORT>) {
+ if (/Process termination:/ && !/\bOK\b/) {
+ warn "Process termination not OK\n";
+ $warnings++;
+ } elsif (/Number of detected mismatches:\s*(\d+)/ && ($1 ne "0")) {
+ warn "Number of detected mismatches = $1\n";
+ $warnings++;
+ } elsif (/Detailed Results Description/) {
+ break;
+ }
+}
+
+while(<REPORT>) {
+ next if !/^\d+\s+/;
+
+ split;
+
+ if (($_[2] ne "run") &&
+ ($_[2] ne "OK") &&
+ ($_[2] ne "end-of-test")) {
+ warn "Unexpected result code $_[2] from test $_[4]\n";
+ $warnings++;
+ }
+}
+
+if ($warnings) {
+ warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/src/kadmin/testing/scripts/verify_xrunner_report.plin b/src/kadmin/testing/scripts/verify_xrunner_report.plin
new file mode 100644
index 000000000..9d83c3ea2
--- /dev/null
+++ b/src/kadmin/testing/scripts/verify_xrunner_report.plin
@@ -0,0 +1,38 @@
+#!/usr/local/bin/perl
+
+sub usage { die "usage: $0 reportfile\n"; }
+
+$report = shift(@ARGV) || die &usage;
+
+open(REPORT, $report) || die "Couldn't open $report: $!\n";
+
+while(<REPORT>) {
+ if (/Process termination:/ && !/\bOK\b/) {
+ warn "Process termination not OK\n";
+ $warnings++;
+ } elsif (/Number of detected mismatches:\s*(\d+)/ && ($1 ne "0")) {
+ warn "Number of detected mismatches = $1\n";
+ $warnings++;
+ } elsif (/Detailed Results Description/) {
+ break;
+ }
+}
+
+while(<REPORT>) {
+ next if !/^\d+\s+/;
+
+ split;
+
+ if (($_[2] ne "run") &&
+ ($_[2] ne "OK") &&
+ ($_[2] ne "end-of-test")) {
+ warn "Unexpected result code $_[2] from test $_[4]\n";
+ $warnings++;
+ }
+}
+
+if ($warnings) {
+ warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/src/kadmin/testing/tcl/util.t b/src/kadmin/testing/tcl/util.t
new file mode 100644
index 000000000..f4688aeee
--- /dev/null
+++ b/src/kadmin/testing/tcl/util.t
@@ -0,0 +1,61 @@
+proc simple_principal {name} {
+ return "{$name} 0 0 0 0 {$name} 0 0 0 0 null 0"
+}
+
+proc princ_w_pol {name policy} {
+ return "{$name} 0 0 0 0 {$name} 0 0 0 0 {$policy} 0"
+}
+
+proc simple_policy {name} {
+ return "{$name} 0 0 0 0 0 0"
+}
+
+proc config_params {masks values} {
+ if {[llength $masks] != [llength $values]} {
+ error "config_params: length of mask and values differ"
+ }
+
+ set params [list $masks 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 {}]
+ for {set i 0} {$i < [llength $masks]} {incr i} {
+ set mask [lindex $masks $i]
+ set value [lindex $values $i]
+ switch -glob -- $mask {
+ "KADM5_CONFIG_REALM" {set params [lreplace $params 1 1 $value]}
+ "KADM5_CONFIG_PROFILE" {set params [lreplace $params 2 2 $value]}
+ "KADM5_CONFIG_KADMIND_PORT" {
+ set params [lreplace $params 3 3 $value]}
+ "KADM5_CONFIG_ADMIN_SERVER" {
+ set params [lreplace $params 4 4 $value]}
+ "KADM5_CONFIG_DBNAME" {set params [lreplace $params 5 5 $value]}
+ "KADM5_CONFIG_ADBNAME" {set params [lreplace $params 6 6 $value]}
+ "KADM5_CONFIG_ADB_LOCKFILE" {
+ set params [lreplace $params 7 7 $value]}
+ "KADM5_CONFIG_ADMIN_KEYTAB" {
+ set params [lreplace $params 8 8 $value]}
+ "KADM5_CONFIG_ACL_FILE" {set params [lreplace $params 9 9 $value]}
+ "KADM5_CONFIG_DICT_FILE" {
+ set params [lreplace $params 10 10 $value]}
+ "KADM5_CONFIG_MKEY_FROM_KBD" {
+ set params [lreplace $params 11 11 $value]}
+ "KADM5_CONFIG_STASH_FILE" {
+ set params [lreplace $params 12 12 $value]}
+ "KADM5_CONFIG_MKEY_NAME" {
+ set params [lreplace $params 13 13 $value]}
+ "KADM5_CONFIG_ENCTYPE" {set params [lreplace $params 14 14 $value]}
+ "KADM5_CONFIG_MAX_LIFE" {
+ set params [lreplace $params 15 15 $value]}
+ "KADM5_CONFIG_MAX_RLIFE" {
+ set params [lreplace $params 16 16 $value]}
+ "KADM5_CONFIG_EXPIRATION" {
+ set params [lreplace $params 17 17 $value]}
+ "KADM5_CONFIG_FLAGS" {set params [lreplace $params 18 18 $value]}
+ "KADM5_CONFIG_ENCTYPES" {
+ set params [lreplace $params 19 20 [llength $value] $value]}
+ "*" {error "config_params: unknown mask $mask"}
+ }
+ }
+ return $params
+}
+
+
+
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);
+}