Here's what I've figure out, but first, why this is important:
In some website platforms with plugins, adding an insecure plugin can compromise an entire site. Openacs Pacakges via the package repository are somewhat akin to plugins. Any package that requires a high level of security, such as with health or ecommerce, needs to anticipate that it might be used alongside other packages that have not been vetted as thoroughly for vulnerabilities. Adding a little hurdle can offer some extra time for detecting and stopping an attack in progress without sustaining excessive losses.
Adding " set __calling_proc $proc_name_as_passed" to the body of code defined by each ad_proc doesn't work well. It's too easy to spoof by writing over the set value.
Below is example code that chains a value using upvar from the first proc to all dependent procs that need checking.
The name of the variable is dynamic, so it would take a little work to decode. This variable is audited against the same variable and value defined in the thread's namespace. The name of the variable is defined by ns_thread info, which means that it could be figured out with some work, but I anticipate this is about as much protection as can be expected.
This method could be improved if there is some thread-level information available to the thread via an ns_* call that is not shared with other threads --maybe the time thread began for example.
Anyway, here is the code:
ad_proc -private proc_context_set {
} {
Set floating context in the first proc that calls other procs.
} {
set a [ns_thread id]
upvar 1 $a b
set b $a
set n "::app-namespace::"
set ${n}${a} $a
return 1
}
ad_proc -private proc_in_context_q {
{namespace_name "::app-namespace::"}
} {
Checks if a scheduled proc is running in context of its namespace.
} {
# To work as expected, each proc in namespace must call this function
set a [ns_thread id]
upvar 3 $a $a
if { ![info exists $a] || ![info exists ${namespace_name}${a} ] || [set $a] ne [set ${namespace_name}${a} ]} {
ns_log Warning "proc_in_context_q: namespace '${namespace_name}' no! ns_thread id '${a}' info level '[info level]' namespace current '[namespace current]' "
set context_p 0
} else {
upvar 2 $a $a
set context_p 1
}
return $context_p
}
ad_proc -private proc_that_tests_context_checking {
} {
This is a dummy proc that checks if context checker is working.
} {
ns_log Notice "proc_that_tests_context_checking: info level '[info level]' namespace current '[namespace current]'"
set allowed_p [go_ahead ]
ns_log Notice "proc_that_tests_context_checking: context check. PASSED."
}
proc go_ahead calls proc_in_context_q among other things.
Criticisms and comments welcome,
(^Ben