1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
|
# In this test, we are using arrays as sets. The key itself does not matter,
# only the value
set test "server_trust"
# exp_internal 1
if {! [installtest_p]} { untested "client"; return }
if {! [nss_p]} { untested "client (no nss)"; return }
# Note we have to be root (to get the namespace to work correctly).
set effective_uid [exec /usr/bin/id -u]
if {$effective_uid != 0} { untested "client (must be root)"; return }
# Let's start with a clean slate in terms of trust.
exec rm -fr $env(SYSTEMTAP_DIR)/ssl
# arr given as list (e.g. [array_has [array get myarr] elem])
proc array_has {arr elem} {
array set foo $arr
if {[array size foo] == 0} {
return 0
}
foreach {key val} [array get foo] {
if {[string equal $val $elem]} {
return 1
}
}
return 0
}
# Check if array1 is a subset of array2. Returns 1 if yes, otherwise 0.
# (Modified from http://wiki.tcl.tk/1032.)
proc array_in {array1 array2} {
upvar 1 $array1 sub $array2 super
if {![array exists sub]} {
return -code error "$array1 is not an array"
}
if {![array exists super]} {
return -code error "$array2 is not an array"
}
if {[array size sub] > [array size super]} {
return 0
}
if {[array size sub] == 0} {
return 1
}
foreach key [array names sub] {
if {![array_has [array get super] $sub($key)]} {
return 0
}
}
return 1
}
# Check if array1 and array2 have all the same elements
proc array_equal {array1 array2} {
upvar 1 $array1 foo $array2 bar
return [expr [array_in foo bar] && [array_in bar foo]]
}
# Returns the union of the three arrays
proc array_union {array1 array2 array3} {
upvar 1 $array1 foo $array2 bar $array3 baz
array unset ::union
if {![array exists foo]} {
return -code error "$array1 is not an array"
}
if {![array exists bar]} {
return -code error "$array2 is not an array"
}
if {![array exists baz]} {
return -code error "$array3 is not an array"
}
set n 0
foreach key [array names foo] {
set ::union($n) $foo($key)
incr n
}
foreach key [array names bar] {
if {![array_has [array get ::union] $bar($key)]} {
set ::union($n) $bar($key)
incr n
}
}
foreach key [array names baz] {
if {![array_has [array get ::union] $baz($key)]} {
set ::union($n) $baz($key)
incr n
}
}
}
# Returns all the elements in array_new not in array_old
proc array_diff {array_new array_old} {
upvar 1 $array_new anew $array_old aold
array unset ::diff
if {![array exists anew]} {
return -code error "$array_new is not an array"
}
if {![array exists aold]} {
return -code error "$array_old is not an array"
}
if {[array size anew] == 0} {
verbose -log "array_diff $array_new size = 0"
}
foreach {index value} [array get anew] {
verbose -log "array_diff $array_new index: $index, value: $value"
}
if {[array size aold] == 0} {
verbose -log "array_diff $array_old size = 0"
}
foreach {index value} [array get aold] {
verbose -log "array_diff $array_old index: $index, value: $value"
}
set n 0
foreach key [array names anew] {
if {![array_has [array get aold] $anew($key)]} {
set ::diff($n) $anew($key)
incr n
}
}
}
# Test the --list-servers option and return an array of the servers found.
proc list_servers { TEST_NAME SERVER_SPEC args } {
global systemtap_http_server_spec
set failed 0
set n 0
array unset ::servers
set cmd [concat stap --list-servers=$SERVER_SPEC $args --use-http-server=$systemtap_http_server_spec]
send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 150
-re "^Systemtap Compile Server Status for '${SERVER_SPEC}'\r\n" {
exp_continue
}
-re {^No servers found\r\n} {
}
-re {^ host=[^\r]*\r\n} {
set ::servers($n) "$expect_out(0,string)"
incr n
exp_continue
}
-re {^No certificate found in database [^\r]*\r\n} {
exp_continue
}
-re {^[^\r]*\r\n} {
verbose -log "unexpected output: $expect_out(0,string)"
set failed 1
}
timeout {
verbose -log "timeout"
kill -INT -[exp_pid] 2
set failed 1
}
}
catch {close}; catch {wait}
if {$failed != 0} {
fail "$TEST_NAME"
} else {
pass "$TEST_NAME"
}
}
# Test the --list-servers option and return an array of the servers
# found in the custom namespace.
proc ns_list_servers { TEST_NAME SERVER_SPEC args } {
global systemtap_http_server_spec
set failed 0
set n 0
array unset ::servers
set cmd "stap --list-servers=$SERVER_SPEC $args --use-http-server=$systemtap_http_server_spec"
send_log "executing: $cmd\n"
lassign [server_ns_as_root $cmd] rc output
if {$rc == 0} {
# The command succeeded. Search the output for the servers.
foreach line [split $output \n] {
if {[regexp {^ host=(.*)$} $line match server]} {
set ::servers($n) $server
incr n
} elseif {[regexp "^Systemtap Compile Server Status for '${SERVER_SPEC}'$" $line]
|| [regexp {^No servers found$} $line]
|| [regexp {^No certificate found in database .*$} $line]} {
# Ignore this output
} else {
verbose -log "unexpected output: $line"
}
}
pass "$TEST_NAME"
} else {
fail "$TEST_NAME"
}
}
array set existing_online_servers {}
array set existing_trusted_servers {}
# array set existing_signing_servers {}
# Now start our own server and make sure we can work with it.
if {[http_start_server] == 0} {
pass "$test server start"
} else {
untested "$test server start"
return
}
# There may be existing trusted signers. Keep track of them.
list_servers "List existing signing servers" signer
array unset existing_signing_servers
array set existing_signing_servers [array get servers]
# Our server should now appear online, separate from the previously
# discovered online servers. Note that our server could generate
# serveral listings because it could appear at more than one ip
# address,
list_servers "List current online servers" online
array unset current_online_servers
array set current_online_servers [array get servers]
# array_diff will give us all the servers in current not in existing
array_diff current_online_servers existing_online_servers
array unset new_online_servers
array set new_online_servers [array get diff]
set test "New online servers"
if {[array size new_online_servers] > 0} {
pass "$test"
} else {
fail "$test"
}
# Our server should now be trusted, separate from the previously
# discovered trusted servers.
list_servers "List current trusted servers" online,trusted
array unset current_trusted_servers
array set current_trusted_servers [array get servers]
# array_diff will give us all the servers in current not in existing
array_diff current_trusted_servers existing_trusted_servers
array unset new_trusted_servers
array set new_trusted_servers [array get diff]
set test "New trusted servers"
if {[array size new_trusted_servers] > 0} {
pass "$test"
} else {
fail "$test"
}
# The new servers should automatically be trusted, so the
# new_trusted_servers array should be a subset of the
# new_online_servers array, but not necessarily vice-versa, since new
# servers may have come online independently of our testing.
set test "Verify new trusted server list"
if {[array_in new_trusted_servers new_online_servers]} {
pass "$test"
} else {
fail "$test"
}
# The newly trusted servers represent the server we just started.
array unset our_servers
array set our_servers [array get new_trusted_servers]
# The new servers should not be trusted as signers so there should be
# no new signing servers.
list_servers "List current signing servers" signer
array unset current_signing_servers
array set current_signing_servers [array get servers]
set test "No new signing servers"
if {[array_equal current_signing_servers existing_signing_servers]} {
pass "$test"
} else {
fail "$test"
}
# Revoke trust in our server. Specify the server by host name.
set test "Server has host name"
if {[array size our_servers] > 0} {
if {[regexp {^ host=([^ ]*).*} $our_servers(0) match host_name]} {
pass $test
} else {
fail $test
}
} else {
fail "$test no servers in list"
}
# Compile and run a simple hello test, selecting the server automatically
set test "Hello from server"
set rc [stap_run_batch $srcdir/systemtap.server/hello.stp --use-http-server=$systemtap_http_server_spec]
if {$rc == 0} { pass $test } else { fail $test }
set cmd [concat stap --trust-servers=ssl,revoke,no-prompt --use-http-server=$systemtap_http_server_spec]
send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 150
-re {^.*\r\n} { exp_continue }
timeout {
kill -INT -[exp_pid] 2
set failed 1
}
}
catch {close}; catch {wait}
# Our server should no longer be trusted.
list_servers "List current trusted servers after revocation by host name" trusted
array unset current_trusted_servers
array set current_trusted_servers [array get servers]
set test "No longer trusted after revocation by host name"
if {[array_equal current_trusted_servers existing_trusted_servers]} {
pass "$test"
} else {
fail "$test"
}
# Reinstate trust in our server. Specify the server by ip address.
# The default for --trusted servers is 'ssl'.
set test "Server has ip address"
if {[array size our_servers] > 0} {
if {[regexp {^.*address=([^ ]*).*} $our_servers(0) match ip_address]} {
pass $test
} else {
fail $test
}
} else {
fail "$test no servers in list"
}
set cmd [concat stap --trust-servers=no-prompt --use-http-server=$systemtap_http_server_spec]
send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 150
-re {^.*\r\n} { exp_continue }
timeout {
kill -INT -[exp_pid] 2
set failed 1
}
}
catch {close}; catch {wait}
# Our server should be trusted again, separate from the previously discovered
# trusted servers.
list_servers "List current trusted servers after reinstatement by ip address" online,trusted
array unset current_trusted_servers
array set current_trusted_servers [array get servers]
array_diff current_trusted_servers existing_trusted_servers
array unset new_trusted_servers
array set new_trusted_servers [array get diff]
set test "New trusted servers after reinstatement by ip address"
if {[array size new_trusted_servers] > 0} {
pass "$test"
} else {
fail "$test"
}
# The new_trusted_servers array should now match the our_servers
# array, since the our_servers array is a copy of the original
# new_trusted_servers array.
set test "New trusted servers matches after reinstatement by ip address"
if {[array size our_servers] > 0} {
if {[array_equal new_trusted_servers our_servers]} {
pass "$test"
} else {
fail "$test"
verbose -log "new_trusted_servers:"
foreach {index value} [array get new_trusted_servers] {
verbose -log " index: $index, value: $value"
}
verbose -log "our_servers:"
foreach {index value} [array get our_servers] {
verbose -log " index: $index, value: $value"
}
}
} else {
fail "$test no servers in list"
}
# Trust our server as a module signer. This must be done as root and
# in the namespace. Specify the server by certificate serial number.
set test "Server has certificate serial number"
if {[array size our_servers] > 0} {
if {[regexp {^.*certinfo="([^ ]*)".*} $our_servers(0) match cert_info]} {
pass $test
} else {
fail $test
}
} else {
fail "$test no servers in list"
}
# Grab the existing trusted signers in the namespace. There should be
# none (since we're starting with a clean slate).
set test "Namespace existing signer servers"
ns_list_servers "List namespace existing signing servers" signer
array unset ns_existing_signing_servers
array set ns_existing_signing_servers [array get servers]
if {[array size ns_existing_signing_servers] == 0} {
pass $test
} else {
fail $test
}
# We only want to change the system's trusted signer list in our mount
# namespace, not in the real system.
set test "Adding trusted signer (in a namespace)"
set cmd "stap --trust-servers=signer,no-prompt --use-http-server=$systemtap_http_server_spec"
lassign [server_ns_as_root $cmd] rc output
if {$rc == 0} {
pass "$test"
} else {
fail "$test"
}
# Our server should now be trusted as a signer (but only in our namespace).
ns_list_servers "List namespace current online signing servers" online,signer
array unset ns_current_signing_servers
array set ns_current_signing_servers [array get servers]
# The current list of signing servers in the namespace should have
# changed.
array_diff ns_current_signing_servers ns_existing_signing_servers
array unset ns_new_signing_servers
array set ns_new_signing_servers [array get diff]
set test "New namespace signing servers"
if {[array size ns_new_signing_servers] > 0} {
pass "$test"
} else {
fail "$test"
}
# The current list of signing servers shouldn't have changed in the
# real system (since the list of servers in the real system and in the
# namespace should be separate).
list_servers "List current online signing servers" online,signer
array unset current_signing_servers
array set current_signing_servers [array get servers]
array_diff current_signing_servers existing_signing_servers
array unset new_signing_servers
array set new_signing_servers [array get diff]
set test "New signing servers"
if {[array size new_signing_servers] == 0} {
pass "$test"
} else {
fail "$test"
}
set test "Server has port number"
if {[array size ns_new_signing_servers] > 0} {
if {[regexp {^.*port=([^ ]*).*} $ns_new_signing_servers(0) match port_num]} {
pass $test
} else {
fail $test
}
} else {
fail "$test no new signing servers"
}
foreach privilege {"--unprivileged" "--privilege=stapusr" "--privilege=stapsys"} {
# Compile a simple test using an unprivileged setting. This will
# ask the server to check and sign the module. Specify the server
# using host name and port.
#
# Notice we can use the server directly, and don't need to be in
# the namespace. We'll need to be in the namespace when trying to
# run the compiled module.
set test "Compile module using server with $privilege"
set failed 1
set module_name ""
set cmd [concat stap -p4 $privilege $srcdir/systemtap.server/hello.stp --use-http-server=$systemtap_http_server_spec]
send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 150
-re {^stap_[^ \t\r\n]*\.ko\r\n} {
set module_name [string trim "$expect_out(0,string)" \r\n]
set failed 0
exp_continue
}
-re {^.*\r\n} { exp_continue }
timeout {
kill -INT -[exp_pid] 2
}
}
catch {close}; catch {wait}
if {$failed == 0} {
pass "$test"
}
send_log "'$module_name'\n"
# Make sure that the module was returned
set no_module 0
set test "Module was created with $privilege"
catch {exec /bin/ls $module_name $module_name.sgn} result
send_log "$result\n"
if {[file exists $module_name]} {
pass "$test"
} else {
fail "$test"
set no_module 1
}
# Make sure that the module was signed
set no_signature 0
set test "Module was signed with $privilege"
if {[file exists $module_name.sgn]} {
pass "$test"
} else {
fail "$test"
set no_signature 1
}
# Make sure we can load the module. This will verify that the
# signature is correct and trusted. There must be a module to
# load.
#
# Note that we must do this in the namespace, since only there can
# the signature be verified.
#
# We're going to use the optional 'stapusr' and 'stapsys' users,
# if they exist.
set test "Load and run signed module when trusted with $privilege"
set user ""
if {$privilege == "--privilege=stapsys"} {
if {$systemtap_stapsys_user_exists} {
set user "stapsys"
} elseif {$systemtap_stapusr_user_exists} {
set user "stapusr"
setup_xfail *-*-*
}
} else {
if {$systemtap_stapusr_user_exists} {
set user "stapusr"
}
}
if {$no_module == 1 || $no_signature == 1 || [string length $user] == 0} {
untested "$test"
} else {
set failed 1
set module_path [exec pwd]/$module_name
set cmd [concat staprun $module_path]
lassign [server_ns_as_user $user $cmd] rc output
if {$rc == 0} {
foreach line [split $output \n] {
if {[regexp {^Hello From Server$} $line]} {
set failed 0
}
}
}
if {$failed == 0} {
pass "$test"
} else {
fail "$test"
}
}
}
# Revoke trust in our server as a module signer in the namespace.
# Specify the server by certificate serial number to ensure we're
# revoking trust in the correct server.
set test "Revoking trusted signer (in a namespace)"
if {[info exists cert_info]} {
set cmd [concat stap --trust-servers=revoke,signer,no-prompt --use-http-server=$cert_info]
lassign [server_ns_as_root $cmd] rc output
if {$rc == 0} {
pass "$test"
} else {
fail "$test"
}
} else {
fail "$test no cert_info"
}
# Our server should no longer be trusted as a signer in the namespace.
ns_list_servers "List namespace current signing servers after revocation " signer
array unset ns_current_signing_servers
array set ns_current_signing_servers [array get servers]
set test "No longer trusted as a signer after revocation"
foreach {index value} [array get ns_current_signing_servers] {
verbose -log "ns_current_signing_servers: $index, value: $value"
}
foreach {index value} [array get ns_existing_signing_servers] {
verbose -log "ns_existing_signing_servers: $index, value: $value"
}
if {[array_in ns_current_signing_servers ns_existing_signing_servers]} {
pass "$test"
} else {
fail "$test"
}
# Since our server is no longer a trusted signer, attempting to load
# and run the module now should fail (when run as 'stapsys' in the
# namespace). We have to use the 'stapsys' user since the last module
# compiled used "--privilege=stapsys".
set test "Load and run signed module when not trusted"
if {$no_module == 1 || !$systemtap_stapsys_user_exists} {
untested "$test"
} else {
setup_xfail *-*-*
set failed 1
set module_path [exec pwd]/$module_name
set cmd [concat staprun $module_path]
lassign [server_ns_as_user "stapsys" $cmd] rc output
if {$rc == 0} {
foreach line [split $output \n] {
if {[regexp {^Hello From Server$} $line]} {
set failed 0
}
}
}
if {$failed == 0} {
pass "$test"
} else {
fail "$test"
}
}
# Shutdown the server we started
http_shutdown_server
|