diff options
Diffstat (limited to 'src/kadmin/testing')
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 0000000000..206bd85510 --- /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 0000000000..71959a3b05 --- /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 0000000000..798d6c51bd --- /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 0000000000..6e0c4687d6 --- /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 0000000000..b54e3a85e1 --- /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 0000000000..5d7069186e --- /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 0000000000..335b636e7e --- /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 0000000000..df93df4a00 --- /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 0000000000..df93df4a00 --- /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 0000000000..904730dfa0 --- /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 0000000000..d7834d1c74 --- /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 0000000000..d7834d1c74 --- /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 0000000000..c53ff96c1e --- /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 0000000000..14d7b10b54 --- /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 0000000000..14d7b10b54 --- /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 0000000000..3d047c550a --- /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 0000000000..b9fc37319a --- /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 0000000000..ea94ab2d1d --- /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 0000000000..ea94ab2d1d --- /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 0000000000..2e395faf85 --- /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 0000000000..a9c8e79570 --- /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 0000000000..fc5372dd4e --- /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 0000000000..c0a97ef271 --- /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 0000000000..9d83c3ea24 --- /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 0000000000..9d83c3ea24 --- /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 0000000000..f4688aeee3 --- /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 0000000000..36df4616d2 --- /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 0000000000..6d01590923 --- /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 0000000000..ba69b84611 --- /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 0000000000..b102cdfc2a --- /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], ¶ms->realm)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing realm name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[2], ¶ms->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], ¶ms->admin_server)) + != TCL_OK) { + Tcl_AppendElement(interp, "while parsing profile name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[5], ¶ms->dbname)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing profile name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[6], ¶ms->admin_dbname)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing admin_dbname name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[7], ¶ms->admin_lockfile)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing admin_lockfile name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[8], ¶ms->admin_keytab)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing admin_keytab name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[9], ¶ms->acl_file)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing acl_file name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[10], ¶ms->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], ¶ms->stash_file)) != TCL_OK) { + Tcl_AppendElement(interp, "while parsing stash_file name"); + retcode = TCL_ERROR; + goto finished; + } + if ((retcode = parse_str(interp, argv[13], ¶ms->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], ¶ms->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], ¶ms_str)) != TCL_OK) || + ((tcl_ret = parse_config_params(interp, params_str, ¶ms)) + != 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, + ¶ms, struct_version, + api_version, &server_handle); + + (void) krb5_cc_close(context, cc); + } else + ret = kadm5_init(client_name, pass, service_name, ¶ms, + 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 0000000000..95a3451d93 --- /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 0000000000..0c6aaac9cb --- /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 0000000000..3fc77fbcbf --- /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 0000000000..75a0fc25f9 --- /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); +} |
