diff options
Diffstat (limited to 'src/tests/dejagnu/config/default.exp')
-rw-r--r-- | src/tests/dejagnu/config/default.exp | 1987 |
1 files changed, 1520 insertions, 467 deletions
diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp index 44ffab7..8943b52 100644 --- a/src/tests/dejagnu/config/default.exp +++ b/src/tests/dejagnu/config/default.exp @@ -7,7 +7,7 @@ # This file provides several functions which deal with a local # Kerberos database. We have to do this such that we don't interfere # with any existing Kerberos database. We will create all the files -# in the directory tmpdir, which will have been created by the +# in the directory $tmppwd, which will have been created by the # testsuite default script. We will use $REALMNAME as our Kerberos # realm name, defaulting to KRBTEST.COM. @@ -15,12 +15,229 @@ set timeout 100 set stty_init {erase \^h kill \^u} set env(TERM) dumb -set des3_krbtgt 1 +set des3_krbtgt 0 +set tgt_support_desmd5 0 +set supported_enctypes "des-cbc-crc:normal" +set kdc_supported_enctypes "des-cbc-crc:normal" + +# The names of the individual passes must be unique; lots of things +# depend on it. The PASSES variable may not contain comments; only +# small pieces get evaluated, so comments will do strange things. + +# Most of the purpose of using multiple passes is to exercise the +# dependency of various bugs on configuration file settings, +# particularly with regards to encryption types. + +# The des.no-kdc-md5 pass will fail if the KDC does not constrain +# session key enctypes to those in its permitted_enctypes list. It +# works by assuming enctype similarity, thus allowing the client to +# request a des-cbc-md4 session key. Since only des-cbc-crc is in the +# KDC's permitted_enctypes list, the TGT will be unusable. + +# The des.des3-tgt.no-kdc-des3 pass will fail if the KDC doesn't +# constrain ticket key enctypes to those in permitted_enctypes. It +# does this by not putting des3 in the permitted_enctypes, while +# creating a TGT princpal that has a des3 key as well as a des key. + +# XXX -- master_key_type is fragile w.r.t. permitted_enctypes; it is +# possible to configure things such that you have a master_key_type +# that is not permitted, and the error message used to be cryptic. + +set passes { + { + des + des3_krbtgt=0 + {supported_enctypes=des-cbc-crc:normal} + {kdc_supported_enctypes=des-cbc-crc:normal} + {dummy=[verbose -log "DES TGT, DES enctype"]} + } + { + des.des3tgt + des3_krbtgt=1 + {supported_enctypes=des-cbc-crc:normal} + {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} + {dummy=[verbose -log "DES3 TGT, DES enctype"]} + } + { + des3 + des3_krbtgt=1 + {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} + {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} + {dummy=[verbose -log "DES3 TGT, DES3 + DES enctypes"]} + } + { + des-v4 + des3_krbtgt=0 + {supported_enctypes=des-cbc-crc:v4} + {kdc_supported_enctypes=des-cbc-crc:v4} + {default_tkt_enctypes(client)=des-cbc-crc} + {dummy=[verbose -log "DES TGT, DES-CRC enctype, V4 salt"]} + } + { + des-md5-v4 + des3_krbtgt=0 + {supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4} + {kdc_supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4} + {default_tkt_enctypes(client)=des-cbc-md5 des-cbc-crc} + {dummy=[verbose -log "DES TGT, DES-MD5 and -CRC enctypes, V4 salt"]} + } + { + all-des-des3-enctypes + des3_krbtgt=1 + {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \ + des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \ + des-cbc-md4:normal} + {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \ + des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \ + des-cbc-md4:normal} + {dummy=[verbose -log "DES3 TGT, many DES3 + DES enctypes"]} + } + { + des.no-kdc-md5 + des3_krbtgt=0 + tgt_support_desmd5=0 + {permitted_enctypes(kdc)=des-cbc-crc} + {default_tgs_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} + {default_tkt_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} + {supported_enctypes=des-cbc-crc:normal} + {kdc_supported_enctypes=des-cbc-crc:normal} + {master_key_type=des-cbc-crc} + {dummy=[verbose -log \ + "DES TGT, KDC permitting only des-cbc-crc"]} + } + { + des.des3-tgt.no-kdc-des3 + tgt_support_desmd5=0 + {permitted_enctypes(kdc)=des-cbc-crc} + {default_tgs_enctypes(client)=des-cbc-crc} + {default_tkt_enctypes(client)=des-cbc-crc} + {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} + {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} + {master_key_type=des-cbc-crc} + {dummy=[verbose -log \ + "DES3 TGT, KDC permitting only des-cbc-crc"]} + } +} -# We do everything in a temporary directory. -if ![file isdirectory tmpdir] {catch "exec mkdir tmpdir" status} +# des.md5-tgt is set as unused, since it won't trigger the error case +# if SUPPORT_DESMD5 isn't honored. + +# The des.md5-tgt pass will fail if enctype similarity is inconsisent; +# between 1.0.x and 1.1, the decrypt functions became more strict +# about matching enctypes, while the KDB retrieval functions didn't +# coerce the enctype to match what was requested. It works by setting +# SUPPORT_DESMD5 on the TGT principal, forcing an enctype of +# des-cbc-md5 on the TGT key. Since the database only contains a +# des-cbc-crc key, the decrypt will fail if enctypes are not coerced. + +# des.no-kdc-md5.client-md4-skey is retained in unsed_passes, even +# though des.no-kdc-md5 is roughly equivalent, since the associated +# comment needs additional investigation at some point re the kadmin +# client. + +# The des.no-kdc-md5.client-md4-skey will fail on TGS requests due to +# the KDC issuing session keys that it won't accept. It will also +# fail for a kadmin client, but for different reasons, since the kadm5 +# library does some curious filtering of enctypes, and also uses +# get_in_tkt() rather than get_init_creds(); the former does an +# intersection of the enctypes provided by the caller and those listed +# in the config file! + +set unused_passes { + { + des.md5-tgt + des3_krbtgt=0 + tgt_support_desmd5=1 + supported_enctypes=des-cbc-crc:normal + kdc_supported_enctypes=des-cbc-crc:normal + {permitted_enctypes(kdc)=des-cbc-md5 des-cbc-md4 des-cbc-crc} + {permitted_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} + {dummy=[verbose -log "DES TGT, SUPPORTS_DESMD5"]} + } + { + des.md5-tgt.no-kdc-md5 + des3_krbtgt=0 + tgt_support_desmd5=1 + {permitted_enctypes(kdc)=des-cbc-crc} + {default_tgs_enctypes(client)=des-cbc-crc} + {default_tkt_enctypes(client)=des-cbc-crc} + {supported_enctypes=des-cbc-crc:normal} + {kdc_supported_enctypes=des-cbc-crc:normal} + {master_key_type=des-cbc-crc} + {dummy=[verbose -log \ + "DES TGT, SUPPORTS_DESMD5, KDC permitting only des-cbc-crc"]} + } + { + des.no-kdc-md5.client-md4-skey + des3_krbtgt=0 + {permitted_enctypes(kdc)=des-cbc-crc} + {permitted_enctypes(client)=des-cbc-crc des-cbc-md4} + {default_tgs_enctypes(client)=des-cbc-crc des-cbc-md4} + {default_tkt_enctypes(client)=des-cbc-md4} + {supported_enctypes=des-cbc-crc:normal} + {kdc_supported_enctypes=des-cbc-crc:normal} + {dummy=[verbose -log \ + "DES TGT, DES enctype, KDC permitting only des-cbc-crc, client requests des-cbc-md4 session key"]} + } + { + all-enctypes + des3_krbtgt=1 + {supported_enctypes=\ + rijndael256-hmac-sha1:normal rijndael192-hmac-sha1:normal rijndael128-hmac-sha1:normal \ + serpent256-hmac-sha1:normal serpent192-hmac-sha1:norealm serpent128-hmac-sha1:normal \ + twofish256-hmac-sha1:normal twofish192-hmac-sha1:norealm twofish128-hmac-sha1:normal \ + des3-cbc-sha1:normal des3-cbc-sha1:none \ + des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \ + des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \ + } + {kdc_supported_enctypes=\ + rijndael256-hmac-sha1:normal rijndael192-hmac-sha1:normal rijndael128-hmac-sha1:normal \ + serpent256-hmac-sha1:normal serpent192-hmac-sha1:norealm serpent128-hmac-sha1:normal \ + twofish256-hmac-sha1:normal twofish192-hmac-sha1:norealm twofish128-hmac-sha1:normal \ + des3-cbc-sha1:normal des3-cbc-sha1:none \ + des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \ + des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \ + } + {dummy=[verbose -log "DES3 TGT, default enctypes"]} + } + { + aes + des3_krbtgt=0 + {supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal} + {kdc_supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal} + {default_tgs_enctypes=rijndael256-hmac-sha1 des-cbc-crc} + {default_tkt_enctypes=rijndael256-hmac-sha1 des-cbc-crc} + {dummy=[verbose -log "DES3 TGT, default enctypes"]} + } +} +# {supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal } +# {kdc_supported_enctypes= des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal} + +# This shouldn't be necessary on dejagnu-1.4 and later, but 1.3 seems +# to need it because its runtest.exp doesn't deal with PASS at all. +if [info exists PASS] { + foreach pass $passes { + if { [lsearch -exact $PASS [lindex $pass 0]] >= 0 } { + lappend MULTIPASS $pass + } + } +} else { + set MULTIPASS $passes +} -set tmppwd "[pwd]/tmpdir" +set last_passname_conf "" +set last_passname_db "" + +# We do everything in a temporary directory. +if ![info exists TMPDIR] { + set tmppwd "[pwd]/tmpdir" + if ![file isdirectory $tmppwd] { + catch "exec mkdir $tmppwd" status + } +} else { + set tmppwd $TMPDIR +} +verbose "tmppwd=$tmppwd" # On Ultrix, use /bin/sh5 in preference to /bin/sh. if ![info exists BINSH] { @@ -41,7 +258,7 @@ if ![info exists BINSH] { if ![info exists KEY] { catch {exec $BINSH -c "echo $$"} KEY verbose "KEY is $KEY" - set keyfile [open tmpdir/KEY w] + set keyfile [open $tmppwd/KEY w] puts $keyfile "$KEY" close $keyfile } @@ -49,7 +266,7 @@ if ![info exists KEY] { # Clear away any files left over from a previous run. # We can't use them now because we don't know the right KEY. # krb5.conf might change if running tests on another host -catch "exec rm -f tmpdir/db.ok tmpdir/srvtab tmpdir/krb5.conf tmpdir/kdc.conf tmpdir/cpw_srvtab" +catch "exec rm -f $tmppwd/db.ok $tmppwd/srvtab $tmppwd/krb5.conf $tmppwd/kdc.conf $tmppwd/cpw_srvtab $tmppwd/krb.realms $tmppwd/krb.conf" # Put the installed kerberos directories on PATH. # This needs to be fixed for V5. @@ -79,41 +296,37 @@ verbose "Test realm is $REALMNAME" # if they exist. If they do not, then they must be in PATH. We # expect $objdir to be ...tests/dejagnu. -if ![info exists KDB5_UTIL] { - set KDB5_UTIL [findfile $objdir/../../kadmin/dbutil/kdb5_util] -} - -if ![info exists KRB5KDC] { - set KRB5KDC [findfile $objdir/../../kdc/krb5kdc] -} - -if ![info exists KADMIND] { - set KADMIND [findfile $objdir/../../kadmin/server/kadmind] -} - -if ![info exists KADMIN] { - set KADMIN [findfile $objdir/../../kadmin/cli/kadmin] -} - -if ![info exists KADMIN_LOCAL] { - set KADMIN_LOCAL [findfile $objdir/../../kadmin/cli/kadmin.local] -} - - -if ![info exists KINIT] { - set KINIT [findfile $objdir/../../clients/kinit/kinit] -} - -if ![info exists KTUTIL] { - set KTUTIL [findfile $objdir/../../kadmin/ktutil/ktutil] +foreach i { + {KDB5_UTIL $objdir/../../kadmin/dbutil/kdb5_util} + {KRB5KDC $objdir/../../kdc/krb5kdc} + {KADMIND $objdir/../../kadmin/server/kadmind} + {KADMIN $objdir/../../kadmin/cli/kadmin} + {KADMIN_LOCAL $objdir/../../kadmin/cli/kadmin.local} + {KINIT $objdir/../../clients/kinit/kinit} + {KTUTIL $objdir/../../kadmin/ktutil/ktutil} + {KLIST $objdir/../../clients/klist/klist} + {KDESTROY $objdir/../../clients/kdestroy/kdestroy} + {RESOLVE $objdir/../resolve/resolve} + {T_INETD $objdir/t_inetd} +} { + set varname [lindex $i 0] + if ![info exists $varname] { + eval set varval [lindex $i 1] + set varval [findfile $varval] + set $varname $varval + verbose "$varname=$varval" + } { + eval set varval \$$varname + verbose "$varname already set to $varval" + } } -if ![info exists RESOLVE] { - set RESOLVE [findfile $objdir/../resolve/resolve] +if ![info exists RLOGIN] { + set RLOGIN rlogin } -if ![info exists T_INETD] { - set T_INETD [findfile $objdir/t_inetd] +if ![info exists RLOGIN_FLAGS] { + set RLOGIN_FLAGS "" } # We use a couple of variables to hold shell prompts which may be @@ -127,23 +340,40 @@ if ![info exists SHELL_PROMPT] { set SHELL_PROMPT "(%|#|>|\\$) $" } +verbose "setting up onexit handler (old handler=[exit -onexit])" +exit -onexit [concat { + verbose "calling stop_kerberos_daemons (onexit handler)" + stop_kerberos_daemons; +} [exit -onexit]] + # check_k5login + # Most of the tests won't work if the user has a .k5login file, unless -# the user's name appears unadorned in .k5login (in which case kuserok -# will assume a null instance and the local realm). This procedure -# returns 1 if the .k5login file appears to be OK, 0 otherwise. This -# check is not foolproof. +# the user's name appears with $REALMNAME in .k5login + +# This procedure returns 1 if the .k5login file appears to be OK, 0 +# otherwise. This check is not foolproof. + +# Note that this previously checked for a username with no realm; this +# works for krb4's kuserok() but not for krb5_kuserok(), due to some +# implementation details. *sigh* proc check_k5login { testname } { global env global REALMNAME - if ![file exists ~/.k5login] { - return 1 + if {![file exists ~/.k5login]} { + if {$env(USER) == "root"} { + return 0 + } else { + return 1 + } } + verbose "looking for $env(USER)@$REALMNAME in ~/.k5login" 2 set file [open ~/.k5login r] while { [gets $file principal] != -1 } { + verbose " found $principal" 2 if { $principal == "$env(USER)@$REALMNAME" } { close $file return 1 @@ -151,8 +381,40 @@ proc check_k5login { testname } { } close $file - untested "$testname test requires that your name appear in your ~/.k5login" - untested "file with no realm or instance." + note "$testname test requires that your name appear in your ~/.k5login" + note "file in the form $env(USER)@$REALMNAME" + unsupported "$testname" + + return 0 +} + +proc check_klogin { testname } { + global env + global REALMNAME + + if {![file exists ~/.klogin]} { + if {$env(USER) == "root"} { + return 0 + } else { + return 1 + } + } + + verbose "looking for $env(USER) in ~/.klogin" 2 + set file [open ~/.klogin r] + while { [gets $file principal] != -1 } { + verbose " found $principal" 2 + if { $principal == "$env(USER)" \ + || $principal == "$env(USER)@$REALMNAME" } { + close $file + return 1 + } + } + close $file + + note "$testname test requires that your name appear in your ~/.klogin" + note "file without a realm." + unsupported "$testname" return 0 } @@ -169,8 +431,7 @@ proc check_exit_status { testname } { verbose "wait -i $spawn_id returned $status_list ($testname)" catch "close -i $spawn_id" if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } { - send_log "exit status: $status_list\n" - verbose "exit status: $status_list" + verbose -log "exit status: $status_list" fail "$testname" return 0 } else { @@ -178,73 +439,126 @@ proc check_exit_status { testname } { } } -# setup_runtime_flags -# Sets the proper flags for shared libraries. -# Configuration is through a site.exp and the runvarlist variable -# Returns 1 if variables were already set, otherwise 0 -proc setup_runtime_env { } { - global env - global runvarlist - global krb5_init_vars - global krb5_old_vars - global runtime_setup +# +# ENVSTACK +# - if [info exists runtime_setup] { - return 1 - } +# These procedures implement an environment variable stack. They use +# the global variable $envvars_tosave for the purpose of identifying +# which environment variables to save. They also track which ones are +# unset at any particular point. The stack pointer is $envstackp, +# which is an integer. The arrays $envstack$envstackp and +# $unenvstack$envstackp store respectively the set of old environment +# variables/values pushed onto the stack and the set of old unset +# environment variables for a given value of $envstackp. - set runtime_setup 1 - set krb5_init_vars [list ] - set krb5_old_vars [list ] +# Changing the value of $envvars_tosave after performing the first +# push operation may result in strangeness. - # Only keep the foo=bar and ignore export commands... - foreach i $runvarlist { - if {[regexp ".*=.*" $i]} { - lappend krb5_init_vars $i +# +# envstack_push +# +# Push set of current environment variables. +# +proc envstack_push { } { + global env + global envvars_tosave + global envstackp + global envstack$envstackp + global unenvstack$envstackp + + verbose "envstack_push: starting, sp=$envstackp" + foreach i $envvars_tosave { + if [info exists env($i)] { + verbose "envstack_push: saving $i=$env($i)" + set envstack${envstackp}($i) $env($i) + } { + verbose "envstack_push: marking $i as unset" + set unenvstack${envstackp}($i) unset } } + incr envstackp + verbose "envstack_push: exiting, sp=$envstackp" +} - - # Set the variables... (and save the old ones) - foreach i $krb5_init_vars { - regexp "^(\[^=\]*)=(.*)" $i foo evar evalue - if [info exists env($evar)] { - lappend krb5_old_vars $evar=$env($evar) - } - set env($evar) "$evalue" - verbose "$evar=$evalue" +# +# envstack_pop +# +# Pop set of current environment variables. +# +proc envstack_pop { } { + global env + global envstackp + + verbose "envstack_pop: starting, sp=$envstackp" + incr envstackp -1 + global envstack$envstackp # YUCK!!! no obvious better way though... + global unenvstack$envstackp + if {$envstackp < 0} { + perror "envstack_pop: stack underflow!" + return + } + if [info exists envstack$envstackp] { + foreach i [array names envstack$envstackp] { + if [info exists env($i)] { + verbose "envstack_pop: $i was $env($i)" + } + eval set env($i) \$envstack${envstackp}($i) + verbose "envstack_pop: restored $i to $env($i)" + } + unset envstack$envstackp + } + if [info exists unenvstack$envstackp] { + foreach i [array names unenvstack$envstackp] { + if [info exists env($i)] { + verbose "envstack_pop: $i was $env($i)" + unset env($i) + verbose "envstack_pop: $i unset" + } { + verbose "envstack_pop: ignoring already unset $i" + } + } + unset unenvstack$envstackp } + verbose "envstack_pop: exiting, sp=$envstackp" +} - return 0 +# +# Initialize the envstack +# +set envvars_tosave { + KRB5_CONFIG KRB5CCNAME KRBTKFILE KRB5RCACHEDIR + KERBEROS_SERVER KRB5_KDC_PROFILE } +set krb5_init_vars [list ] +# XXX -- fix me later! +foreach i $runvarlist { + verbose "processing $i" + if {[regexp "^(\[^=\]*)=(.*)" $i foo evar evalue]} { + verbose "adding $evar to savelist" + lappend envvars_tosave $evar + verbose "savelist $envvars_tosave" + lappend krb5_init_vars $i + } +} +set envstackp 0 +envstack_push +# setup_runtime_flags +# Sets the proper flags for shared libraries. # Configuration is through a site.exp and the runvarlist variable -proc restore_runtime_env { } { +# Returns 1 if variables were already set, otherwise 0 +proc setup_runtime_env { } { global env global krb5_init_vars - global krb5_old_vars - global runtime_setup - - if ![info exists runtime_setup] { - return 1 - } - - # restore the variables... + # Set the variables foreach i $krb5_init_vars { regexp "^(\[^=\]*)=(.*)" $i foo evar evalue - set idx [lsearch -regexp $krb5_old_vars "^$evar=" ] - if {$idx >= 0} { - - regexp "^(\[^=\]*)=(.*)" [lindex $krb5_old_vars $idx] foo evar evalue - set env($evar) "$evalue" - - } else { - catch "unset env($evar)" - } + set env($evar) "$evalue" + verbose "$evar=$evalue" } - - unset runtime_setup + return 0 } # get_hostname @@ -257,37 +571,65 @@ proc get_hostname { } { global hostname global localhostname global domain + global tmppwd if {[info exists hostname] && [info exists localhostname]} { return 1 } - set setup [setup_runtime_env] - - catch "exec $RESOLVE -q >tmpdir/hostname" exec_output + envstack_push + setup_runtime_env + catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output + envstack_pop if ![string match "" $exec_output] { - send_log "$exec_output\n" - verbose $exec_output - send_error "ERROR: can't get hostname\n" - if {$setup == 0} restore_runtime_env + verbose -log $exec_output + perror "can't get hostname" return 0 } - set file [open tmpdir/hostname r] + set file [open $tmppwd/hostname r] if { [ gets $file hostname ] == -1 } { - send_error "ERROR: no output from hostname\n" - if {$setup == 0} restore_runtime_env + perror "no output from hostname" return 0 } close $file - catch "exec rm -f tmpdir/hostname" exec_output - regexp "^(\[^.\]*)\.(.*)$" $hostname foo localhostname domain + catch "exec rm -f $tmppwd/hostname" exec_output + regexp "^(\[^.\]*)\\.(.*)$" $hostname foo localhostname domain set hostname [string tolower $hostname] set localhostname [string tolower $localhostname] set domain [string tolower $domain] verbose "hostname: $hostname; localhostname: $localhostname; domain $domain" - if {$setup == 0} restore_runtime_env + return 1 +} + +# modify_principal name options... + +proc modify_principal { name args } { + global KADMIN_LOCAL + global REALMNAME + + spawn $KADMIN_LOCAL -r $REALMNAME + expect_after { + eof { + fail "modprinc (kadmin.local)" + return 0 + } + timeout { + fail "modprinc (kadmin.local)" + return 0 + } + } + expect "kadmin.local: " + send "modprinc $args $name\r" + expect -re "modprinc \[^\n\r\]* $name" + expect -re "Principal .* modified." + send "quit\r" + expect eof + catch expect_after + if ![check_exit_status "kadmin.local modprinc"] { + perror "kadmin.local modprinc exited abnormally" + } return 1 } @@ -301,40 +643,27 @@ proc setup_kerberos_files { } { global hostname global domain global tmppwd + global supported_enctypes + global kdc_supported_enctypes + global last_passname_conf + global multipass_name + global master_key_type if ![get_hostname] { return 0 } - # Create a krb5.conf file. - if ![file exists tmpdir/krb5.conf] { - set conffile [open tmpdir/krb5.conf w] - puts $conffile "\[libdefaults\]" - puts $conffile " default_realm = $REALMNAME" -# puts $conffile "default_tgs_enctypes = des-cbc-md5 des-cbc-crc" - puts $conffile "" - puts $conffile "\[realms\]" - puts $conffile " $REALMNAME = \{" - puts $conffile " kdc = $hostname:3088" - puts $conffile " admin_server = $hostname:3750" - puts $conffile " kpasswd_server = $hostname:3751" - puts $conffile " default_domain = $domain" - puts $conffile " \}" - puts $conffile "" - puts $conffile "\[domain_realm\]" - puts $conffile " .$domain = $REALMNAME" - puts $conffile " $domain = $REALMNAME" - puts $conffile "" - puts $conffile "\[logging\]" - puts $conffile " admin_server = FILE:$tmppwd/kadmind5.log" - puts $conffile " kdc = FILE:$tmppwd/kdc.log" - puts $conffile " default = FILE:$tmppwd/others.log" - close $conffile - } + setup_krb5_conf client + setup_krb5_conf server + setup_krb5_conf kdc # Create a kdc.conf file. - if ![file exists tmpdir/kdc.conf] { - set conffile [open tmpdir/kdc.conf w] + if { ![file exists $tmppwd/kdc.conf] \ + || $last_passname_conf != $multipass_name } { + if ![info exists master_key_type] { + set master_key_type des-cbc-md5 + } + set conffile [open $tmppwd/kdc.conf w] puts $conffile "\[kdcdefaults\]" puts $conffile " kdc_ports = 3085,3086,3087,3088,3089" puts $conffile "" @@ -350,34 +679,114 @@ proc setup_kerberos_files { } { puts $conffile " kpasswd_port = 3751" puts $conffile " max_life = 1:00:00" puts $conffile " max_renewable_life = 3:00:00" - puts $conffile " master_key_type = des-cbc-md5" + puts $conffile " master_key_type = $master_key_type" puts $conffile " master_key_name = master/key" -# des3-cbc-sha1:normal - puts $conffile " supported_enctypes = des-cbc-crc:normal des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm" - puts $conffile " kdc_supported_enctypes = des3-cbc-sha1:normal des-cbc-crc:normal des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm" + puts $conffile " supported_enctypes = $supported_enctypes" + puts $conffile " kdc_supported_enctypes = $kdc_supported_enctypes" puts $conffile " kdc_ports = 3088" puts $conffile " default_principal_expiration = 2037.12.31.23.59.59" puts $conffile " default_principal_flags = -postdateable forwardable" + puts $conffile " dict_file = $tmppwd/dictfile" puts $conffile " \}" puts $conffile "" close $conffile } # Create ACL file. - if ![file exists tmpdir/acl] { - set aclfile [open tmpdir/acl w] + if ![file exists $tmppwd/acl] { + set aclfile [open $tmppwd/acl w] puts $aclfile "krbtest/admin@$REALMNAME *" close $aclfile } + # Create krb.conf file + if ![file exists $tmppwd/krb.conf] { + set conffile [open $tmppwd/krb.conf w] + puts $conffile "$REALMNAME" + puts $conffile "$REALMNAME $hostname:3088 admin server" + close $conffile + } + + # Create krb.realms file + if ![file exists $tmppwd/krb.realms] { + set conffile [open $tmppwd/krb.realms w] + puts $conffile ".[string toupper $domain] $REALMNAME" + puts $conffile "[string toupper $domain]. $REALMNAME" + close $conffile + } + + # Create dictfile file. + if ![file exists $tmppwd/dictfile] { + set dictfile [open $tmppwd/dictfile w] + puts $dictfile "weak_password" + close $dictfile + } + + set last_passname_conf $multipass_name return 1 } +proc setup_krb5_conf { {type client} } { + global tmppwd + global hostname + global domain + global REALMNAME + global last_passname_conf + global multipass_name + global default_tgs_enctypes + global default_tkt_enctypes + global permitted_enctypes + + # Create a krb5.conf file. + if { ![file exists $tmppwd/krb5.$type.conf] \ + || $last_passname_conf != $multipass_name } { + set conffile [open $tmppwd/krb5.$type.conf w] + puts $conffile "\[libdefaults\]" + puts $conffile " default_realm = $REALMNAME" + if [info exists default_tgs_enctypes($type)] { + puts $conffile \ + " default_tgs_enctypes = $default_tgs_enctypes($type)" + } + if [info exists default_tkt_enctypes($type)] { + puts $conffile \ + " default_tkt_enctypes = $default_tkt_enctypes($type)" + } + if [info exists permitted_enctypes($type)] { + puts $conffile \ + " permitted_enctypes = $permitted_enctypes($type)" + } + puts $conffile " krb4_config = $tmppwd/krb.conf" + puts $conffile " krb4_realms = $tmppwd/krb.realms" + puts $conffile " krb4_srvtab = $tmppwd/v4srvtab" + puts $conffile "" + puts $conffile "\[realms\]" + puts $conffile " $REALMNAME = \{" + puts $conffile " kdc = $hostname:3088" + puts $conffile " admin_server = $hostname:3750" + puts $conffile " kpasswd_server = $hostname:3751" + puts $conffile " default_domain = $domain" + puts $conffile " krb524_server = $hostname:3752" + puts $conffile " \}" + puts $conffile "" + puts $conffile "\[domain_realm\]" + puts $conffile " .$domain = $REALMNAME" + puts $conffile " $domain = $REALMNAME" + puts $conffile "" + puts $conffile "\[logging\]" + puts $conffile " admin_server = FILE:$tmppwd/kadmind5.log" + puts $conffile " kdc = FILE:$tmppwd/kdc.log" + puts $conffile " default = FILE:$tmppwd/others.log" + close $conffile + } +} + # Save the original values of the environment variables we are going # to muck with. +# XXX deal with envstack later. + if [info exists env(KRB5_CONFIG)] { - set orig_krb_conf $env(KRB5_CONFIG) + set orig_krb5_conf $env(KRB5_CONFIG) } else { catch "unset orig_krb5_config" } @@ -403,7 +812,7 @@ if [ info exists env(KERBEROS_SERVER)] { # setup_kerberos_env # Set the environment variables needed to run Kerberos programs. -proc setup_kerberos_env { } { +proc setup_kerberos_env { {type client} } { global REALMNAME global env global tmppwd @@ -413,13 +822,17 @@ proc setup_kerberos_env { } { # Set the environment variable KRB5_CONFIG to point to our krb5.conf file. # All the Kerberos tools check KRB5_CONFIG. # Actually, V5 doesn't currently use this. - set env(KRB5_CONFIG) $tmppwd/krb5.conf + set env(KRB5_CONFIG) $tmppwd/krb5.$type.conf verbose "KRB5_CONFIG=$env(KRB5_CONFIG)" # Direct the Kerberos programs at a local ticket file. set env(KRB5CCNAME) $tmppwd/tkt verbose "KRB5CCNAME=$env(KRB5CCNAME)" + # Direct the Kerberos programs at a local ticket file. + set env(KRBTKFILE) $tmppwd/tktv4 + verbose "KRBTKFILE=$env(KRBTKFILE)" + # Direct the Kerberos server at a cache file stored in the # temporary directory. set env(KRB5RCACHEDIR) $tmppwd @@ -437,8 +850,8 @@ proc setup_kerberos_env { } { verbose "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)" # Create an environment setup script. (For convenience) - if ![file exists tmpdir/env.sh] { - set envfile [open tmpdir/env.sh w] + if ![file exists $tmppwd/env.sh] { + set envfile [open $tmppwd/env.sh w] puts $envfile "KRB5_CONFIG=$env(KRB5_CONFIG)" puts $envfile "KRB5CCNAME=$env(KRB5CCNAME)" puts $envfile "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)" @@ -453,8 +866,8 @@ proc setup_kerberos_env { } { } close $envfile } - if ![file exists tmpdir/env.csh] { - set envfile [open tmpdir/env.csh w] + if ![file exists $tmppwd/env.csh] { + set envfile [open $tmppwd/env.csh w] puts $envfile "setenv KRB5_CONFIG $env(KRB5_CONFIG)" puts $envfile "setenv KRB5CCNAME $env(KRB5CCNAME)" puts $envfile "setenv KRB5RCACHEDIR $env(KRB5RCACHEDIR)" @@ -503,7 +916,6 @@ proc restore_kerberos_env { } { catch "unset env(KERBEROS_SERVER)" } - restore_runtime_env } # setup_kadmind_srvtab @@ -516,58 +928,69 @@ proc setup_kadmind_srvtab { } { global KEY global tmppwd - catch "exec rm -f tmpdir/admin-keytab" + catch "exec rm -f $tmppwd/admin-keytab" + envstack_push + setup_kerberos_env kdc spawn $KADMIN_LOCAL -r $REALMNAME + envstack_pop + catch expect_after expect_after { + -re "(.*)\r\nkadmin.local: " { + fail "kadmin.local admin-keytab (unmatched output: $expect_out(1,string)" + catch "exec rm -f $tmppwd/admin-keytab" + catch "expect_after" + return 0 + } timeout { fail "kadmin.local admin-keytab (timeout)" - catch "exec rm -f tmpdir/admin-keytab" + catch "exec rm -f $tmppwd/admin-keytab" catch "expect_after" return 0 } eof { fail "kadmin.local admin-keytab (eof)" - catch "exec rm -f tmpdir/admin-keytab" + catch "exec rm -f $tmppwd/admin-keytab" catch "expect_after" return 0 } } expect "kadmin.local: " send "xst -k admin-new-srvtab kadmin/admin\r" + expect "xst -k admin-new-srvtab kadmin/admin\r\n" expect -re ".*Entry for principal kadmin/admin.* added to keytab WRFILE:admin-new-srvtab." expect "kadmin.local: " catch "exec mv -f admin-new-srvtab changepw-new-srvtab" exec_output if ![string match "" $exec_output] { - send_log "$exec_output\n" - verbose $exec_output - send_error "ERROR: can't mv admin-new-srvtab\n" + verbose -log "$exec_output" + perror "can't mv admin-new-srvtab" + catch expect_after return 0 } send "xst -k changepw-new-srvtab kadmin/changepw\r" + expect "xst -k changepw-new-srvtab kadmin/changepw\r\n" expect -re ".*Entry for principal kadmin/changepw.* added to keytab WRFILE:changepw-new-srvtab." expect "kadmin.local: " send "quit\r" - expect "\r" - expect_after + expect eof + catch expect_after if ![check_exit_status "kadmin.local admin-keytab"] { - catch "exec rm -f tmpdir/admin-keytab" - send_error "ERROR: kadmin.local admin-keytab exited abnormally\n" + catch "exec rm -f $tmppwd/admin-keytab" + perror "kadmin.local admin-keytab exited abnormally" return 0 } - catch "exec mv -f changepw-new-srvtab tmpdir/admin-keytab" exec_output + catch "exec mv -f changepw-new-srvtab $tmppwd/admin-keytab" exec_output if ![string match "" $exec_output] { - send_log "$exec_output\n" - verbose $exec_output - send_error "ERROR: can't mv new admin-keytab\n" + verbose -log "$exec_output" + perror "can't mv new admin-keytab" return 0 } # Make the srvtab file globally readable in case we are using a # root shell and the srvtab is NFS mounted. - catch "exec chmod a+r tmpdir/admin-keytab" + catch "exec chmod a+r $tmppwd/admin-keytab" return 1 } @@ -584,208 +1007,260 @@ proc setup_kerberos_db { standalone } { global tmppwd global spawn_id global des3_krbtgt + global tgt_support_desmd5 + global multipass_name + global last_passname_db + + set failall 0 - if {!$standalone && [file exists tmpdir/db.ok]} { + if {!$standalone && [file exists $tmppwd/db.ok] \ + && $last_passname_db == $multipass_name} { return 1 } - catch "exec rm -f [glob -nocomplain tmpdir/db* tmpdir/adb*]" + catch "exec rm -f [glob -nocomplain $tmppwd/db* $tmppwd/adb*]" # Creating a new database means we need a new srvtab. - catch "exec rm -f tmpdir/srvtab" + catch "exec rm -f $tmppwd/srvtab" - if { ![setup_kerberos_files] || ![setup_kerberos_env] } { - return 0 + envstack_push + if { ![setup_kerberos_files] || ![setup_kerberos_env kdc] } { + set failall 1 } - spawn $KDB5_UTIL -r $REALMNAME create - - expect { - "Enter KDC database master key:" { - verbose "kdb5_util started" - } + # Set up a common expect_after for use in multiple places. + set def_exp_after { timeout { - fail "kdb5_util - create" - return 0 + set test "$test (timeout)" + break } eof { - fail "kdb5_util - create" - return 0 + set test "$test (eof)" + break } } - send "masterkey$KEY\r" - set failed 0 - expect { - "Re-enter KDC database master key to verify:" { } - timeout { - fail "kdb5_util create - verify" - return 0 - } - eof { - fail "kdb5_util create - verify" - return 0 + + set test "kdb5_util create" + set body { + if $failall { + break } - } - send "masterkey$KEY\r" - expect { - -re "\[Cc\]ouldn't" { - fail "kdb5_util - create" - return 0 + #exec xterm + verbose "starting $test" + spawn $KDB5_UTIL -r $REALMNAME create + expect_after $def_exp_after + + expect "Enter KDC database master key:" + + set test "kdb5_util create (verify)" + send "masterkey$KEY\r" + expect "Re-enter KDC database master key to verify:" + + set test "kdb5_util create" + send "masterkey$KEY\r" + expect { + -re "\[Cc\]ouldn't" { + expect eof + break + } + "Cannot find/read stored" exp_continue + "Warning: proceeding without master key" exp_continue + eof { } } - "Cannot find/read stored" { - exp_continue + catch expect_after + if ![check_exit_status kdb5_util] { + break } - "Warning: proceeding without master key" { - exp_continue + } + set ret [catch $body] + catch expect_after + if $ret { + set failall 1 + if $standalone { + fail $test } - timeout { - fail "kdb5_util - create" - return 0 + } else { + if $standalone { + pass $test } - eof { } - } - if ![check_exit_status kdb5_util] { - return 0 - } - - if {$standalone} { - pass "kdb5_util - create" } # Stash the master key in a file. - spawn $KDB5_UTIL -r $REALMNAME stash - expect { - "Enter KDC database master key:" { - verbose "kdb5_util stash started" + set test "kdb5_util stash" + set body { + if $failall { + break } - timeout { - fail "kdb5_util stash" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 - } - eof { - fail "kdb5_util stash" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 + spawn $KDB5_UTIL -r $REALMNAME stash + verbose "starting $test" + expect_after $def_exp_after + expect "Enter KDC database master key:" + send "masterkey$KEY\r" + expect eof + catch expect_after + if ![check_exit_status kdb5_util] { + break } } - send "masterkey$KEY\r" - expect { - eof { } - timeout { - fail "kdb5_util stash" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 + set ret [catch $body] + catch "expect eof" + catch expect_after + if $ret { + set failall 1 + if $standalone { + fail $test + } else { + catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db" + } + } else { + if $standalone { + pass $test } - } - if ![check_exit_status kdb5_util] { - return 0 - } - - if {$standalone} { - pass "kdb5_util stash" } # Add an admin user. - spawn $KADMIN_LOCAL -r $REALMNAME - expect_after { - timeout { - catch "expect_after" - fail "kadmin.local (timeout)" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 +#send_user "will run: $KADMIN_LOCAL -r $REALMNAME\n" +#exec xterm + set test "kadmin.local ank krbtest/admin" + set body { + if $failall { + break } - eof { - catch "expect_after" - fail "kadmin.local (eof)" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 + spawn $KADMIN_LOCAL -r $REALMNAME + verbose "starting $test" + expect_after $def_exp_after + + expect "kadmin.local: " + send "ank krbtest/admin@$REALMNAME\r" + # It echos... + expect "ank krbtest/admin@$REALMNAME\r" + expect "Enter password for principal \"krbtest/admin@$REALMNAME\":" + send "adminpass$KEY\r" + expect "Re-enter password for principal \"krbtest/admin@$REALMNAME\":" + send "adminpass$KEY\r" + expect { + "Principal \"krbtest/admin@$REALMNAME\" created" { } + "Principal or policy already exists while creating*" { } + } + expect "kadmin.local: " + send "quit\r" + expect eof + catch expect_after + if ![check_exit_status kadmin_local] { + break } } - expect "kadmin.local: " - send "ank krbtest/admin@$REALMNAME\r" - # It echos... - expect "ank krbtest/admin@$REALMNAME\r" - expect "Enter password for principal \"krbtest/admin@$REALMNAME\":" - send "adminpass$KEY\r" - expect "Re-enter password for principal \"krbtest/admin@$REALMNAME\":" - send "adminpass$KEY\r" - expect { - "Principal \"krbtest/admin@$REALMNAME\" created" { } - "Principal or policy already exists while creating*" { expect eof } - } - expect "kadmin.local: " - send "quit\r" - expect "\r" - expect_after - if ![check_exit_status kadmin_local] { - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" + set ret [catch $body] + catch "expect eof" + catch expect_after + if $ret { + set failall 1 + if $standalone { + fail $test + } else { + catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db" + } + } else { + if $standalone { + pass $test } - return 0 } if $des3_krbtgt { # Set the TGT key to DES3. - spawn $KADMIN_LOCAL -r $REALMNAME -e des3-cbc-sha1:normal - expect_after { - timeout { - catch "expect_after" - fail "kadmin.local (timeout)" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 + set test "kadmin.local TGT to DES3" + set body { + if $failall { + break } - eof { - catch "expect_after" - fail "kadmin.local (eof)" - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" - } - return 0 + spawn $KADMIN_LOCAL -r $REALMNAME -e des3-cbc-sha1:normal + verbose "starting $test" + expect_after $def_exp_after + + expect "kadmin.local: " + send "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" + # It echos... + expect "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" + expect { + "Key for \"krbtgt/$REALMNAME@$REALMNAME\" randomized." { } + } + expect "kadmin.local: " + send "quit\r" + expect eof + catch expect_after + if ![check_exit_status kadmin_local] { + break } } - expect "kadmin.local: " - send "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" - # It echos... - expect "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" - expect { - "Key for \"krbtgt/$REALMNAME@$REALMNAME\" randomized." { } + set ret [catch $body] + catch "expect eof" + catch expect_after + if $ret { + set failall 1 + if $standalone { + fail $test + } else { + catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db" + } + } else { + if $standalone { + pass $test + } } - expect "kadmin.local: " - send "quit\r" - expect "\r" - expect_after - if ![check_exit_status kadmin_local] { - if {!$standalone} { - catch "exec rm -f tmpdir/db.ok tmpdir/adb.db" + } + if $tgt_support_desmd5 { + # Make TGT support des-cbc-md5 + set test "kadmin.local TGT to SUPPORT_DESMD5" + set body { + if $failall { + break + } + spawn $KADMIN_LOCAL -r $REALMNAME + verbose "starting $test" + expect_after $def_exp_after + + expect "kadmin.local: " + send "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r" + # It echos... + expect "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r" + expect { + "Principal \"krbtgt/$REALMNAME@$REALMNAME\" modified.\r\n" { } + } + expect "kadmin.local: " + send "quit\r" + expect eof + catch expect_after + if ![check_exit_status kadmin_local] { + break + } + } + set ret [catch $body] + catch "expect eof" + catch expect_after + if $ret { + set failall 1 + if $standalone { + fail $test + } else { + catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db" + } + } else { + if $standalone { + pass $test } - return 0 } } - - if ![setup_kadmind_srvtab] { + # XXX should deal with envstack inside setup_kadmind_srvtab too + set ret [setup_kadmind_srvtab] + envstack_pop + if !$ret { return 0 } # create the admin database lock file - catch "exec touch tmpdir/adb.lock" - - if {$standalone} { - pass "kadmin_local" - } + catch "exec touch $tmppwd/adb.lock" + set last_passname_db $multipass_name return 1 } @@ -815,8 +1290,9 @@ proc start_kerberos_daemons { standalone } { } if {$standalone} { - catch "exec rm -f tmpdir/krb.log" - catch "exec rm -f tmpdir/kadmind.log" + catch "exec rm -f $tmppwd/krb.log" + catch "exec rm -f $tmppwd/kadmind.log" + catch "exec rm -f $tmppwd/krb5kdc_rcache" } # Start up the kerberos daemon @@ -829,43 +1305,72 @@ proc start_kerberos_daemons { standalone } { # The same thing is done a little later for the kadmind set kdc_lfile $tmppwd/kdc.log set kadmind_lfile $tmppwd/kadmind5.log - set retry 30 if ![file exists $kdc_lfile] then { catch [touch $kdc_lfile] } - sleep 2 - set kdc_start [file mtime $kdc_lfile] - spawn $KRB5KDC -r $REALMNAME -n - set kdc_pid [exp_pid] - set kdc_spawn_id $spawn_id + spawn tail -f $kdc_lfile + set tailf_spawn_id $spawn_id + set tailf_pid [exp_pid] - for {set count 0} {$count < $retry} {incr count} { - if { [file mtime $kdc_lfile] != $kdc_start } then { - break; - } - sleep 2 - } + set markstr "===MARK $tailf_pid [exec date] ===" + set f [open $kdc_lfile a] + puts $f $markstr + close $f - if {$count >= $retry} { - fail "krb5kdc" - stop_kerberos_daemons - return 0 + expect { + -i $tailf_spawn_id + -ex "$markstr\r\n" { } + timeout { + if {$standalone} { + verbose -log "tail -f timed out looking for mark" + fail "krb5kdc" + } else { + perror "krbkdc tail -f timed out looking for mark" + } + stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id + return 0 + } } - if ![regexp "commencing operation" [tail1 $kdc_lfile]] { - fail "krb5kdc" - stop_kerberos_daemons - return 0 + envstack_push + setup_kerberos_env kdc + spawn $KRB5KDC -r $REALMNAME -n + envstack_pop + set kdc_pid [exp_pid] + set kdc_spawn_id $spawn_id + + expect { + -i $tailf_spawn_id + -re "commencing operation\r\n" { } + timeout { + if {$standalone} { + verbose -log "krb5kdc startup timed out" + fail "krb5kdc" + } else { + perror "krb5kdc startup timed out" + } + stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id + return 0 + } } + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id if {$standalone} { pass "krb5kdc" } # Give the kerberos daemon a few seconds to get set up. - sleep 2 +# sleep 2 # @@ -880,66 +1385,107 @@ proc start_kerberos_daemons { standalone } { if ![file exists $kadmind_lfile] then { catch [touch $kadmind_lfile] - sleep 1 } - set kadmind_start [file mtime $kadmind_lfile] + spawn tail -f $kadmind_lfile + set tailf_spawn_id $spawn_id + set tailf_pid [exp_pid] + + set markstr "===MARK $tailf_pid [exec date] ===" + set f [open $kadmind_lfile a] + puts $f $markstr + close $f + + expect { + -i $tailf_spawn_id + -ex "$markstr\r\n" { } + timeout { + if {$standalone} { + verbose -log "tail -f timed out looking for mark" + fail "kadmind" + } else { + perror "kadmind tail -f timed out looking for mark" + } + stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id + return 0 + } + } # Start up the kadmind daemon # XXXX kadmind uses stderr a lot. the sh -c and redirect can be - # removed when this is fixed + # removed when this is fixed + envstack_push + setup_kerberos_env kdc spawn $BINSH -c "exec $KADMIND -r $REALMNAME -nofork 2>>$kadmind_lfile" + envstack_pop set kadmind_pid [exp_pid] set kadmind_spawn_id $spawn_id - for {set count 0} {$count < $retry} {incr count} { - if { [file mtime $kadmind_lfile] != $kadmind_start } then { - break; - } - sleep 1 - } - - if {$count >= $retry} { - fail "kadmin5 (starting)" - if [info exists start_save_ktname] { - set env(KRB5_KTNAME) $start_save_ktname - unset start_save_ktname - } - stop_kerberos_daemons - return 0 - } - # Restore KRB5_KTNAME if [info exists start_save_ktname] { set env(KRB5_KTNAME) $start_save_ktname unset start_save_ktname } - switch -regexp [tail1 $kadmind_lfile] { - "cannot initialize network" { - fail "kadmind (network init)" + expect { + -i $tailf_spawn_id + "Seeding random number" exp_continue + "cannont initialize network" { + if {$standalone} { + verbose -log "kadmind failed network init" + fail "kadmind" + } else { + perror "kadmind failed network init" + } stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id return 0 } "cannot bind to network address" { - fail "kadmind (bind)" + if {$standalone} { + verbose -log "kadmind failed to bind socket" + fail "kadmind" + } else { + perror "kadmind failed to bind socket" + } stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id return 0 } "starting" { } - default { - fail "kadmind (startup)" + timeout { + if {$standalone} { + verbose -log "kadmind failed to start" + fail "kadmind" + } else { + verbose -log "kadmind failed to start" + perror "kadmind failed to start" + } +#sleep 10 stop_kerberos_daemons + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id return 0 } } + exec kill $tailf_pid + expect -i $tailf_spawn_id eof + wait -i $tailf_spawn_id if {$standalone} { pass "kadmind" } # Give the kadmind daemon a few seconds to get set up. - sleep 2 +# sleep 2 return 1 } @@ -953,9 +1499,11 @@ proc stop_kerberos_daemons { } { global kadmind_pid global kadmind_spawn_id + verbose "entered stop_kerberos_daemons" + if [info exists kdc_pid] { - catch "close -i $kdc_spawn_id" catch "exec kill $kdc_pid" + catch "expect eof" set kdc_list [wait -i $kdc_spawn_id] verbose "wait -i $kdc_spawn_id returned $kdc_list (kdc)" unset kdc_pid @@ -963,14 +1511,16 @@ proc stop_kerberos_daemons { } { } if [info exists kadmind_pid] { - catch "close -i $kadmind_spawn_id" catch "exec kill $kadmind_pid" + catch "expect eof" set kadmind_list [wait -i $kadmind_spawn_id] verbose "wait -i $kadmind_spawn_id returned $kadmind_list (kadmind5)" unset kadmind_pid unset kadmind_list } + verbose "exiting stop_kerberos_daemons" + return 1 } @@ -987,45 +1537,58 @@ proc add_kerberos_key { kkey standalone } { global spawn_id # Use kadmin to add an key. - spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME" - expect_after { - "Cannot contact any KDC" { - fail "kadmin interactive add $kkey lost KDC" - catch "expect_after" - return 0 + set test "kadmin ank $kkey" + set body { + envstack_push + setup_kerberos_env client + spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME" + envstack_pop + verbose "starting $test" + expect_after { + "Cannot contact any KDC" { + set test "$test (lost KDC)" + break + } + timeout { + set test "$test (timeout)" + break + } + eof { + set test "$test (eof)" + break + } } - timeout { - fail "kadmin $kkey" - catch "expect_after" - return 0 + expect "Enter password:" + send "adminpass$KEY\r" + expect "Enter password for principal \"$kkey@$REALMNAME\":" + send "$kkey" + send "$KEY\r" + expect "Re-enter password for principal \"$kkey@$REALMNAME\":" + send "$kkey" + send "$KEY\r" + expect { + "Principal \"$kkey@$REALMNAME\" created" { } + "Principal or policy already exists while creating*" { } } - eof { - fail "kadmin $kkey" - return 0 + expect eof + if ![check_exit_status kadmin] { + break } } - expect "Enter password:" - send "adminpass$KEY\r" - expect "Enter password for principal \"$kkey@$REALMNAME\":" - send "$kkey" - send "$KEY\r" - expect "Re-enter password for principal \"$kkey@$REALMNAME\":" - send "$kkey" - send "$KEY\r" - expect { - "Principal \"$kkey@$REALMNAME\" created" { } - "Principal or policy already exists while creating*" { expect eof } - } - catch "expect_after" - if ![check_exit_status kadmin] { + set ret [catch $body] + catch "expect eof" + catch expect_after + if $ret { + if $standalone { + fail $test + } return 0 + } else { + if $standalone { + pass $test + } + return 1 } - - if {$standalone} { - pass "kadmin $kkey" - } - - return 1 } # add_random_key @@ -1041,35 +1604,46 @@ proc add_random_key { kkey standalone } { global spawn_id # Use kadmin to add an key. - spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME" - expect_after { - timeout { - fail "kadmin $kkey" - catch "expect_after" - return 0 + set test "kadmin ark $kkey" + set body { + envstack_push + setup_kerberos_env client + spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME" + envstack_pop + expect_after { + timeout { + set test "$test (timeout)" + break + } + eof { + set test "$test (eof)" + break + } } - eof { - fail "kadmin $kkey" - catch "expect_after" - return 0 + expect "Enter password:" + send "adminpass$KEY\r" + expect { + "Principal \"$kkey@$REALMNAME\" created" { } + "Principal or policy already exists while creating*" { } + } + expect eof + if ![check_exit_status kadmin] { + break } } - expect "Enter password:" - send "adminpass$KEY\r" - expect { - "Principal \"$kkey@$REALMNAME\" created" { } - "Principal or policy already exists while creating*" { expect eof} - } - catch "expect_after" - if ![check_exit_status kadmin] { + if [catch $body] { + catch expect_after + if $standalone { + fail $test + } return 0 + } else { + catch expect_after + if $standalone { + pass $test + } + return 1 } - - if {$standalone} { - pass "kadmin $kkey" - } - - return 1 } # setup_srvtab @@ -1087,11 +1661,11 @@ proc setup_srvtab { standalone {id host} } { global spawn_id global last_service - if {!$standalone && [file exists tmpdir/srvtab] && $last_service == $id} { + if {!$standalone && [file exists $tmppwd/srvtab] && $last_service == $id} { return 1 } - catch "exec rm -f tmpdir/srvtab tmpdir/srvtab.old" + catch "exec rm -f $tmppwd/srvtab $tmppwd/srvtab.old" if ![get_hostname] { return 0 @@ -1099,12 +1673,23 @@ proc setup_srvtab { standalone {id host} } { catch "exec rm -f $hostname-new-srvtab" + envstack_push + setup_kerberos_env kdc spawn $KADMIN_LOCAL -r $REALMNAME + envstack_pop expect_after { + -re "(.*)\r\nkadmin.local: " { + fail "kadmin.local srvtab (unmatched output: $expect_out(1,string))" + if {!$standalone} { + catch "exec rm -f $tmppwd/srvtab" + } + catch "expect_after" + return 0 + } timeout { fail "kadmin.local srvtab" if {!$standalone} { - catch "exec rm -f tmpdir/srvtab" + catch "exec rm -f $tmppwd/srvtab" } catch "expect_after" return 0 @@ -1112,7 +1697,7 @@ proc setup_srvtab { standalone {id host} } { eof { fail "kadmin.local srvtab" if {!$standalone} { - catch "exec rm -f tmpdir/srvtab" + catch "exec rm -f $tmppwd/srvtab" } catch "expect_after" return 0 @@ -1120,23 +1705,34 @@ proc setup_srvtab { standalone {id host} } { } expect "kadmin.local: " send "xst -k $hostname-new-srvtab $id/$hostname\r" - expect -re ".*Entry for principal $id/$hostname.* added to keytab WRFILE:$hostname-new-srvtab." + expect "xst -k $hostname-new-srvtab $id/$hostname\r\n" + expect { + -re ".*Entry for principal $id/$hostname.* added to keytab WRFILE:$hostname-new-srvtab." { } + -re "\r\nkadmin.local: " { + if {$standalone} { + fail "kadmin.local srvtab" + } else { + catch "exec rm -f $tmppwd/srvtab" + } + catch expect_after + return 0 + } + } expect "kadmin.local: " send "quit\r" - expect "\r" - expect_after + expect eof + catch expect_after if ![check_exit_status "kadmin.local srvtab"] { if {!$standalone} { - catch "exec rm -f tmpdir/srvtab" + catch "exec rm -f $tmppwd/srvtab" } return 0 } - catch "exec mv -f $hostname-new-srvtab tmpdir/srvtab" exec_output + catch "exec mv -f $hostname-new-srvtab $tmppwd/srvtab" exec_output if ![string match "" $exec_output] { - send_log "$exec_output\n" - verbose $exec_output - send_error "ERROR: can't mv new srvtab\n" + verbose -log "$exec_output" + perror "can't mv new srvtab" return 0 } @@ -1146,7 +1742,7 @@ proc setup_srvtab { standalone {id host} } { # Make the srvtab file globally readable in case we are using a # root shell and the srvtab is NFS mounted. - catch "exec chmod a+r tmpdir/srvtab" + catch "exec chmod a+r $tmppwd/srvtab" # Remember what we just extracted set last_service $id @@ -1184,22 +1780,371 @@ proc kinit { name pass standalone } { } } send "$pass\r" - # This last expect seems useless, but without it the test hangs on - # AIX. + expect eof + if ![check_exit_status kinit] { + return 0 + } + + if {$standalone} { + pass "kinit" + } + + return 1 +} + +proc kinit_kt { name keytab standalone testname } { + global REALMNAME + global KINIT + global spawn_id + + # Use kinit to get a ticket. + # + # For now always get forwardable tickets. Later when we need to make + # tests that distiguish between forwardable tickets and otherwise + # we should but another option to this proc. --proven + # + spawn $KINIT -5 -f -k -t $keytab $name@$REALMNAME + expect { + timeout { + fail "kinit $testname" + return 0 + } + eof { } + } + if ![check_exit_status "kinit $testname"] { + return 0 + } + + if {$standalone} { + pass "kinit $testname" + } + + return 1 +} + +# List tickets. Requires client and server names, and test name. +# Checks that klist exist status is zero. +# Records pass or fail, and returns 1 or 0. +proc do_klist { myname servname testname } { + global KLIST + global tmppwd + + spawn $KLIST -5 -e + expect { + -re "Ticket cache:\[ \]*(.+:)?$tmppwd/tkt.*Default principal:\[ \]*$myname.*$servname\r\n" { + verbose "klist started" + } + timeout { + fail $testname + return 0 + } + eof { + fail $testname + return 0 + } + } + expect { "\r" { } + eof { } } + if ![check_exit_status $testname] { + return 0 + } + pass $testname + return 1 +} + +proc do_klist_kt { keytab testname } { + global KLIST + global tmppwd + + spawn $KLIST -5 -e -k $keytab + expect { + -re "Keytab name:\[ \]*(.+:)?.*KVNO Principal\r\n---- -*\r\n" { + verbose "klist started" + } + timeout { + fail $testname + return 0 + } + eof { + fail $testname + return 0 + } + } + set more 1 + while {$more} { + expect { + -re { *[0-9][0-9]* *[a-zA-Z/@.-]* \([/a-zA-Z 0-9-]*\) *\r\n} { + verbose -log "key: $expect_out(buffer)" + } + eof { set more 0 } + } + } + + if ![check_exit_status $testname] { + return 0 + } + pass $testname + return 1 +} + +proc do_klist_err { testname } { + global KLIST + global spawn_id + + spawn $KLIST -5 + expect { + -re "klist: No credentials cache found.*\r\n" { + verbose "klist started" + } + timeout { + fail $testname + return 0 + } + eof { + fail $testname + return 0 + } + } + # We can't use check_exit_status, because we expect an exit status + # of 1. + set status_list [wait -i $spawn_id] + verbose "wait -i $spawn_id returned $status_list ($testname)" + if { [lindex $status_list 2] != 0 } { + fail "$testname (bad exit status) $status_list" + return 0 + } else { if { [lindex $status_list 3] != 1 } { + fail "$testname (bad exit status) $status_list" + return 0 + } else { + pass $testname + } } + return 1 +} + +proc do_kdestroy { testname } { + global KDESTROY + spawn $KDESTROY -5 + if ![check_exit_status $testname] { + fail $testname + return 0 + } + pass $testname + return 1 +} + +proc xst { keytab name } { + global KADMIN_LOCAL + global REALMNAME + + envstack_push + setup_kerberos_env kdc + spawn $KADMIN_LOCAL -r $REALMNAME + envstack_pop + catch expect_after + expect_after { + -re "(.*)\r\nkadmin.local: " { + fail "kadmin.local xst $keytab (unmatched output: $expect_out(1,string)" + catch "expect_after" + return 0 + } + timeout { + fail "kadmin.local xst $keytab (timeout)" + catch "expect_after" + return 0 + } + eof { + fail "kadmin.local xst $keytab (eof)" + catch "expect_after" + return 0 + } + } + expect "kadmin.local: " + send "xst -k $keytab $name\r" + expect -re "xst -k \[^\r\n\]*\r\n.*Entry for principal .* added to keytab WRFILE:.*\r\nkadmin.local: " + send "quit\r" + expect eof + catch expect_after + if ![check_exit_status "kadmin.local $keytab"] { + perror "kadmin.local xst $keytab exited abnormally" + return 0 + } + return 1 +} + +# v4_compatible_enctype +# Returns 1 if v4 testing is enabled this passes encryption types are compatable with kerberos 4 work +proc v4_compatible_enctype {} { + global supported_enctypes + global KRBIV + + if ![info exists KRBIV] { + return 0; + } + + if { $KRBIV && [string first des-cbc-crc:v4 "$supported_enctypes"] >= 0} { + return 1 + } else { + return 0 + } +} + +# kinit +# Use kinit to get a ticket. If the argument is non-zero, call pass +# at relevant points. Returns 1 on success, 0 on failure. + +proc v4kinit { name pass standalone } { + global REALMNAME + global KINIT + global spawn_id + + # Use kinit to get a ticket. + # + # For now always get forwardable tickets. Later when we need to make + # tests that distiguish between forwardable tickets and otherwise + # we should but another option to this proc. --proven + # + spawn $KINIT -4 $name@$REALMNAME + expect { + "Password for $name@$REALMNAME:" { + verbose "v4kinit started" + } + timeout { + fail "v4kinit" + return 0 + } + eof { + fail "v4kinit" + return 0 + } + } + send "$pass\r" expect eof + if ![check_exit_status kinit] { + return 0 + } + + if {$standalone} { + pass "v4kinit" + } + + return 1 +} +proc v4kinit_kt { name keytab standalone } { + global REALMNAME + global KINIT + global spawn_id + + # Use kinit to get a ticket. + # + # For now always get forwardable tickets. Later when we need to make + # tests that distiguish between forwardable tickets and otherwise + # we should but another option to this proc. --proven + # + spawn $KINIT -4 -k -t $keytab $name@$REALMNAME + expect { + timeout { + fail "v4kinit" + return 0 + } + eof { } + } if ![check_exit_status kinit] { return 0 } if {$standalone} { - pass "kinit" + pass "v4kinit" + } + + return 1 +} + +# List v4 tickets. +# Client and server are regular expressions. +proc v4klist { client server testname } { + global KLIST + global tmppwd + + spawn $KLIST -4 + expect { + -re "Kerberos 4 ticket cache:\[ \]*(.+:)?$tmppwd/tkt.*Principal:\[ \]*$client.*$server\r\n" { + verbose "klist started" + } + timeout { + fail $testname + return 0 + } + eof { + fail $testname + return 0 + } } + expect { + "\r" { } + eof { } + } + + if ![check_exit_status $testname] { + return 0 + } + pass $testname + return 1 +} + +# Destroy tickets. +proc v4kdestroy { testname } { + global KDESTROY + spawn $KDESTROY -4 + if ![check_exit_status $testname] { + return 0 + } + pass $testname + return 1 +} + +# Try to list the krb4 tickets -- there shouldn't be any ticket file. +proc v4klist_none { testname } { + global KLIST + global tmppwd + + # Double check that the ticket was destroyed. + spawn $KLIST -4 + expect { + -re "Kerberos 4 ticket cache:\[ \]*(.+:)?$tmppwd/tkt.*klist: You have no tickets cached.*\r\n" { + verbose "v4klist started" + pass "$testname (output)" + } + timeout { + fail "$testname (output)" + # Skip the 'wait' below, if it's taking too long. + untested "$testname (exit status)" + return 0 + } + eof { + fail "$testname (output)" + } + } + # We can't use check_exit_status, because we expect an exit status + # of 1. + set status_list [wait -i $spawn_id] + verbose "wait -i $spawn_id returned $status_list (v4klist)" + if { [lindex $status_list 2] != 0 } { + fail "$testname (exit status)" + return 0 + } else { + if { [lindex $status_list 3] != 1 } { + fail "$testname (exit status)" + return 0 + } else { + pass "$testname (exit status)" + } + } return 1 } @@ -1217,6 +2162,8 @@ proc setup_root_shell { testname } { global BINSH global ROOT_PROMPT global KEY + global RLOGIN + global RLOGIN_FLAGS global hostname global rlogin_spawn_id global rlogin_pid @@ -1224,15 +2171,22 @@ proc setup_root_shell { testname } { global env global krb5_init_vars + global timeout # Make sure we are using the original values of the environment # variables. This means that the caller must call # setup_kerberos_env after calling this procedure. + # XXX fixme to deal with envstack restore_kerberos_env setup_runtime_env + set me [exec whoami] + if [string match root $me] { + return [setup_root_shell_noremote $testname] + } + if ![get_hostname] { return 0 } @@ -1248,45 +2202,50 @@ proc setup_root_shell { testname } { # send "rootpassword\r" # exp_continue - spawn rlogin $hostname -l root + eval spawn $RLOGIN $hostname -l root $RLOGIN_FLAGS set rlogin_spawn_id $spawn_id set rlogin_pid [exp_pid] + set old_timeout $timeout + set timeout 300 + expect { - "word:" { - untested "$testname test requires ability to rlogin as root" + -re "word:|erberos rlogin failed|ection refused|ection reset by peer" { + note "$testname test requires ability to rlogin as root" + unsupported "$testname" + set timeout $old_timeout stop_root_shell return 0 } - "Kerberos rlogin failed" { - untested "$testname test requires ability to rlogin as root" + -re "$ROOT_PROMPT" { } + timeout { + perror "timeout from rlogin $hostname -l root" + perror "If you have an unusual root prompt," + perror "try running with ROOT_PROMPT=\"regexp\"" + set timeout $old_timeout stop_root_shell return 0 } eof { - untested "$testname test requires ability to rlogin as root" - stop_root_shell - return 0 - } - -re "$ROOT_PROMPT" { } - timeout { - send_error "ERROR: timeout from rlogin $hostname -l root\n" - send_error "ERROR: If you have an unusual root prompt,\n" - send_error "ERROR: try running with ROOT_PROMPT=\"regexp\"\n" + perror "eof from rlogin $hostname -l root" stop_root_shell + set timeout $old_timeout + catch "expect_after" return 0 } } expect_after { timeout { - send_error "ERROR: timeout from rlogin $hostname -l root\n" + perror "timeout from rlogin $hostname -l root" stop_root_shell + set timeout $old_timeout catch "expect_after" return 0 } eof { - send_error "ERROR: eof from rlogin $hostname -l root\n" + perror "eof from rlogin $hostname -l root" stop_root_shell + set timeout $old_timeout catch "expect_after" return 0 } @@ -1308,7 +2267,7 @@ proc setup_root_shell { testname } { } # Set up our krb5.conf - send "KRB5_CONFIG=$tmppwd/krb5.conf\r" + send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r" expect { -re "$ROOT_PROMPT" { } } @@ -1337,13 +2296,96 @@ proc setup_root_shell { testname } { expect { -re "$ROOT_PROMPT" { } "$dir:" { - send_error "ERROR: root shell can not cd to $dir\n" + perror "root shell can not cd to $dir" + set timeout $old_timeout stop_root_shell return 0 } } - restore_runtime_env + expect_after + set timeout $old_timeout + + return 1 +} + +proc setup_root_shell_noremote { testname } { + global BINSH + global ROOT_PROMPT + global KEY + global hostname + global rlogin_spawn_id + global rlogin_pid + global tmppwd + global env + global krb5_init_vars + + eval spawn $BINSH + set rlogin_spawn_id $spawn_id + set rlogin_pid [exp_pid] + + expect_after { + timeout { + perror "timeout from root shell" + stop_root_shell + catch "expect_after" + return 0 + } + eof { + perror "eof from root shell" + stop_root_shell + catch "expect_after" + return 0 + } + } + expect { + -re "$ROOT_PROMPT" { } + } + + # Set up a shell variable tmppwd. The callers use this to keep + # command line lengths down. The command line length is important + # because we are feeding input to a shell via a pty. On some + # systems a pty will only accept 255 characters. + send "tmppwd=$tmppwd\r" + expect { + -re "$ROOT_PROMPT" { } + } + + # Set up our krb5.conf + send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r" + expect { + -re "$ROOT_PROMPT" { } + } + send "export KRB5_CONFIG\r" + expect { + -re "$ROOT_PROMPT" { } + } + + # For all of our runtime environment variables - send them over... + foreach i $krb5_init_vars { + regexp "^(\[^=\]*)=(.*)" $i foo evar evalue + send "$evar=$env($evar)\r" + expect { + -re "$ROOT_PROMPT" { } + } + + send "export $evar\r" + expect { + -re "$ROOT_PROMPT" { } + } + } + + # Move over to the right directory. + set dir [pwd] + send "cd $dir\r" + expect { + -re "$ROOT_PROMPT" { } + "$dir:" { + perror "root shell can not cd to $dir" + stop_root_shell + return 0 + } + } expect_after @@ -1377,8 +2419,7 @@ proc check_date { date } { scan $date "%s %s %d %d:%d:%d %s %d" adow amon adom ahr amn asc atz ayr scan $ndate "%s %s %d %d:%d:%d %s %d" ndow nmon ndom nhr nmn nsc ntz nyr if { $atz != $ntz } { - verbose "date check failed: $atz != $ntz" - send_log "date check failed: $atz != $ntz\n" + verbose -log "date check failed: $atz != $ntz" return 0 } return 1 @@ -1421,5 +2462,17 @@ proc setup_wrapper { file command } { return 1 } - +proc krb_exit { } { + stop_kerberos_daemons +} + +# helpful sometimes for debugging the test suite +proc spawn_xterm { } { + global env + foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST} { + global $i + set env($i) [set $i] + } + exec "xterm" +} |