1# Basic expect script for Kerberos tests. 2# This is a DejaGnu test script. 3# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>. 4# This script is automatically run by DejaGnu before running any of 5# the Kerberos test scripts. 6 7# This file provides several functions which deal with a local 8# Kerberos database. We have to do this such that we don't interfere 9# with any existing Kerberos database. We will create all the files 10# in the directory $tmppwd, which will have been created by the 11# testsuite default script. We will use $REALMNAME as our Kerberos 12# realm name, defaulting to KRBTEST.COM. 13 14set timeout 100 15set stty_init {erase \^h kill \^u} 16set env(TERM) dumb 17 18set des3_krbtgt 0 19set tgt_support_desmd5 0 20set supported_enctypes "des-cbc-crc:normal" 21set kdc_supported_enctypes "des-cbc-crc:normal" 22 23# The names of the individual passes must be unique; lots of things 24# depend on it. The PASSES variable may not contain comments; only 25# small pieces get evaluated, so comments will do strange things. 26 27# Most of the purpose of using multiple passes is to exercise the 28# dependency of various bugs on configuration file settings, 29# particularly with regards to encryption types. 30 31# The des.no-kdc-md5 pass will fail if the KDC does not constrain 32# session key enctypes to those in its permitted_enctypes list. It 33# works by assuming enctype similarity, thus allowing the client to 34# request a des-cbc-md4 session key. Since only des-cbc-crc is in the 35# KDC's permitted_enctypes list, the TGT will be unusable. 36 37# KLUDGE for tracking down leaking ptys 38if 0 { 39 rename spawn oldspawn 40 rename wait oldwait 41 proc spawn { args } { 42 upvar 1 spawn_id spawn_id 43 verbose "spawn: args=$args" 44 set pid [eval oldspawn $args] 45 verbose "spawn: pid=$pid spawn_id=$spawn_id" 46 return $pid 47 } 48 proc wait { args } { 49 upvar 1 spawn_id spawn_id 50 verbose "wait: args=$args" 51 set ret [eval oldwait $args] 52 verbose "wait: $ret" 53 return $ret 54 } 55} 56 57if { [string length $VALGRIND] } { 58 rename spawn valgrind_aux_spawn 59 proc spawn { args } { 60 global VALGRIND 61 upvar 1 spawn_id spawn_id 62 set newargs {} 63 set inflags 1 64 set eatnext 0 65 foreach arg $args { 66 if { $arg == "-ignore" \ 67 || $arg == "-open" \ 68 || $arg == "-leaveopen" } { 69 lappend newargs $arg 70 set eatnext 1 71 continue 72 } 73 if [string match "-*" $arg] { 74 lappend newargs $arg 75 continue 76 } 77 if { $eatnext } { 78 set eatnext 0 79 lappend newargs $arg 80 continue 81 } 82 if { $inflags } { 83 set inflags 0 84 # Only run valgrind for local programs, not 85 # system ones. 86#&&![string match "/bin/sh" $arg] sh is used to start kadmind! 87 if [string match "/" [string index $arg 0]]&&![string match "/bin/ls" $arg]&&![regexp {/kshd$} $arg] { 88 set newargs [concat $newargs $VALGRIND] 89 } 90 } 91 lappend newargs $arg 92 } 93 set pid [eval valgrind_aux_spawn $newargs] 94 return $pid 95 } 96} 97 98# The des.des3-tgt.no-kdc-des3 pass will fail if the KDC doesn't 99# constrain ticket key enctypes to those in permitted_enctypes. It 100# does this by not putting des3 in the permitted_enctypes, while 101# creating a TGT princpal that has a des3 key as well as a des key. 102 103# XXX -- master_key_type is fragile w.r.t. permitted_enctypes; it is 104# possible to configure things such that you have a master_key_type 105# that is not permitted, and the error message used to be cryptic. 106 107set passes { 108 { 109 des 110 mode=udp 111 des3_krbtgt=0 112 {supported_enctypes=des-cbc-crc:normal} 113 {kdc_supported_enctypes=des-cbc-crc:normal} 114 {dummy=[verbose -log "DES TGT, DES enctype"]} 115 } 116 { 117 des.des3tgt 118 mode=udp 119 des3_krbtgt=1 120 {supported_enctypes=des-cbc-crc:normal} 121 {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} 122 {dummy=[verbose -log "DES3 TGT, DES enctype"]} 123 } 124 { 125 des3 126 mode=udp 127 des3_krbtgt=1 128 {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} 129 {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} 130 {dummy=[verbose -log "DES3 TGT, DES3 + DES enctypes"]} 131 } 132 { 133 aes 134 mode=udp 135 des3_krbtgt=0 136 {supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal} 137 {kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal} 138 {permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des-cbc-crc} 139 {permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des-cbc-crc} 140 {permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des-cbc-crc} 141 {master_key_type=aes256-cts-hmac-sha1-96} 142 {dummy=[verbose -log "AES + DES enctypes"]} 143 } 144 { 145 aes-des3 146 mode=udp 147 des3_krbtgt=0 148 {supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal} 149 {kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal} 150 {permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 151 {permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 152 {permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 153 {master_key_type=aes256-cts-hmac-sha1-96} 154 {dummy=[verbose -log "AES + DES enctypes"]} 155 } 156 { 157 des3-aes 158 mode=udp 159 des3_krbtgt=1 160 {supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal} 161 {kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal} 162 {permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 163 {permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 164 {permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc} 165 {master_key_type=aes256-cts-hmac-sha1-96} 166 {dummy=[verbose -log "AES + DES enctypes, DES3 TGT"]} 167 } 168 { 169 des-v4 170 mode=udp 171 des3_krbtgt=0 172 {supported_enctypes=des-cbc-crc:v4} 173 {kdc_supported_enctypes=des-cbc-crc:v4} 174 {default_tkt_enctypes(client)=des-cbc-crc} 175 {dummy=[verbose -log "DES TGT, DES-CRC enctype, V4 salt"]} 176 } 177 { 178 des-md5-v4 179 mode=udp 180 des3_krbtgt=0 181 {supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4} 182 {kdc_supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4} 183 {default_tkt_enctypes(client)=des-cbc-md5 des-cbc-crc} 184 {dummy=[verbose -log "DES TGT, DES-MD5 and -CRC enctypes, V4 salt"]} 185 } 186 { 187 all-des-des3-enctypes 188 mode=udp 189 des3_krbtgt=1 190 {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \ 191 des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \ 192 des-cbc-md4:normal} 193 {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \ 194 des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \ 195 des-cbc-md4:normal} 196 {dummy=[verbose -log "DES3 TGT, many DES3 + DES enctypes"]} 197 } 198 { 199 des.no-kdc-md5 200 mode=udp 201 des3_krbtgt=0 202 tgt_support_desmd5=0 203 {permitted_enctypes(kdc)=des-cbc-crc} 204 {default_tgs_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} 205 {default_tkt_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} 206 {supported_enctypes=des-cbc-crc:normal} 207 {kdc_supported_enctypes=des-cbc-crc:normal} 208 {master_key_type=des-cbc-crc} 209 {dummy=[verbose -log \ 210 "DES TGT, KDC permitting only des-cbc-crc"]} 211 } 212 { 213 des.des3-tgt.no-kdc-des3 214 mode=udp 215 tgt_support_desmd5=0 216 {permitted_enctypes(kdc)=des-cbc-crc} 217 {default_tgs_enctypes(client)=des-cbc-crc} 218 {default_tkt_enctypes(client)=des-cbc-crc} 219 {supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} 220 {kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal} 221 {master_key_type=des-cbc-crc} 222 {dummy=[verbose -log \ 223 "DES3 TGT, KDC permitting only des-cbc-crc"]} 224 } 225} 226 227# des.md5-tgt is set as unused, since it won't trigger the error case 228# if SUPPORT_DESMD5 isn't honored. 229 230# The des.md5-tgt pass will fail if enctype similarity is inconsisent; 231# between 1.0.x and 1.1, the decrypt functions became more strict 232# about matching enctypes, while the KDB retrieval functions didn't 233# coerce the enctype to match what was requested. It works by setting 234# SUPPORT_DESMD5 on the TGT principal, forcing an enctype of 235# des-cbc-md5 on the TGT key. Since the database only contains a 236# des-cbc-crc key, the decrypt will fail if enctypes are not coerced. 237 238# des.no-kdc-md5.client-md4-skey is retained in unsed_passes, even 239# though des.no-kdc-md5 is roughly equivalent, since the associated 240# comment needs additional investigation at some point re the kadmin 241# client. 242 243# The des.no-kdc-md5.client-md4-skey will fail on TGS requests due to 244# the KDC issuing session keys that it won't accept. It will also 245# fail for a kadmin client, but for different reasons, since the kadm5 246# library does some curious filtering of enctypes, and also uses 247# get_in_tkt() rather than get_init_creds(); the former does an 248# intersection of the enctypes provided by the caller and those listed 249# in the config file! 250 251set unused_passes { 252 { 253 des.md5-tgt 254 des3_krbtgt=0 255 tgt_support_desmd5=1 256 supported_enctypes=des-cbc-crc:normal 257 kdc_supported_enctypes=des-cbc-crc:normal 258 {permitted_enctypes(kdc)=des-cbc-md5 des-cbc-md4 des-cbc-crc} 259 {permitted_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc} 260 {dummy=[verbose -log "DES TGT, SUPPORTS_DESMD5"]} 261 } 262 { 263 des.md5-tgt.no-kdc-md5 264 des3_krbtgt=0 265 tgt_support_desmd5=1 266 {permitted_enctypes(kdc)=des-cbc-crc} 267 {default_tgs_enctypes(client)=des-cbc-crc} 268 {default_tkt_enctypes(client)=des-cbc-crc} 269 {supported_enctypes=des-cbc-crc:normal} 270 {kdc_supported_enctypes=des-cbc-crc:normal} 271 {master_key_type=des-cbc-crc} 272 {dummy=[verbose -log \ 273 "DES TGT, SUPPORTS_DESMD5, KDC permitting only des-cbc-crc"]} 274 } 275 { 276 des.no-kdc-md5.client-md4-skey 277 des3_krbtgt=0 278 {permitted_enctypes(kdc)=des-cbc-crc} 279 {permitted_enctypes(client)=des-cbc-crc des-cbc-md4} 280 {default_tgs_enctypes(client)=des-cbc-crc des-cbc-md4} 281 {default_tkt_enctypes(client)=des-cbc-md4} 282 {supported_enctypes=des-cbc-crc:normal} 283 {kdc_supported_enctypes=des-cbc-crc:normal} 284 {dummy=[verbose -log \ 285 "DES TGT, DES enctype, KDC permitting only des-cbc-crc, client requests des-cbc-md4 session key"]} 286 } 287 { 288 all-enctypes 289 des3_krbtgt=1 290 {supported_enctypes=\ 291 aes256-cts-hmac-sha1-96:normal aes256-cts-hmac-sha1-96:norealm \ 292 aes128-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:norealm \ 293 des3-cbc-sha1:normal des3-cbc-sha1:none \ 294 des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \ 295 des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \ 296 } 297 {kdc_supported_enctypes=\ 298 des3-cbc-sha1:normal des3-cbc-sha1:none \ 299 des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \ 300 des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \ 301 } 302 {dummy=[verbose -log "DES3 TGT, default enctypes"]} 303 } 304 { 305 aes-tcp 306 mode=tcp 307 des3_krbtgt=0 308 {supported_enctypes=aes256-cts-hmac-sha1-96:normal} 309 {kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal} 310 {permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96} 311 {permitted_enctypes(client)=aes256-cts-hmac-sha1-96} 312 {permitted_enctypes(server)=aes256-cts-hmac-sha1-96} 313 {master_key_type=aes256-cts-hmac-sha1-96} 314 {dummy=[verbose -log "AES via TCP"]} 315 } 316} 317# {supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal } 318# {kdc_supported_enctypes= des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal} 319 320# This shouldn't be necessary on dejagnu-1.4 and later, but 1.3 seems 321# to need it because its runtest.exp doesn't deal with PASS at all. 322if [info exists PASS] { 323 foreach pass $passes { 324 if { [lsearch -exact $PASS [lindex $pass 0]] >= 0 } { 325 lappend MULTIPASS $pass 326 } 327 } 328} else { 329 set MULTIPASS $passes 330} 331 332set last_passname_conf "" 333set last_passname_db "" 334 335# We do everything in a temporary directory. 336if ![info exists TMPDIR] { 337 set tmppwd "[pwd]/tmpdir" 338 if ![file isdirectory $tmppwd] { 339 catch "exec mkdir $tmppwd" status 340 } 341} else { 342 set tmppwd $TMPDIR 343} 344verbose "tmppwd=$tmppwd" 345 346# On Ultrix, use /bin/sh5 in preference to /bin/sh. 347if ![info exists BINSH] { 348 if [file exists /bin/sh5] { 349 set BINSH /bin/sh5 350 } else { 351 set BINSH /bin/sh 352 } 353} 354 355# For security, we must not use generally known passwords. This is 356# because some of the tests may be run as root. If the passwords were 357# generally know, then somebody could work out the appropriate 358# Kerberos ticket to use, and come in when, say, the telnetd daemon 359# was being tested by root. The window for doing this is very very 360# small, so the password does not have to be perfect, it just can't be 361# constant. 362if ![info exists KEY] { 363 catch {exec $BINSH -c "echo $$"} KEY 364 verbose "KEY is $KEY" 365 set keyfile [open $tmppwd/KEY w] 366 puts $keyfile "$KEY" 367 close $keyfile 368} 369 370# Clear away any files left over from a previous run. 371# We can't use them now because we don't know the right KEY. 372# krb5.conf might change if running tests on another host 373file delete $tmppwd/krb5.conf $tmppwd/kdc.conf $tmppwd/slave.conf \ 374 $tmppwd/krb5.client.conf $tmppwd/krb5.server.conf \ 375 $tmppwd/krb5.kdc.conf $tmppwd/krb5.slave.conf 376 377proc delete_db {} { 378 global tmppwd 379 # Master and slave db files 380 file delete $tmppwd/kdc-db $tmppwd/kdc-db.ok $tmppwd/kdc-db.kadm5 \ 381 $tmppwd/kdc-db.kadm5.lock \ 382 $tmppwd/kdc-db.ulog \ 383 $tmppwd/slave-db $tmppwd/slave-db.ok $tmppwd/slave-db.kadm5 $tmppwd/slave-db.kadm5.lock \ 384 $tmppwd/slave-db~ $tmppwd/slave-db~.ok $tmppwd/slave-db~.kadm5 $tmppwd/slave-db~.kadm5.lock 385 # Creating a new database means we need a new srvtab. 386 file delete $tmppwd/srvtab $tmppwd/cpw_srvtab 387} 388 389delete_db 390 391# Put the installed kerberos directories on PATH. 392# This needs to be fixed for V5. 393# set env(PATH) $env(PATH):/usr/kerberos/bin:/usr/kerberos/etc 394# verbose "PATH=$env(PATH)" 395 396# Some of the tests expect $env(USER) to be set. 397if ![info exists env(USER)] { 398 if [info exists env(LOGNAME)] { 399 set env(USER) $env(LOGNAME) 400 } else { 401 if [info exists logname] { 402 set env(USER) $logname 403 } else { 404 catch "exec whoami" env(USER) 405 } 406 } 407} 408 409# set the realm. The user can override this on the runtest line. 410if ![info exists REALMNAME] { 411 set REALMNAME "KRBTEST.COM" 412} 413verbose "Test realm is $REALMNAME" 414 415# Find some programs we need. We use the binaries from the build tree 416# if they exist. If they do not, then they must be in PATH. We 417# expect $objdir to be ...tests/dejagnu. 418 419foreach i { 420 {KDB5_UTIL $KRB5_SBINDIR/kdb5_util} 421 {KRB5KDC $KRB5_SBINDIR/krb5kdc} 422 {KADMIND $KRB5_SBINDIR/kadmind} 423 {KADMIN $KRB5_BINDIR/kadmin} 424 {KADMIN_LOCAL $KRB5_SBINDIR/kadmin.local} 425 {KINIT $KRB5_BINDIR/kinit} 426 {KTUTIL $KRB5_BINDIR/ktutil} 427 {KLIST $KRB5_BINDIR/klist} 428 {KDESTROY $KRB5_BINDIR/kdestroy} 429 {RESOLVE $objdir/resolve/resolve} 430 {T_INETD $objdir/t_inetd} 431} { 432 set varname [lindex $i 0] 433 if ![info exists $varname] { 434 eval set varval [lindex $i 1] 435 set varval [findfile $varval] 436 set $varname $varval 437 verbose "$varname=$varval" 438 } { 439 eval set varval \$$varname 440 verbose "$varname already set to $varval" 441 } 442} 443 444if ![info exists RLOGIN] { 445 set RLOGIN rlogin 446} 447 448if ![info exists RLOGIN_FLAGS] { 449 set RLOGIN_FLAGS "-x" 450} 451 452# We use a couple of variables to hold shell prompts which may be 453# overridden by the user. 454 455if ![info exists ROOT_PROMPT] { 456 set ROOT_PROMPT "(%|#|>|\\$) $" 457} 458 459if ![info exists SHELL_PROMPT] { 460 set SHELL_PROMPT "(%|#|>|\\$) $" 461} 462 463verbose "setting up onexit handler (old handler=[exit -onexit])" 464exit -onexit [concat { 465 verbose "calling stop_kerberos_daemons (onexit handler)" 466 stop_kerberos_daemons; 467} [exit -onexit]] 468 469# run_once 470 471# Many tests are independent of the actual enctypes used, which is 472# what our passes are (currently) all about. Use this to prevent 473# multiple invocations. If a test depends on, say, the master key 474# type but nothing else, you could also use the master key type in the 475# tag name, and avoid redundant tests in additional passes using the 476# same master key type. 477 478proc run_once { tag body } { 479 global run_once_tags 480 if ![info exists run_once_tags($tag)] { 481 set run_once_tags($tag) 1 482 uplevel 1 $body 483 } 484} 485 486# check_k5login 487 488# Most of the tests won't work if the user has a .k5login file, unless 489# the user's name appears with $REALMNAME in .k5login 490 491# This procedure returns 1 if the .k5login file appears to be OK, 0 492# otherwise. This check is not foolproof. 493 494# Note that this previously checked for a username with no realm; this 495# works for krb4's kuserok() but not for krb5_kuserok(), due to some 496# implementation details. *sigh* 497 498proc check_k5login { testname } { 499 global env 500 global REALMNAME 501 502 if {![file exists ~/.k5login]} { 503 if {$env(USER) == "root"} { 504 return 0 505 } else { 506 return 1 507 } 508 } 509 510 verbose "looking for $env(USER)@$REALMNAME in ~/.k5login" 2 511 set file [open ~/.k5login r] 512 while { [gets $file principal] != -1 } { 513 verbose " found $principal" 2 514 if { $principal == "$env(USER)@$REALMNAME" } { 515 close $file 516 return 1 517 } 518 } 519 close $file 520 521 note "$testname test requires that your name appear in your ~/.k5login" 522 note "file in the form $env(USER)@$REALMNAME" 523 unsupported "$testname" 524 525 return 0 526} 527 528proc check_klogin { testname } { 529 global env 530 global REALMNAME 531 532 if {![file exists ~/.klogin]} { 533 if {$env(USER) == "root"} { 534 return 0 535 } else { 536 return 1 537 } 538 } 539 540 verbose "looking for $env(USER) in ~/.klogin" 2 541 set file [open ~/.klogin r] 542 while { [gets $file principal] != -1 } { 543 verbose " found $principal" 2 544 if { $principal == "$env(USER)" \ 545 || $principal == "$env(USER)@$REALMNAME" } { 546 close $file 547 return 1 548 } 549 } 550 close $file 551 552 note "$testname test requires that your name appear in your ~/.klogin" 553 note "file without a realm." 554 unsupported "$testname" 555 556 return 0 557} 558 559# check_exit_status 560# Check the exit status of a spawned program (using the caller's value 561# of spawn_id). Returns 1 if the program succeeded, 0 if it failed. 562 563proc check_exit_status { testname } { 564 upvar 1 spawn_id spawn_id 565 566 verbose "about to wait ($testname)" 567 set status_list [wait -i $spawn_id] 568 verbose "wait -i $spawn_id returned $status_list ($testname)" 569 catch "close -i $spawn_id" 570 if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } { 571 verbose -log "exit status: $status_list" 572 fail "$testname" 573 return 0 574 } else { 575 return 1 576 } 577} 578 579# 580# ENVSTACK 581# 582 583# These procedures implement an environment variable stack. They use 584# the global variable $envvars_tosave for the purpose of identifying 585# which environment variables to save. They also track which ones are 586# unset at any particular point. The stack pointer is $envstackp, 587# which is an integer. The arrays $envstack$envstackp and 588# $unenvstack$envstackp store respectively the set of old environment 589# variables/values pushed onto the stack and the set of old unset 590# environment variables for a given value of $envstackp. 591 592# Changing the value of $envvars_tosave after performing the first 593# push operation may result in strangeness. 594 595# 596# envstack_push 597# 598# Push set of current environment variables. 599# 600proc envstack_push { } { 601 global env 602 global envvars_tosave 603 global envstackp 604 global envstack$envstackp 605 global unenvstack$envstackp 606 607 verbose "envstack_push: starting, sp=$envstackp" 608 foreach i $envvars_tosave { 609 if [info exists env($i)] { 610 verbose "envstack_push: saving $i=$env($i)" 611 set envstack${envstackp}($i) $env($i) 612 } { 613 verbose "envstack_push: marking $i as unset" 614 set unenvstack${envstackp}($i) unset 615 } 616 } 617 incr envstackp 618 verbose "envstack_push: exiting, sp=$envstackp" 619} 620 621# 622# envstack_pop 623# 624# Pop set of current environment variables. 625# 626proc envstack_pop { } { 627 global env 628 global envstackp 629 630 verbose "envstack_pop: starting, sp=$envstackp" 631 incr envstackp -1 632 global envstack$envstackp # YUCK!!! no obvious better way though... 633 global unenvstack$envstackp 634 if {$envstackp < 0} { 635 perror "envstack_pop: stack underflow!" 636 return 637 } 638 if [info exists envstack$envstackp] { 639 foreach i [array names envstack$envstackp] { 640 if [info exists env($i)] { 641 verbose "envstack_pop: $i was $env($i)" 642 } 643 eval set env($i) \$envstack${envstackp}($i) 644 verbose "envstack_pop: restored $i to $env($i)" 645 } 646 unset envstack$envstackp 647 } 648 if [info exists unenvstack$envstackp] { 649 foreach i [array names unenvstack$envstackp] { 650 if [info exists env($i)] { 651 verbose "envstack_pop: $i was $env($i)" 652 unset env($i) 653 verbose "envstack_pop: $i unset" 654 } { 655 verbose "envstack_pop: ignoring already unset $i" 656 } 657 } 658 unset unenvstack$envstackp 659 } 660 verbose "envstack_pop: exiting, sp=$envstackp" 661} 662 663# 664# Initialize the envstack 665# 666set envvars_tosave { 667 KRB5_CONFIG KRB5CCNAME KRBTKFILE KRB5RCACHEDIR 668 KERBEROS_SERVER KRB5_KDC_PROFILE 669} 670set envstackp 0 671envstack_push 672 673# get_hostname 674# This procedure will get the local hostname. It sets the global 675# variables hostname (the full name) and localhostname (the first part 676# of the name). Returns 1 on success, 0 on failure. 677 678proc get_hostname { } { 679 global RESOLVE 680 global hostname 681 global localhostname 682 global domain 683 global tmppwd 684 685 if {[info exists hostname] && [info exists localhostname]} { 686 return 1 687 } 688 689 envstack_push 690 catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output 691 envstack_pop 692 if ![string match "" $exec_output] { 693 verbose -log $exec_output 694 perror "can't get hostname" 695 return 0 696 } 697 set file [open $tmppwd/hostname r] 698 if { [ gets $file hostname ] == -1 } { 699 perror "no output from hostname" 700 return 0 701 } 702 close $file 703 file delete $tmppwd/hostname 704 regexp "^(\[^.\]*)\\.(.*)$" $hostname foo localhostname domain 705 706 set hostname [string tolower $hostname] 707 set localhostname [string tolower $localhostname] 708 set domain [string tolower $domain] 709 verbose "hostname: $hostname; localhostname: $localhostname; domain $domain" 710 711 return 1 712} 713 714# modify_principal name options... 715 716proc modify_principal { name args } { 717 global KADMIN_LOCAL 718 global REALMNAME 719 720 envstack_push 721 setup_kerberos_env kdc 722 spawn $KADMIN_LOCAL -r $REALMNAME 723 envstack_pop 724 expect_after { 725 eof { 726 fail "modprinc (kadmin.local)" 727 return 0 728 } 729 timeout { 730 fail "modprinc (kadmin.local)" 731 return 0 732 } 733 } 734 expect "kadmin.local: " 735 send "modprinc $args $name\r" 736 expect -re "modprinc \[^\n\r\]* $name" 737 expect -re "Principal .* modified." 738 send "quit\r" 739 expect eof 740 catch expect_after 741 if ![check_exit_status "kadmin.local modprinc"] { 742 perror "kadmin.local modprinc exited abnormally" 743 } 744 return 1 745} 746 747# kdc listens on +0..+3, depending whether we're testing reachable or not 748# client tries +1 and +6 749# kadmind +4 750# kpasswd +5 751# (nothing) +6 752# application servers (krlogind, telnetd, krshd, ftpd, etc) +8 753# iprop +9 (if enabled) 754# kpropd +10 755if [info exists PORTBASE] { 756 set portbase $PORTBASE 757} else { 758 set portbase 3085 759} 760 761set ulog 0 762 763# setup_kerberos_files 764# This procedure will create some Kerberos files which must be created 765# manually before trying to run any Kerberos programs. Returns 1 on 766# success, 0 on failure. 767 768proc setup_kerberos_files { } { 769 global REALMNAME 770 global hostname 771 global domain 772 global tmppwd 773 global supported_enctypes 774 global kdc_supported_enctypes 775 global last_passname_conf 776 global multipass_name 777 global master_key_type 778 global mode 779 global portbase 780 global ulog 781 782 if ![get_hostname] { 783 return 0 784 } 785 786 setup_krb5_conf client 787 setup_krb5_conf server 788 setup_krb5_conf kdc 789 setup_krb5_conf slave 790 791 # Create a kdc.conf file. 792 if { ![file exists $tmppwd/kdc.conf] \ 793 || $last_passname_conf != $multipass_name } { 794 if ![info exists master_key_type] { 795 set master_key_type des-cbc-md5 796 } 797 set conffile [open $tmppwd/kdc.conf w] 798 puts $conffile "\[kdcdefaults\]" 799 puts $conffile " kdc_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]" 800 puts $conffile " kdc_tcp_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]" 801 puts $conffile "" 802 puts $conffile "\[realms\]" 803 puts $conffile " $REALMNAME = \{" 804# puts $conffile " database_name = $tmppwd/db" 805 puts $conffile " admin_database_name = $tmppwd/adb" 806 puts $conffile " admin_database_lockfile = $tmppwd/adb.lock" 807 # Testing with a colon in the name exercises default handling 808 # for pathnames. 809 puts $conffile " key_stash_file = $tmppwd/stash:foo" 810 puts $conffile " acl_file = $tmppwd/acl" 811 puts $conffile " kadmind_port = [expr 4 + $portbase]" 812 puts $conffile " kpasswd_port = [expr 5 + $portbase]" 813 puts $conffile " max_life = 1:00:00" 814 puts $conffile " max_renewable_life = 3:00:00" 815 puts $conffile " master_key_type = $master_key_type" 816 puts $conffile " master_key_name = master/key" 817 puts $conffile " supported_enctypes = $supported_enctypes" 818 puts $conffile " kdc_supported_enctypes = $kdc_supported_enctypes" 819 if { $mode == "tcp" } { 820 puts $conffile " kdc_ports = [expr 3 + $portbase]" 821 puts $conffile " kdc_tcp_ports = [expr 1 + $portbase],[expr 3 + $portbase]" 822 } else { 823 puts $conffile " kdc_ports = [expr 1 + $portbase]" 824 puts $conffile " kdc_tcp_ports = [expr 3 + $portbase]" 825 } 826 puts $conffile " default_principal_expiration = 2037.12.31.23.59.59" 827 puts $conffile " default_principal_flags = -postdateable forwardable" 828 puts $conffile " dict_file = $tmppwd/dictfile" 829 if { $ulog != 0 } { 830 puts $conffile " iprop_enable = true" 831 puts $conffile " iprop_port = [expr 9 + $portbase]" 832 puts $conffile " iprop_logfile = $tmppwd/db.ulog" 833 } else { 834 puts $conffile "# no ulog" 835 } 836 puts $conffile " \}" 837 puts $conffile "" 838 close $conffile 839 } 840 841 # Create a config file for the slave KDC (kpropd only, no normal 842 # KDC processes). 843 if { ![file exists $tmppwd/slave.conf] \ 844 || $last_passname_conf != $multipass_name } { 845 if ![info exists master_key_type] { 846 set master_key_type des-cbc-md5 847 } 848 set conffile [open $tmppwd/slave.conf w] 849 puts $conffile "\[kdcdefaults\]" 850 puts $conffile " kdc_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]" 851 puts $conffile " kdc_tcp_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]" 852 puts $conffile "" 853 puts $conffile "\[realms\]" 854 puts $conffile " $REALMNAME = \{" 855# puts $conffile " database_name = $tmppwd/slave-db" 856 puts $conffile " admin_database_name = $tmppwd/slave-adb" 857 puts $conffile " admin_database_lockfile = $tmppwd/slave-adb.lock" 858 # Testing with a colon in the name exercises default handling 859 # for pathnames. 860 puts $conffile " key_stash_file = $tmppwd/slave-stash" 861 puts $conffile " acl_file = $tmppwd/slave-acl" 862 puts $conffile " kadmind_port = [expr 4 + $portbase]" 863 puts $conffile " kpasswd_port = [expr 5 + $portbase]" 864 puts $conffile " max_life = 1:00:00" 865 puts $conffile " max_renewable_life = 3:00:00" 866 puts $conffile " master_key_type = $master_key_type" 867 puts $conffile " master_key_name = master/key" 868 puts $conffile " supported_enctypes = $supported_enctypes" 869 puts $conffile " kdc_supported_enctypes = $kdc_supported_enctypes" 870 if { $mode == "tcp" } { 871 puts $conffile " kdc_ports = [expr 3 + $portbase]" 872 puts $conffile " kdc_tcp_ports = [expr 1 + $portbase],[expr 3 + $portbase]" 873 } else { 874 puts $conffile " kdc_ports = [expr 1 + $portbase]" 875 puts $conffile " kdc_tcp_ports = [expr 3 + $portbase]" 876 } 877 puts $conffile " default_principal_expiration = 2037.12.31.23.59.59" 878 puts $conffile " default_principal_flags = -postdateable forwardable" 879 puts $conffile " dict_file = $tmppwd/dictfile" 880 if { $ulog != 0 } { 881 puts $conffile " iprop_enable = true" 882 puts $conffile " iprop_port = [expr 9 + $portbase]" 883 puts $conffile " iprop_logfile = $tmppwd/slave-db.ulog" 884 } else { 885 puts $conffile "# no ulog" 886 } 887 puts $conffile " \}" 888 puts $conffile "" 889 close $conffile 890 } 891 892 # Create ACL file. 893 if ![file exists $tmppwd/acl] { 894 set aclfile [open $tmppwd/acl w] 895 puts $aclfile "krbtest/admin@$REALMNAME *" 896 puts $aclfile "kiprop/$hostname@$REALMNAME p" 897 close $aclfile 898 } 899 900 # Create dictfile file. 901 if ![file exists $tmppwd/dictfile] { 902 set dictfile [open $tmppwd/dictfile w] 903 puts $dictfile "weak_password" 904 close $dictfile 905 } 906 907 set last_passname_conf $multipass_name 908 return 1 909} 910 911proc reset_kerberos_files { } { 912 global tmppwd 913 file delete $tmppwd/kdc.conf $tmppwd/slave.conf $tmppwd/krb5.client.conf \ 914 $tmppwd/krb5.server.conf $tmppwd/krb5.kdc.conf 915 setup_kerberos_files 916} 917 918proc setup_krb5_conf { {type client} } { 919 global tmppwd 920 global hostname 921 global domain 922 global REALMNAME 923 global last_passname_conf 924 global multipass_name 925 global default_tgs_enctypes 926 global default_tkt_enctypes 927 global permitted_enctypes 928 global mode 929 global portbase 930 931 # Create a krb5.conf file. 932 if { ![file exists $tmppwd/krb5.$type.conf] \ 933 || $last_passname_conf != $multipass_name } { 934 set conffile [open $tmppwd/krb5.$type.conf w] 935 puts $conffile "\[libdefaults\]" 936 puts $conffile " default_realm = $REALMNAME" 937 puts $conffile " dns_lookup_kdc = false" 938 puts $conffile " allow_weak_crypto = true" 939 if [info exists default_tgs_enctypes($type)] { 940 puts $conffile \ 941 " default_tgs_enctypes = $default_tgs_enctypes($type)" 942 } 943 if [info exists default_tkt_enctypes($type)] { 944 puts $conffile \ 945 " default_tkt_enctypes = $default_tkt_enctypes($type)" 946 } 947 if [info exists permitted_enctypes($type)] { 948 puts $conffile \ 949 " permitted_enctypes = $permitted_enctypes($type)" 950 } 951 if { $mode == "tcp" } { 952 puts $conffile " udp_preference_limit = 1" 953 } 954 puts $conffile "" 955 puts $conffile "\[realms\]" 956 puts $conffile " $REALMNAME = \{" 957 # There's probably nothing listening here. It would be a good 958 # test for the handling of a non-responsive KDC address. However, 959 # on some systems, like Tru64, we often wind up with the client's 960 # socket bound to this address, causing our request to appear in 961 # our incoming queue as if it were a response, which causes test 962 # failures. If we were running the client and KDC on different 963 # hosts, this would be okay.... 964 #puts $conffile " kdc = $hostname:[expr 6 + $portbase]" 965 puts $conffile " kdc = $hostname:[expr 1 + $portbase]" 966 puts $conffile " admin_server = $hostname:[expr 4 + $portbase]" 967 puts $conffile " kpasswd_server = $hostname:[expr 5 + $portbase]" 968 puts $conffile " default_domain = $domain" 969 puts $conffile " database_module = foo_db2" 970 puts $conffile " \}" 971 puts $conffile "" 972 puts $conffile "\[domain_realm\]" 973 puts $conffile " .$domain = $REALMNAME" 974 puts $conffile " $domain = $REALMNAME" 975 puts $conffile "" 976 puts $conffile "\[logging\]" 977 puts $conffile " admin_server = FILE:$tmppwd/kadmind5.log" 978 puts $conffile " kdc = FILE:$tmppwd/kdc.log" 979 puts $conffile " default = FILE:$tmppwd/others.log" 980 puts $conffile "" 981 puts $conffile "\[dbmodules\]" 982 puts $conffile " foo_db2 = {" 983 puts $conffile " db_library = db2" 984 puts $conffile " database_name = $tmppwd/$type-db" 985 puts $conffile " }" 986 close $conffile 987 } 988} 989 990# Save the original values of the environment variables we are going 991# to muck with. 992 993# XXX deal with envstack later. 994 995if [info exists env(KRB5_CONFIG)] { 996 set orig_krb5_conf $env(KRB5_CONFIG) 997} else { 998 catch "unset orig_krb5_config" 999} 1000 1001if [info exists env(KRB5CCNAME)] { 1002 set orig_krb5ccname $env(KRB5CCNAME) 1003} else { 1004 catch "unset orig_krb5ccname" 1005} 1006 1007if [ info exists env(KRB5RCACHEDIR)] { 1008 set orig_krb5rcachedir $env(KRB5RCACHEDIR) 1009} else { 1010 catch "unset orig_krb5rcachedir" 1011} 1012 1013if [ info exists env(KERBEROS_SERVER)] { 1014 set orig_kerberos_server $env(KERBEROS_SERVER) 1015} else { 1016 catch "unset orig_kerberos_server" 1017} 1018 1019# setup_kerberos_env 1020# Set the environment variables needed to run Kerberos programs. 1021 1022proc setup_kerberos_env { {type client} } { 1023 global REALMNAME 1024 global env 1025 global tmppwd 1026 global hostname 1027 global portbase 1028 1029 # Set the environment variable KRB5_CONFIG to point to our krb5.conf file. 1030 # All the Kerberos tools check KRB5_CONFIG. 1031 # Actually, V5 doesn't currently use this. 1032 set env(KRB5_CONFIG) $tmppwd/krb5.$type.conf 1033 verbose "KRB5_CONFIG=$env(KRB5_CONFIG)" 1034 1035 # Direct the Kerberos programs at a local ticket file. 1036 set env(KRB5CCNAME) $tmppwd/tkt 1037 verbose "KRB5CCNAME=$env(KRB5CCNAME)" 1038 1039 # Direct the Kerberos server at a cache file stored in the 1040 # temporary directory. 1041 set env(KRB5RCACHEDIR) $tmppwd 1042 verbose "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)" 1043 1044 # Tell the Kerberos tools how to contact the $REALMNAME server. 1045 set env(KERBEROS_SERVER) "$REALMNAME:$hostname:[expr 1 + $portbase]" 1046 verbose "KERBEROS_SERVER=$env(KERBEROS_SERVER)" 1047 1048 # Set our kdc config file, if needed. 1049 switch $type { 1050 client - 1051 server { catch {unset env(KRB5_KDC_PROFILE)} } 1052 kdc { set env(KRB5_KDC_PROFILE) $tmppwd/kdc.conf } 1053 slave { set env(KRB5_KDC_PROFILE) $tmppwd/slave.conf } 1054 default { error "unknown config file type $type" } 1055 } 1056 if [info exists env(KRB5_KDC_PROFILE)] { 1057 verbose "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)" 1058 } 1059 1060 # Create an environment setup script. (For convenience) 1061 if ![file exists $tmppwd/$type-env.sh] { 1062 set envfile [open $tmppwd/$type-env.sh w] 1063 puts $envfile "KRB5_CONFIG=$env(KRB5_CONFIG)" 1064 puts $envfile "KRB5CCNAME=$env(KRB5CCNAME)" 1065 puts $envfile "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)" 1066 puts $envfile "KERBEROS_SERVER=$env(KERBEROS_SERVER)" 1067 if [info exists env(KRB5_KDC_PROFILE)] { 1068 puts $envfile "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)" 1069 } else { 1070 puts $envfile "unset KRB5_KDC_PROFILE" 1071 } 1072 puts $envfile "export KRB5_CONFIG KRB5CCNAME KRB5RCACHEDIR" 1073 puts $envfile "export KERBEROS_SERVER KRB5_KDC_PROFILE" 1074 close $envfile 1075 } 1076 if ![file exists $tmppwd/$type-env.csh] { 1077 set envfile [open $tmppwd/$type-env.csh w] 1078 puts $envfile "setenv KRB5_CONFIG $env(KRB5_CONFIG)" 1079 puts $envfile "setenv KRB5CCNAME $env(KRB5CCNAME)" 1080 puts $envfile "setenv KRB5RCACHEDIR $env(KRB5RCACHEDIR)" 1081 puts $envfile "setenv KERBEROS_SERVER $env(KERBEROS_SERVER)" 1082 if [info exists env(KRB5_KDC_PROFILE)] { 1083 puts $envfile "setenv KRB5_KDC_PROFILE $env(KRB5_KDC_PROFILE)" 1084 } else { 1085 puts $envfile "unsetenv KRB5_KDC_PROFILE" 1086 } 1087 close $envfile 1088 } 1089 return 1 1090} 1091 1092# Restore the Kerberos environment, in case setup_kerberos_env was 1093# already called by an earlier test. 1094 1095proc restore_kerberos_env { } { 1096 global env 1097 global orig_krb5_config 1098 global orig_krb5ccname 1099 global orig_krb5rcachedir 1100 global orig_kerberos_server 1101 1102 if [info exists orig_krb5_config] { 1103 set env(KRB5_CONFIG) $orig_krb5_config 1104 } else { 1105 catch "unset env(KRB5_CONFIG)" 1106 } 1107 1108 if [info exists orig_krb5ccname] { 1109 set env(KRB5CCNAME) $orig_krb5ccname 1110 } else { 1111 catch "unset env(KRB5CCNAME)" 1112 } 1113 1114 if [info exists orig_krb5rcachedir] { 1115 set env(KRB5RCACHEDIR) $orig_krb5rcachedir 1116 } else { 1117 catch "unset env(KRB5RCACHEDIR)" 1118 } 1119 1120 if [info exists orig_kerberos_server] { 1121 set env(KERBEROS_SERVER) $orig_kerberos_server 1122 } else { 1123 catch "unset env(KERBEROS_SERVER)" 1124 } 1125 1126} 1127 1128# setup_kerberos_db 1129# Initialize the Kerberos database. If the argument is non-zero, call 1130# pass at relevant points. Returns 1 on success, 0 on failure. 1131 1132proc setup_kerberos_db { standalone } { 1133 global REALMNAME KDB5_UTIL KADMIN_LOCAL KEY 1134 global tmppwd hostname 1135 global spawn_id 1136 global des3_krbtgt tgt_support_desmd5 1137 global multipass_name last_passname_db 1138 1139 set failall 0 1140 1141 if {!$standalone && [file exists $tmppwd/kdc-db.ok] \ 1142 && $last_passname_db == $multipass_name} { 1143 return 1 1144 } 1145 1146 delete_db 1147 1148 envstack_push 1149 if { ![setup_kerberos_files] || ![setup_kerberos_env kdc] } { 1150 set failall 1 1151 } 1152 1153 # Set up a common expect_after for use in multiple places. 1154 set def_exp_after { 1155 timeout { 1156 set test "$test (timeout)" 1157 break 1158 } 1159 eof { 1160 set test "$test (eof)" 1161 break 1162 } 1163 } 1164 1165 set test "kdb5_util create" 1166 set body { 1167 if $failall { 1168 break 1169 } 1170 #exec xterm 1171 verbose "starting $test" 1172 spawn $KDB5_UTIL -r $REALMNAME create -W 1173 expect_after $def_exp_after 1174 1175 expect "Enter KDC database master key:" 1176 1177 set test "kdb5_util create (verify)" 1178 send "masterkey$KEY\r" 1179 expect "Re-enter KDC database master key to verify:" 1180 1181 set test "kdb5_util create" 1182 send "masterkey$KEY\r" 1183 expect { 1184 -re "\[Cc\]ouldn't" { 1185 expect eof 1186 break 1187 } 1188 "Cannot find/read stored" exp_continue 1189 "Warning: proceeding without master key" exp_continue 1190 eof { } 1191 } 1192 catch expect_after 1193 if ![check_exit_status kdb5_util] { 1194 break 1195 } 1196 } 1197 set ret [catch $body] 1198 catch expect_after 1199 if $ret { 1200 set failall 1 1201 if $standalone { 1202 fail $test 1203 } 1204 } else { 1205 if $standalone { 1206 pass $test 1207 } 1208 } 1209 1210 # Stash the master key in a file. 1211 set test "kdb5_util stash" 1212 set body { 1213 if $failall { 1214 break 1215 } 1216 spawn $KDB5_UTIL -r $REALMNAME stash 1217 verbose "starting $test" 1218 expect_after $def_exp_after 1219 expect "Enter KDC database master key:" 1220 send "masterkey$KEY\r" 1221 expect eof 1222 catch expect_after 1223 if ![check_exit_status kdb5_util] { 1224 break 1225 } 1226 } 1227 set ret [catch $body] 1228 catch "expect eof" 1229 catch expect_after 1230 if $ret { 1231 set failall 1 1232 if $standalone { 1233 fail $test 1234 } else { 1235 delete_db 1236 } 1237 } else { 1238 if $standalone { 1239 pass $test 1240 } 1241 } 1242 1243 # Add an admin user. 1244 set test "kadmin.local ank krbtest/admin" 1245 set body { 1246 if $failall { 1247 break 1248 } 1249 spawn $KADMIN_LOCAL -r $REALMNAME 1250 verbose "starting $test" 1251 expect_after $def_exp_after 1252 1253 expect "kadmin.local: " 1254 send "ank krbtest/admin@$REALMNAME\r" 1255 # It echos... 1256 expect "ank krbtest/admin@$REALMNAME\r" 1257 expect "Enter password for principal \"krbtest/admin@$REALMNAME\":" 1258 send "adminpass$KEY\r" 1259 expect "Re-enter password for principal \"krbtest/admin@$REALMNAME\":" 1260 send "adminpass$KEY\r" 1261 expect { 1262 "Principal \"krbtest/admin@$REALMNAME\" created" { } 1263 "Principal or policy already exists while creating*" { } 1264 } 1265 expect "kadmin.local: " 1266 send "quit\r" 1267 expect eof 1268 catch expect_after 1269 if ![check_exit_status kadmin_local] { 1270 break 1271 } 1272 } 1273 set ret [catch $body] 1274 catch "expect eof" 1275 catch expect_after 1276 if $ret { 1277 set failall 1 1278 if $standalone { 1279 fail $test 1280 } else { 1281 delete_db 1282 } 1283 } else { 1284 if $standalone { 1285 pass $test 1286 } 1287 } 1288 1289 # Add an incremental-propagation service. 1290 set test "kadmin.local ank kiprop/$hostname" 1291 set body { 1292 if $failall { 1293 break 1294 } 1295 spawn $KADMIN_LOCAL -r $REALMNAME 1296 verbose "starting $test" 1297 expect_after $def_exp_after 1298 1299 expect "kadmin.local: " 1300 send "ank kiprop/$hostname@$REALMNAME\r" 1301 # It echos... 1302 expect "ank kiprop/$hostname@$REALMNAME\r" 1303 expect "Enter password for principal \"kiprop/$hostname@$REALMNAME\":" 1304 send "kiproppass$KEY\r" 1305 expect "Re-enter password for principal \"kiprop/$hostname@$REALMNAME\":" 1306 send "kiproppass$KEY\r" 1307 expect { 1308 "Principal \"kiprop/$hostname@$REALMNAME\" created" { } 1309 "Principal or policy already exists while creating*" { } 1310 } 1311 expect "kadmin.local: " 1312 send "quit\r" 1313 expect eof 1314 catch expect_after 1315 if ![check_exit_status kadmin_local] { 1316 break 1317 } 1318 } 1319 set ret [catch $body] 1320 catch "expect eof" 1321 catch expect_after 1322 if $ret { 1323 set failall 1 1324 if $standalone { 1325 fail $test 1326 } else { 1327 delete_db 1328 } 1329 } else { 1330 if $standalone { 1331 pass $test 1332 } 1333 } 1334 1335 if $des3_krbtgt { 1336 # Set the TGT key to DES3. 1337 set test "kadmin.local TGT to DES3" 1338 set body { 1339 if $failall { 1340 break 1341 } 1342 spawn $KADMIN_LOCAL -r $REALMNAME -e des3-cbc-sha1:normal 1343 verbose "starting $test" 1344 expect_after $def_exp_after 1345 1346 expect "kadmin.local: " 1347 send "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" 1348 # It echos... 1349 expect "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r" 1350 expect { 1351 "Key for \"krbtgt/$REALMNAME@$REALMNAME\" randomized." { } 1352 } 1353 expect "kadmin.local: " 1354 send "quit\r" 1355 expect eof 1356 catch expect_after 1357 if ![check_exit_status kadmin_local] { 1358 break 1359 } 1360 } 1361 set ret [catch $body] 1362 catch "expect eof" 1363 catch expect_after 1364 if $ret { 1365 set failall 1 1366 if $standalone { 1367 fail $test 1368 } else { 1369 delete_db 1370 } 1371 } else { 1372 if $standalone { 1373 pass $test 1374 } 1375 } 1376 } 1377 if $tgt_support_desmd5 { 1378 # Make TGT support des-cbc-md5 1379 set test "kadmin.local TGT to SUPPORT_DESMD5" 1380 set body { 1381 if $failall { 1382 break 1383 } 1384 spawn $KADMIN_LOCAL -r $REALMNAME 1385 verbose "starting $test" 1386 expect_after $def_exp_after 1387 1388 expect "kadmin.local: " 1389 send "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r" 1390 # It echos... 1391 expect "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r" 1392 expect { 1393 "Principal \"krbtgt/$REALMNAME@$REALMNAME\" modified.\r\n" { } 1394 } 1395 expect "kadmin.local: " 1396 send "quit\r" 1397 expect eof 1398 catch expect_after 1399 if ![check_exit_status kadmin_local] { 1400 break 1401 } 1402 } 1403 set ret [catch $body] 1404 catch "expect eof" 1405 catch expect_after 1406 if $ret { 1407 set failall 1 1408 if $standalone { 1409 fail $test 1410 } else { 1411 delete_db 1412 } 1413 } else { 1414 if $standalone { 1415 pass $test 1416 } 1417 } 1418 } 1419 envstack_pop 1420 1421 # create the admin database lock file 1422 catch "exec touch $tmppwd/adb.lock" 1423 1424 set last_passname_db $multipass_name 1425 return 1 1426} 1427 1428proc start_tail { fname spawnid_var pid_var which standalone } { 1429 upvar $spawnid_var spawnid 1430 upvar $pid_var pid 1431 global timeout 1432 1433 set f [open $fname a] 1434 1435 spawn tail -f $fname 1436 set spawnid $spawn_id 1437 set pid [exp_pid] 1438 1439 set markstr "===MARK $pid ===" 1440 puts $f $markstr 1441 flush $f 1442 1443 set p 0 1444 set otimeout $timeout 1445 set timeout 3 1446 set ok 0 1447 while { $ok == 0 && $p < 3 } { 1448 expect { 1449 -i $spawn_id 1450 -ex "$markstr" { set ok 1 } 1451 -re "\[^\r\n\]*\r\n" { exp_continue } 1452 timeout { 1453 # Some versions of GNU tail had a race condition where 1454 # the first batch of data would be read from the end 1455 # of the file, and then there was a brief window 1456 # before calling stat and recording the size of the 1457 # file. If the marker is written during that window, 1458 # then yet another file modification is needed to get 1459 # the first one noticed. 1460 if { $p < 3 } { 1461 verbose -log "no tail output yet, prodding with a blank line" 1462 incr p 1463 puts $f "" 1464 flush $f 1465 exp_continue 1466 } else { 1467 close $f 1468 verbose -log "tail $fname output:" 1469 verbose -log [exec tail $fname] 1470 if {$standalone} { 1471 verbose -log "tail -f timed out ($timeout sec) looking for mark in $which log" 1472 fail "$which" 1473 } else { 1474 perror "$which tail -f timed out ($timeout sec) looking for mark in $which log" 1475 } 1476 stop_kerberos_daemons 1477 exec kill $pid 1478 expect -i $spawn_id eof 1479 wait -i $spawn_id 1480 set timeout $otimeout 1481 return 0 1482 } 1483 } 1484 } 1485 } 1486 close $f 1487 set timeout $otimeout 1488 return 1 1489} 1490 1491# start_kerberos_daemons 1492# A procedure to build a Kerberos database and start up the kerberos 1493# and kadmind daemons. This sets the global variables kdc_pid, 1494# kdc_spawn_id, kadmind_pid, and kadmind_spawn_id. The procedure 1495# stop_kerberos_daemons should be used to stop the daemons. If the 1496# argument is non-zero, call pass at relevant points. Returns 1 on 1497# success, 0 on failure. 1498 1499proc start_kerberos_daemons { standalone } { 1500 global BINSH 1501 global REALMNAME 1502 global KRB5KDC 1503 global KADMIND 1504 global KEY 1505 global kdc_pid 1506 global kdc_spawn_id 1507 global kadmind_pid 1508 global kadmind_spawn_id 1509 global tmppwd 1510 global env 1511 global timeout 1512 1513 if ![setup_kerberos_db 0] { 1514 return 0 1515 } 1516 1517 if {$standalone} { 1518 file delete $tmppwd/krb.log $tmppwd/kadmind.log $tmppwd/krb5kdc_rcache 1519 } 1520 1521 # Start up the kerberos daemon 1522 # Why are we doing all this with the log file you may ask. 1523 # We need a handle on when the server starts. If we log the output 1524 # of the server to say stderr, then if we stop looking for output, 1525 # buffers will fill and the server will stop working.... 1526 # So, we look to see when a line is added to the log file and then 1527 # check it.. 1528 # The same thing is done a little later for the kadmind 1529 set kdc_lfile $tmppwd/kdc.log 1530 set kadmind_lfile $tmppwd/kadmind5.log 1531 1532 if ![start_tail $kdc_lfile tailf_spawn_id tailf_pid krb5kdc $standalone] { 1533 return 0 1534 } 1535 1536 envstack_push 1537 setup_kerberos_env kdc 1538 spawn $KRB5KDC -r $REALMNAME -n full 1539 envstack_pop 1540 set kdc_pid [exp_pid] 1541 set kdc_spawn_id $spawn_id 1542 1543 expect { 1544 -i $tailf_spawn_id 1545 -re "commencing operation\r\n" { } 1546 -re "krb5kdc: \[a-zA-Z\]* - Cannot bind server socket to \[ 0-9a-fA-F:.\]*\r\n" { 1547 verbose -log "warning: $expect_out(0,string)" 1548 exp_continue 1549 } 1550 "no sockets set up?" { 1551 if {$standalone} { 1552 verbose -log "krb5kdc startup failed to bind listening sockets" 1553 fail "krb5kdc" 1554 } else { 1555 perror "krb5kdc startup failed to bind listening sockets" 1556 } 1557 stop_kerberos_daemons 1558 exec kill $tailf_pid 1559 expect -i $tailf_spawn_id eof 1560 wait -i $tailf_spawn_id 1561 return 0 1562 } 1563 timeout { 1564 if {$standalone} { 1565 verbose -log "krb5kdc startup timed out" 1566 fail "krb5kdc" 1567 } else { 1568 perror "krb5kdc startup timed out" 1569 } 1570 stop_kerberos_daemons 1571 exec kill $tailf_pid 1572 expect -i $tailf_spawn_id eof 1573 wait -i $tailf_spawn_id 1574 return 0 1575 } 1576 } 1577 exec kill $tailf_pid 1578 expect -i $tailf_spawn_id eof 1579 wait -i $tailf_spawn_id 1580 1581 if {$standalone} { 1582 pass "krb5kdc" 1583 } 1584 1585 # Give the kerberos daemon a few seconds to get set up. 1586# sleep 2 1587 1588 # 1589 # Save setting of KRB5_KTNAME. We do not want to override kdc.conf 1590 # file during kadmind startup. (this is in case user has KRB5_KTNAME 1591 # set before starting make check) 1592 # 1593 if [info exists env(KRB5_KTNAME)] { 1594 set start_save_ktname $env(KRB5_KTNAME) 1595 } 1596 catch "unset env(KRB5_KTNAME)" 1597 1598 if ![start_tail $kadmind_lfile tailf_spawn_id tailf_pid kadmind $standalone] { 1599 return 0 1600 } 1601 1602 # Start up the kadmind daemon 1603 # XXXX kadmind uses stderr a lot. the sh -c and redirect can be 1604 # removed when this is fixed 1605 envstack_push 1606 setup_kerberos_env kdc 1607 spawn $BINSH -c "exec $KADMIND -r $REALMNAME -W -nofork 2>>$kadmind_lfile" 1608 envstack_pop 1609 set kadmind_pid [exp_pid] 1610 set kadmind_spawn_id $spawn_id 1611 1612 # Restore KRB5_KTNAME 1613 if [info exists start_save_ktname] { 1614 set env(KRB5_KTNAME) $start_save_ktname 1615 unset start_save_ktname 1616 } 1617 1618 expect { 1619 -i $tailf_spawn_id 1620 "Seeding random number" exp_continue 1621 "cannot initialize network" { 1622 if {$standalone} { 1623 verbose -log "kadmind failed network init" 1624 fail "kadmind" 1625 } else { 1626 perror "kadmind failed network init" 1627 } 1628 stop_kerberos_daemons 1629 exec kill $tailf_pid 1630 expect -i $tailf_spawn_id eof 1631 wait -i $tailf_spawn_id 1632 return 0 1633 } 1634 "cannot bind to network address" { 1635 if {$standalone} { 1636 verbose -log "kadmind failed to bind socket" 1637 fail "kadmind" 1638 } else { 1639 perror "kadmind failed to bind socket" 1640 } 1641 stop_kerberos_daemons 1642 exec kill $tailf_pid 1643 expect -i $tailf_spawn_id eof 1644 wait -i $tailf_spawn_id 1645 return 0 1646 } 1647 "No principal in keytab matches desired name" { 1648 dump_db 1649 exp_continue 1650 } 1651 "starting" { } 1652 timeout { 1653 if {$standalone} { 1654 verbose -log "kadmind failed to start" 1655 fail "kadmind" 1656 } else { 1657 verbose -log "kadmind failed to start" 1658 perror "kadmind failed to start" 1659 } 1660#sleep 10 1661 stop_kerberos_daemons 1662 exec kill $tailf_pid 1663 expect -i $tailf_spawn_id eof 1664 wait -i $tailf_spawn_id 1665 return 0 1666 } 1667 } 1668 exec kill $tailf_pid 1669 expect -i $tailf_spawn_id eof 1670 wait -i $tailf_spawn_id 1671 1672 if {$standalone} { 1673 pass "kadmind" 1674 } 1675 1676 # Give the kadmind daemon a few seconds to get set up. 1677# sleep 2 1678 1679 return 1 1680} 1681 1682# stop_kerberos_daemons 1683# Stop the kerberos daemons. Returns 1 on success, 0 on failure. 1684 1685proc stop_kerberos_daemons { } { 1686 global kdc_pid 1687 global kdc_spawn_id 1688 global kadmind_pid 1689 global kadmind_spawn_id 1690 1691 verbose "entered stop_kerberos_daemons" 1692 1693 if [info exists kdc_pid] { 1694 if [catch "exec kill $kdc_pid" msg] { 1695 verbose "kill kdc: $msg" 1696 } 1697 if [catch "expect -i $kdc_spawn_id eof" msg] { 1698 verbose "expect kdc eof: $msg" 1699 } 1700 set kdc_list [wait -i $kdc_spawn_id] 1701 verbose "wait -i $kdc_spawn_id returned $kdc_list (kdc)" 1702 unset kdc_pid 1703 unset kdc_list 1704 } 1705 1706 if [info exists kadmind_pid] { 1707 if [catch "exec kill $kadmind_pid" msg] { 1708 verbose "kill kadmind: $msg" 1709 } 1710 if [catch "expect -i $kadmind_spawn_id eof" msg] { 1711 verbose "expect kadmind eof: $msg" 1712 } 1713 set kadmind_list [wait -i $kadmind_spawn_id] 1714 verbose "wait -i $kadmind_spawn_id returned $kadmind_list (kadmind5)" 1715 unset kadmind_pid 1716 unset kadmind_list 1717 } 1718 1719 verbose "exiting stop_kerberos_daemons" 1720 1721 return 1 1722} 1723 1724# add_kerberos_key 1725# Add an key to the Kerberos database. start_kerberos_daemons must be 1726# called before this procedure. If the standalone argument is 1727# non-zero, call pass at relevant points. Returns 1 on success, 0 on 1728# failure. 1729 1730proc add_kerberos_key { kkey standalone } { 1731 global REALMNAME 1732 global KADMIN 1733 global KEY 1734 global spawn_id 1735 1736 # Use kadmin to add an key. 1737 set test "kadmin ank $kkey" 1738 set body { 1739 envstack_push 1740 setup_kerberos_env client 1741 spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME" 1742 envstack_pop 1743 verbose "starting $test" 1744 expect_after { 1745 "Cannot contact any KDC" { 1746 set test "$test (lost KDC)" 1747 break 1748 } 1749 timeout { 1750 set test "$test (timeout)" 1751 break 1752 } 1753 eof { 1754 set test "$test (eof)" 1755 break 1756 } 1757 } 1758 expect -re "assword\[^\r\n\]*: *" 1759 send "adminpass$KEY\r" 1760 expect "Enter password for principal \"$kkey@$REALMNAME\":" 1761 send "$kkey" 1762 send "$KEY\r" 1763 expect "Re-enter password for principal \"$kkey@$REALMNAME\":" 1764 send "$kkey" 1765 send "$KEY\r" 1766 expect { 1767 "Principal \"$kkey@$REALMNAME\" created" { } 1768 "Principal or policy already exists while creating*" { } 1769 } 1770 expect eof 1771 if ![check_exit_status kadmin] { 1772 break 1773 } 1774 } 1775 set ret [catch $body] 1776 catch "expect eof" 1777 catch expect_after 1778 if $ret { 1779 if $standalone { 1780 fail $test 1781 } 1782 return 0 1783 } else { 1784 if $standalone { 1785 pass $test 1786 } 1787 return 1 1788 } 1789} 1790 1791# dump_db 1792proc dump_db { } { 1793 global KADMIN_LOCAL 1794 global REALMNAME 1795 1796 spawn $KADMIN_LOCAL -r $REALMNAME 1797 expect_after { 1798 eof { 1799 perror "failed to get debugging dump of database (eof)" 1800 } 1801 timeout { 1802 perror "failed to get debugging dump of database (timeout)" 1803 } 1804 } 1805 expect "kadmin.local: " 1806 send "getprincs\r" 1807 expect "kadmin.local: " 1808 send "quit\r" 1809 expect eof 1810 catch expect_after 1811} 1812 1813# add_random_key 1814# Add a key with a random password to the Kerberos database. 1815# start_kerberos_daemons must be called before this procedure. If the 1816# standalone argument is non-zero, call pass at relevant points. 1817# Returns 1 on success, 0 on failure. 1818 1819proc add_random_key { kkey standalone } { 1820 global REALMNAME 1821 global KADMIN 1822 global KEY 1823 global spawn_id 1824 1825 # Use kadmin to add an key. 1826 set test "kadmin ark $kkey" 1827 set body { 1828 envstack_push 1829 setup_kerberos_env client 1830 spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME" 1831 envstack_pop 1832 expect_after { 1833 timeout { 1834 set test "$test (timeout)" 1835 break 1836 } 1837 eof { 1838 set test "$test (eof)" 1839 break 1840 } 1841 } 1842 expect -re "assword\[^\r\n\]*: *" 1843 send "adminpass$KEY\r" 1844 expect { 1845 "Principal \"$kkey@$REALMNAME\" created" { } 1846 "Principal or policy already exists while creating*" { } 1847 } 1848 expect eof 1849 if ![check_exit_status kadmin] { 1850 break 1851 } 1852 } 1853 if [catch $body] { 1854 catch expect_after 1855 if $standalone { 1856 fail $test 1857 } 1858 return 0 1859 } else { 1860 catch expect_after 1861 if $standalone { 1862 pass $test 1863 } 1864 return 1 1865 } 1866} 1867 1868# setup_srvtab 1869# Set up a srvtab file. start_kerberos_daemons and add_random_key 1870# $id/$hostname must be called before this procedure. If the 1871# argument is non-zero, call pass at relevant points. Returns 1 on 1872# success, 0 on failure. If the id field is not provided, host is used. 1873 1874proc setup_srvtab { standalone {id host} } { 1875 global REALMNAME 1876 global KADMIN_LOCAL 1877 global KEY 1878 global tmppwd 1879 global hostname 1880 global spawn_id 1881 global last_service 1882 1883 if {!$standalone && [file exists $tmppwd/srvtab] && $last_service == $id} { 1884 return 1 1885 } 1886 1887 file delete $tmppwd/srvtab $tmppwd/srvtab.old 1888 1889 if ![get_hostname] { 1890 return 0 1891 } 1892 1893 file delete $hostname-new-srvtab 1894 1895 envstack_push 1896 setup_kerberos_env kdc 1897 spawn $KADMIN_LOCAL -r $REALMNAME 1898 envstack_pop 1899 expect_after { 1900 -re "(.*)\r\nkadmin.local: " { 1901 fail "kadmin.local srvtab (unmatched output: $expect_out(1,string))" 1902 if {!$standalone} { 1903 file delete $tmppwd/srvtab 1904 } 1905 catch "expect_after" 1906 return 0 1907 } 1908 timeout { 1909 fail "kadmin.local srvtab" 1910 if {!$standalone} { 1911 file delete $tmppwd/srvtab 1912 } 1913 catch "expect_after" 1914 return 0 1915 } 1916 eof { 1917 fail "kadmin.local srvtab" 1918 if {!$standalone} { 1919 file delete $tmppwd/srvtab 1920 } 1921 catch "expect_after" 1922 return 0 1923 } 1924 } 1925 expect "kadmin.local: " 1926 send "xst -k $hostname-new-srvtab $id/$hostname kiprop/$hostname\r" 1927 expect "xst -k $hostname-new-srvtab $id/$hostname kiprop/$hostname\r\n" 1928 expect { 1929 -re ".*Entry for principal $id/$hostname.* added to keytab WRFILE:$hostname-new-srvtab." { } 1930 -re "\r\nkadmin.local: " { 1931 if {$standalone} { 1932 fail "kadmin.local srvtab" 1933 } else { 1934 file delete $tmppwd/srvtab 1935 } 1936 catch expect_after 1937 return 0 1938 } 1939 } 1940 expect "kadmin.local: " 1941 send "quit\r" 1942 expect eof 1943 catch expect_after 1944 if ![check_exit_status "kadmin.local srvtab"] { 1945 if {!$standalone} { 1946 file delete $tmppwd/srvtab 1947 } 1948 return 0 1949 } 1950 1951 catch "exec mv -f $hostname-new-srvtab $tmppwd/srvtab" exec_output 1952 if ![string match "" $exec_output] { 1953 verbose -log "$exec_output" 1954 perror "can't mv new srvtab" 1955 return 0 1956 } 1957 1958 if {$standalone} { 1959 pass "kadmin.local srvtab" 1960 } 1961 1962 # Make the srvtab file globally readable in case we are using a 1963 # root shell and the srvtab is NFS mounted. 1964 catch "exec chmod a+r $tmppwd/srvtab" 1965 1966 # Remember what we just extracted 1967 set last_service $id 1968 1969 return 1 1970} 1971 1972# kinit 1973# Use kinit to get a ticket. If the argument is non-zero, call pass 1974# at relevant points. Returns 1 on success, 0 on failure. 1975 1976proc kinit { name pass standalone } { 1977 global REALMNAME 1978 global KINIT 1979 global spawn_id 1980 1981 # Use kinit to get a ticket. 1982 # 1983 # For now always get forwardable tickets. Later when we need to make 1984 # tests that distiguish between forwardable tickets and otherwise 1985 # we should but another option to this proc. --proven 1986 # 1987 spawn $KINIT -5 -f $name@$REALMNAME 1988 expect { 1989 "Password for $name@$REALMNAME:" { 1990 verbose "kinit started" 1991 } 1992 timeout { 1993 fail "kinit" 1994 return 0 1995 } 1996 eof { 1997 fail "kinit" 1998 return 0 1999 } 2000 } 2001 send "$pass\r" 2002 expect eof 2003 if ![check_exit_status kinit] { 2004 return 0 2005 } 2006 2007 if {$standalone} { 2008 pass "kinit" 2009 } 2010 2011 return 1 2012} 2013 2014proc kinit_kt { name keytab standalone testname } { 2015 global REALMNAME 2016 global KINIT 2017 global spawn_id 2018 2019 # Use kinit to get a ticket. 2020 # 2021 # For now always get forwardable tickets. Later when we need to make 2022 # tests that distiguish between forwardable tickets and otherwise 2023 # we should but another option to this proc. --proven 2024 # 2025 spawn $KINIT -5 -f -k -t $keytab $name@$REALMNAME 2026 expect { 2027 timeout { 2028 fail "kinit $testname" 2029 return 0 2030 } 2031 eof { } 2032 } 2033 if ![check_exit_status "kinit $testname"] { 2034 return 0 2035 } 2036 2037 if {$standalone} { 2038 pass "kinit $testname" 2039 } 2040 2041 return 1 2042} 2043 2044# List tickets. Requires client and server names, and test name. 2045# Checks that klist exist status is zero. 2046# Records pass or fail, and returns 1 or 0. 2047proc do_klist { myname servname testname } { 2048 global KLIST 2049 global tmppwd 2050 2051 spawn $KLIST -5 -e 2052 expect { 2053 -re "Ticket cache:\[ \]*(.+:)?$tmppwd/tkt.*Default principal:\[ \]*$myname.*$servname\r\n" { 2054 verbose "klist started" 2055 } 2056 timeout { 2057 fail $testname 2058 return 0 2059 } 2060 eof { 2061 fail $testname 2062 return 0 2063 } 2064 } 2065 2066 expect eof 2067 2068 if ![check_exit_status $testname] { 2069 return 0 2070 } 2071 pass $testname 2072 return 1 2073} 2074 2075proc do_klist_kt { keytab testname } { 2076 global KLIST 2077 global tmppwd 2078 2079 spawn $KLIST -5 -e -k $keytab 2080 expect { 2081 -re "Keytab name:\[ \]*(.+:)?.*KVNO Principal\r\n---- -*\r\n" { 2082 verbose "klist started" 2083 } 2084 timeout { 2085 fail $testname 2086 return 0 2087 } 2088 eof { 2089 fail $testname 2090 return 0 2091 } 2092 } 2093 set more 1 2094 while {$more} { 2095 expect { 2096 -re { *[0-9][0-9]* *[a-zA-Z/@.-]* \([/a-zA-Z 0-9-]*\) *\r\n} { 2097 verbose -log "key: $expect_out(buffer)" 2098 } 2099 eof { set more 0 } 2100 } 2101 } 2102 2103 if ![check_exit_status $testname] { 2104 return 0 2105 } 2106 pass $testname 2107 return 1 2108} 2109 2110proc do_klist_err { testname } { 2111 global KLIST 2112 global spawn_id 2113 2114 spawn $KLIST -5 2115 # Might say "credentials cache" or "credentials cache file". 2116 expect { 2117 -re "klist: No credentials cache.*found.*\r\n" { 2118 verbose "klist started" 2119 } 2120 timeout { 2121 fail $testname 2122 return 0 2123 } 2124 eof { 2125 fail $testname 2126 return 0 2127 } 2128 } 2129 # We can't use check_exit_status, because we expect an exit status 2130 # of 1. 2131 catch "expect eof" 2132 set status_list [wait -i $spawn_id] 2133 verbose "wait -i $spawn_id returned $status_list ($testname)" 2134 if { [lindex $status_list 2] != 0 } { 2135 fail "$testname (bad exit status) $status_list" 2136 return 0 2137 } else { if { [lindex $status_list 3] != 1 } { 2138 fail "$testname (bad exit status) $status_list" 2139 return 0 2140 } else { 2141 pass $testname 2142 } } 2143 return 1 2144} 2145 2146proc do_kdestroy { testname } { 2147 global KDESTROY 2148 global spawn_id 2149 2150 spawn $KDESTROY -5 2151 if ![check_exit_status $testname] { 2152 fail $testname 2153 return 0 2154 } 2155 pass $testname 2156 return 1 2157} 2158 2159proc xst { keytab name } { 2160 global KADMIN_LOCAL 2161 global REALMNAME 2162 2163 envstack_push 2164 setup_kerberos_env kdc 2165 spawn $KADMIN_LOCAL -r $REALMNAME 2166 envstack_pop 2167 catch expect_after 2168 expect_after { 2169 -re "(.*)\r\nkadmin.local: " { 2170 fail "kadmin.local xst $keytab (unmatched output: $expect_out(1,string)" 2171 catch "expect_after" 2172 return 0 2173 } 2174 timeout { 2175 fail "kadmin.local xst $keytab (timeout)" 2176 catch "expect_after" 2177 return 0 2178 } 2179 eof { 2180 fail "kadmin.local xst $keytab (eof)" 2181 catch "expect_after" 2182 return 0 2183 } 2184 } 2185 expect "kadmin.local: " 2186 send "xst -k $keytab $name\r" 2187 expect -re "xst -k \[^\r\n\]*\r\n.*Entry for principal .* added to keytab WRFILE:.*\r\nkadmin.local: " 2188 send "quit\r" 2189 expect eof 2190 catch expect_after 2191 if ![check_exit_status "kadmin.local $keytab"] { 2192 perror "kadmin.local xst $keytab exited abnormally" 2193 return 0 2194 } 2195 return 1 2196} 2197 2198# v4_compatible_enctype 2199# Returns 1 if v4 testing is enabled this passes encryption types are compatable with kerberos 4 work 2200proc v4_compatible_enctype {} { 2201 global supported_enctypes 2202 global KRBIV 2203 2204 if ![info exists KRBIV] { 2205 return 0; 2206 } 2207 2208 if { $KRBIV && [string first des-cbc-crc:v4 "$supported_enctypes"] >= 0} { 2209 return 1 2210 } else { 2211 return 0 2212 } 2213} 2214 2215# Set up a root shell using rlogin $hostname -l root. This is used 2216# when testing the daemons that must be run as root, such as telnetd 2217# or rlogind. This sets the global variables rlogin_spawn_id and 2218# rlogin_pid. Returns 1 on success, 0 on failure. 2219# 2220# This procedure will only succeed if the person running the test has 2221# a valid ticket for a name listed in the /.klogin file. Naturally, 2222# Kerberos must already be installed on this machine. It's a pain, 2223# but I can't think of a better approach. 2224 2225if ![info exists can_get_root] { set can_get_root yes } 2226 2227proc setup_root_shell { testname } { 2228 global BINSH 2229 global ROOT_PROMPT 2230 global KEY 2231 global RLOGIN 2232 global RLOGIN_FLAGS 2233 global hostname 2234 global rlogin_spawn_id 2235 global rlogin_pid 2236 global tmppwd 2237 global env 2238 global krb5_init_vars 2239 global can_get_root 2240 2241 global timeout 2242 2243 if [string match $can_get_root no] { 2244 note "$testname test requires ability to log in as root" 2245 unsupported $testname 2246 return 0 2247 } 2248 2249 # Make sure we are using the original values of the environment 2250 # variables. This means that the caller must call 2251 # setup_kerberos_env after calling this procedure. 2252 2253 # XXX fixme to deal with envstack 2254 restore_kerberos_env 2255 2256 set me [exec whoami] 2257 if [string match root $me] { 2258 return [setup_root_shell_noremote $testname] 2259 } 2260 2261 if ![get_hostname] { 2262 set can_get_root no 2263 return 0 2264 } 2265 2266 # If you have not installed Kerberos on your system, and you want 2267 # to run these tests, you can do it if you are willing to put your 2268 # root password in this file (this is not a very good idea, but 2269 # it's safe enough if you disconnect from the network and remember 2270 # to remove the password later). Change the rlogin in the next 2271 # line to be /usr/ucb/rlogin (or whatever is appropriate for your 2272 # system). Then change the lines after "word:" a few lines 2273 # farther down to be 2274 # send "rootpassword\r" 2275 # exp_continue 2276 2277 eval spawn $RLOGIN $hostname -l root $RLOGIN_FLAGS 2278 set rlogin_spawn_id $spawn_id 2279 set rlogin_pid [exp_pid] 2280 set old_timeout $timeout 2281 set timeout 300 2282 set got_refused 0 2283 2284 expect { 2285 -re {connect to address [0-9a-fA-F.:]*: Connection refused} { 2286 note $expect_out(buffer) 2287 set got_refused 1 2288 exp_continue 2289 } 2290 -re "word:|erberos rlogin failed|ection refused|ection reset by peer|not authorized|Ticket expired|authenticity of" { 2291 note "$testname test requires ability to rlogin as root" 2292 unsupported "$testname" 2293 set timeout $old_timeout 2294 stop_root_shell 2295 set can_get_root no 2296 return 0 2297 } 2298 "Cannot assign requested address" { 2299 note "$testname: rlogin as root 'cannot assign requested address'" 2300 unsupported "$testname" 2301 set timeout $old_timeout 2302 stop_root_shell 2303 set can_get_root no 2304 return 0 2305 } 2306 -re "usage: rlogin|illegal option -- x|invalid option -- x" { 2307 note "$testname: rlogin doesn't like command-line flags" 2308 unsupported "$testname" 2309 set timeout $old_timeout 2310 stop_root_shell 2311 set can_get_root no 2312 return 0 2313 } 2314 -re "$ROOT_PROMPT" { } 2315 timeout { 2316 perror "timeout from rlogin $hostname -l root" 2317 perror "If you have an unusual root prompt," 2318 perror "try running with ROOT_PROMPT=\"regexp\"" 2319 set timeout $old_timeout 2320 stop_root_shell 2321 set can_get_root no 2322 return 0 2323 } 2324 eof { 2325 if {$got_refused} { 2326 # reported some errors, continued, and failed 2327 note "$testname test requires ability to log in as root" 2328 unsupported $testname 2329 } else { 2330 # unknown problem? 2331# perror "eof from rlogin $hostname -l root" 2332 note "eof (and unrecognized messages?) from rlogin $hostname -l root" 2333 note "$testname test requires ability to log in as root" 2334 unsupported $testname 2335 } 2336 stop_root_shell 2337 set timeout $old_timeout 2338 catch "expect_after" 2339 set can_get_root no 2340 return 0 2341 } 2342 } 2343 2344 expect_after { 2345 timeout { 2346 perror "timeout from rlogin $hostname -l root" 2347 stop_root_shell 2348 set timeout $old_timeout 2349 catch "expect_after" 2350 set can_get_root no 2351 return 0 2352 } 2353 eof { 2354 perror "eof from rlogin $hostname -l root" 2355 stop_root_shell 2356 set timeout $old_timeout 2357 catch "expect_after" 2358 set can_get_root no 2359 return 0 2360 } 2361 } 2362 2363 # Make sure the root shell is using /bin/sh. 2364 send "$BINSH\r" 2365 expect { 2366 -re "$ROOT_PROMPT" { } 2367 } 2368 2369 # Set up a shell variable tmppwd. The callers use this to keep 2370 # command line lengths down. The command line length is important 2371 # because we are feeding input to a shell via a pty. On some 2372 # systems a pty will only accept 255 characters. 2373 send "tmppwd=$tmppwd\r" 2374 expect { 2375 -re "$ROOT_PROMPT" { } 2376 } 2377 2378 # Set up our krb5.conf 2379 send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r" 2380 expect { 2381 -re "$ROOT_PROMPT" { } 2382 } 2383 send "export KRB5_CONFIG\r" 2384 expect { 2385 -re "$ROOT_PROMPT" { } 2386 } 2387 2388 # Move over to the right directory. 2389 set dir [pwd] 2390 send "cd $dir\r" 2391 expect { 2392 -re "$ROOT_PROMPT" { } 2393 "$dir:" { 2394 perror "root shell can not cd to $dir" 2395 set timeout $old_timeout 2396 stop_root_shell 2397 set can_get_root no 2398 return 0 2399 } 2400 } 2401 2402 expect_after 2403 set timeout $old_timeout 2404 2405 return 1 2406} 2407 2408proc setup_root_shell_noremote { testname } { 2409 global BINSH 2410 global ROOT_PROMPT 2411 global KEY 2412 global hostname 2413 global rlogin_spawn_id 2414 global rlogin_pid 2415 global tmppwd 2416 global env 2417 2418 eval spawn $BINSH 2419 set rlogin_spawn_id $spawn_id 2420 set rlogin_pid [exp_pid] 2421 2422 expect_after { 2423 timeout { 2424 perror "timeout from root shell" 2425 stop_root_shell 2426 catch "expect_after" 2427 return 0 2428 } 2429 eof { 2430 perror "eof from root shell" 2431 stop_root_shell 2432 catch "expect_after" 2433 return 0 2434 } 2435 } 2436 expect { 2437 -re "$ROOT_PROMPT" { } 2438 } 2439 2440 # Set up a shell variable tmppwd. The callers use this to keep 2441 # command line lengths down. The command line length is important 2442 # because we are feeding input to a shell via a pty. On some 2443 # systems a pty will only accept 255 characters. 2444 send "tmppwd=$tmppwd\r" 2445 expect { 2446 -re "$ROOT_PROMPT" { } 2447 } 2448 2449 # Set up our krb5.conf 2450 send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r" 2451 expect { 2452 -re "$ROOT_PROMPT" { } 2453 } 2454 send "export KRB5_CONFIG\r" 2455 expect { 2456 -re "$ROOT_PROMPT" { } 2457 } 2458 2459 # Move over to the right directory. 2460 set dir [pwd] 2461 send "cd $dir\r" 2462 expect { 2463 -re "$ROOT_PROMPT" { } 2464 "$dir:" { 2465 perror "root shell can not cd to $dir" 2466 stop_root_shell 2467 return 0 2468 } 2469 } 2470 2471 expect_after 2472 2473 return 1 2474} 2475 2476# Kill off a root shell started by setup_root_shell. 2477 2478proc stop_root_shell { } { 2479 global rlogin_spawn_id 2480 global rlogin_pid 2481 2482 catch "close -i $rlogin_spawn_id" 2483 catch "exec kill $rlogin_pid" 2484 sleep 1 2485 catch "exec kill -9 $rlogin_pid" 2486 catch "wait -i $rlogin_spawn_id" 2487} 2488 2489# Check the date. The string will be the output of date on this 2490# system, and we must make sure that it is in the same timezone as the 2491# output of date run a second time. The first date will be run on an 2492# rlogin or some such connection to the local system. This is to test 2493# to make sure that the TZ environment variable is handled correctly. 2494# Returns 1 on sucess, 0 on failure. 2495 2496proc check_date { date } { 2497 catch "exec date" ndate 2498 set atz "" 2499 set ntz "" 2500 scan $date "%s %s %d %d:%d:%d %s %d" adow amon adom ahr amn asc atz ayr 2501 scan $ndate "%s %s %d %d:%d:%d %s %d" ndow nmon ndom nhr nmn nsc ntz nyr 2502 if { $atz != $ntz } { 2503 verbose -log "date check failed: $atz != $ntz" 2504 return 0 2505 } 2506 return 1 2507} 2508 2509proc touch { file } { 2510 set f [open $file "a"] 2511 puts $f "" 2512 close $f 2513} 2514 2515# Implement this in tcl someday? 2516proc tail1 { file } { 2517 exec tail -1 $file 2518} 2519 2520# setup_wrapper 2521# Sets up a wraper script to set the runtime shared library environment 2522# variables and then executes a specific command. This is used to allow 2523# a "rsh klist" or telnetd to execute login.krb5. 2524proc setup_wrapper { file command } { 2525 global BINSH 2526 global env 2527 2528 # We will start with a BINSH script 2529 file delete $file 2530 2531 set f [open $file "w" 0777] 2532 puts $f "#!$BINSH" 2533 puts $f "KRB5_CONFIG=$env(KRB5_CONFIG)" 2534 puts $f "export KRB5_CONFIG" 2535 puts $f "exec $command" 2536 close $f 2537 2538 return 1 2539} 2540 2541proc krb_exit { } { 2542 stop_kerberos_daemons 2543} 2544 2545# helpful sometimes for debugging the test suite 2546proc export_debug_envvars { } { 2547 global env 2548 foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST RLOGIN RLOGIN_FLAGS RLOGIND FTP FTPD KPASSWD REALMNAME GSSCLIENT KPROPLOG} { 2549 global $i 2550 if [info exists $i] { set env($i) [set $i] } 2551 } 2552} 2553proc spawn_xterm { } { 2554 export_debug_envvars 2555 exec "xterm" 2556} 2557proc spawn_shell { } { 2558 export_debug_envvars 2559 spawn "sh" 2560 exp_interact 2561} 2562