Re: [users@httpd] graceful-stop closes established connections without response

2024-01-30 Thread Sherrard Burton
i have confirmed that the patch has been applied, and the behavior still 
persists, as confirmed by comparing the counts of [SYN,ACK] and accept()


~$ tcpdump -n -r /tmp/tcpdump.pcap | grep -Fc '[S.]'; grep -Fh 'accept4' 
/tmp/strace-apache2.out.* | grep -Fc .240.209
reading from file /tmp/tcpdump.pcap, link-type LINUX_SLL2 (Linux cooked 
v2), snapshot length 262144

Warning: interface names might be incorrect
3485
3483

as well as

~$ for i in '> GET /index.html' '< HTTP/1.1 200 OK'; do echo -e 
"'$i':\t$( cat /tmp/curl-[0-9]*.out | grep -Fc "$i" )"; done

'> GET /index.html': 3485
'< HTTP/1.1 200 OK': 3483

~$ grep -F reset /tmp/curl-[0-9]*.out
/tmp/curl-13.out:* Recv failure: Connection reset by peer
/tmp/curl-13.out:curl: (56) Recv failure: Connection reset by peer
/tmp/curl-2.out:* Recv failure: Connection reset by peer
/tmp/curl-2.out:curl: (56) Recv failure: Connection reset by peer

which all seem to agree that there were two failed connections

and, in case this shines some light on things:

~$ grep -F '19:10:50' /var/log/apache2/error.log | grep -F XXX
[Tue Jan 30 19:10:50.357074 2024] [mpm_event:notice] [pid 151381:tid 
140267709454016] XXX: may exit (0, 1)
[Tue Jan 30 19:10:50.357498 2024] [mpm_event:notice] [pid 151382:tid 
140267709454016] XXX: may exit (0, 2)
[Tue Jan 30 19:10:50.357610 2024] [mpm_event:notice] [pid 151381:tid 
140267709454016] XXX: draining
[Tue Jan 30 19:10:50.358011 2024] [mpm_event:notice] [pid 151381:tid 
140267709454016] XXX: exiting
[Tue Jan 30 19:10:50.358091 2024] [mpm_event:notice] [pid 151382:tid 
140267709454016] XXX: draining
[Tue Jan 30 19:10:50.358201 2024] [mpm_event:notice] [pid 151381:tid 
140267709454016] XXX: closing
[Tue Jan 30 19:10:50.358492 2024] [mpm_event:notice] [pid 151382:tid 
140267709454016] XXX: exiting
[Tue Jan 30 19:10:50.358906 2024] [mpm_event:notice] [pid 151382:tid 
140267709454016] XXX: closing
[Tue Jan 30 19:10:50.366948 2024] [mpm_event:notice] [pid 151381:tid 
140267709454016] XXX: exited
[Tue Jan 30 19:10:50.367124 2024] [mpm_event:notice] [pid 151382:tid 
140267709454016] XXX: exited



On 1/30/24 06:09 AM, Yann Ylavic wrote:

On Tue, Jan 30, 2024 at 11:54 AM Yann Ylavic  wrote:


On Tue, Jan 30, 2024 at 4:37 AM Sherrard Burton  wrote:


i was going to add some debugging lines, but when i took a quick look at
the patch, i wasn't clear on which sections of the code i should be
guaranteed to hit. can you be so kind as to send an updated patch with
some gratuitous logging in the appropriate sections so that there will
be positive affirmation that the patch has (or hasn't) been applied and
is falling into the expected sections?


Sure, here is a v2 (which also includes a fix w.r.t. v1).


Argh, please use this v3 instead, I missed that EINTR could interfere
and should be ignored while draining.



Regards;
Yann.


-
To unsubscribe, e-mail: users-unsubscr...@httpd.apache.org
For additional commands, e-mail: users-h...@httpd.apache.org


-
To unsubscribe, e-mail: users-unsubscr...@httpd.apache.org
For additional commands, e-mail: users-h...@httpd.apache.org



Re: [users@httpd] If statement against AUTHENTICATE_memberOf variable created by authnz_ldap

2024-01-30 Thread Adam Cecile

On 1/26/24 18:13, Eric Covener wrote:

So the first question is: Is it normal that I have to use mod_rewrite to
check for group membership ? I tried hundred of syntaxes with SetEnvIf
or SetEnvIfExpr but I never managed to get it working. I'm not sure why
but I guess it's somehow related to "race condition" (lazy evaluation)
while evaluating environment variable, does it makes sense ?

SetEnvIf[expr] is evaluated very early, long before authn/authz occurs
and those environment variables can be filled out.


Second question is: I cannot use "$" to make a proper regex matcher. If
the group is not the last one, I can match it with ;.*$, if it is the
last one, I should be able to match [...]DC=internal$, however that does
not work. There's is one unknown character and I have no idea what it
is. Matching with DC=internal.?$ works, so that's one SINGLE char... Any
idea ?


Hello,


Thanks a lot for your help. I ended up going for a completely different 
way because I found it was too messy... So here is the LUA script I use 
instead:


require 'apache2'

local admin_profiles = {
  'CN=Group1,OU=Groups,DC=domain,DC=com',
  'CG=Group2,DC=domain,DC=com',
}
local manager_profiles = {
  'CN=Group1,OU=Groups,DC=domain,DC=com',
  'CN=Group3,OU=Groups,DC=domain,DC=com',
}
local operator_profiles = {
}
local viewer_profiles = {
  'CN=Group4,OU=Groups,DC=domain,DC=com',
  'CN=Group5,OU=Groups,DC=domain,DC=com',
}

local function has_value_case_insensitive(tab, val)
    for index, value in ipairs(tab) do
    if value:lower() == val:lower() then
    return true
    end
    end
    return false
end

function authcheck_hook(r)
  -- Extract username and group list from Active Directory authentication
  local sam_account_name = r.subprocess_env['AUTHENTICATE_SAMACCOUNTNAME']
  local member_of = r.subprocess_env['AUTHENTICATE_MEMBEROF']

  -- Check if Active Directory variables are not set, if so, return 403 
and log error

  if (sam_account_name == nil or sam_account_name == '') then
    r:err("ActiveDirectory group to PCC profile LUA script called but 
AUTHENTICATE_SAMACCOUNTNAME was not set")

    return 403
  end
  if (member_of == nil or member_of == '') then
    r:err("ActiveDirectory group to PCC profile LUA script called but 
AUTHENTICATE_MEMBEROF was not set")

    return 403
  end

  -- Split group member ship into an array and match corresponding profile
  local member_of_split_regex = '([^;%s*]+)'
  local member_of_profiles = {}
  for member_of_entry in member_of:gmatch(member_of_split_regex) do
    local member_of_entry_profiles = {}
    if has_value_case_insensitive(admin_profiles, member_of_entry) then
  if not has_value_case_insensitive(member_of_entry_profiles, 
"admin") then

    table.insert(member_of_entry_profiles, "admin")
  end
  if not has_value_case_insensitive(member_of_profiles, "admin") then
    table.insert(member_of_profiles, "admin")
  end
    end
    if has_value_case_insensitive(manager_profiles, member_of_entry) then
  if not has_value_case_insensitive(member_of_entry_profiles, 
"manager") then

    table.insert(member_of_entry_profiles, "manager")
  end
  if not has_value_case_insensitive(member_of_profiles, "manager") then
    table.insert(member_of_profiles, "manager")
  end
    end
    if has_value_case_insensitive(operator_profiles, member_of_entry) then
  if not has_value_case_insensitive(member_of_entry_profiles, 
"operator") then

    table.insert(member_of_entry_profiles, "operator")
  end
  if not has_value_case_insensitive(member_of_profiles, "operator") 
then

    table.insert(member_of_profiles, "operator")
  end
    end
    if has_value_case_insensitive(viewer_profiles, member_of_entry) then
  if not has_value_case_insensitive(member_of_entry_profiles, 
"viewer") then

    table.insert(member_of_entry_profiles, "viewer")
  end
  if not has_value_case_insensitive(member_of_profiles, "viewer") then
    table.insert(member_of_profiles, "viewer")
  end
    end
    if next(member_of_entry_profiles) == nil then
  r:debug(("Username %s ActiveDirectory group %s gives no PCC 
privileges"):format(sam_account_name, member_of_entry))

    else
  r:debug(("Username %s ActiveDirectory group %s gives PCC 
privileges: %s"):format(sam_account_name, member_of_entry, 
table.concat(member_of_entry_profiles, ', ')))

    end
  end

  -- Compare all matched group resulting profile and get the one with 
highest privileges

  if has_value_case_insensitive(member_of_profiles, "admin") then
    r:info(("Username %s authorized with PCC admin 
privileges"):format(sam_account_name, member_of_entry))

    r.headers_in['X-PCC-Group'] = "admin"
  elseif has_value_case_insensitive(member_of_profiles, "manager") then
    r:info(("Username %s authorized with PCC manager 
privileges"):format(sam_account_name, member_of_entry))

    r.headers_in['X-PCC-Group'] = "manager"
  elseif 

Re: [users@httpd] graceful-stop closes established connections without response

2024-01-30 Thread Yann Ylavic
On Tue, Jan 30, 2024 at 11:54 AM Yann Ylavic  wrote:
>
> On Tue, Jan 30, 2024 at 4:37 AM Sherrard Burton  wrote:
> >
> > i was going to add some debugging lines, but when i took a quick look at
> > the patch, i wasn't clear on which sections of the code i should be
> > guaranteed to hit. can you be so kind as to send an updated patch with
> > some gratuitous logging in the appropriate sections so that there will
> > be positive affirmation that the patch has (or hasn't) been applied and
> > is falling into the expected sections?
>
> Sure, here is a v2 (which also includes a fix w.r.t. v1).

Argh, please use this v3 instead, I missed that EINTR could interfere
and should be ignored while draining.

>
> Regards;
> Yann.
Index: server/mpm/event/event.c
===
--- server/mpm/event/event.c	(revision 1915442)
+++ server/mpm/event/event.c	(working copy)
@@ -174,7 +174,7 @@ static int had_healthy_child = 0;
 static volatile int dying = 0;
 static volatile int workers_may_exit = 0;
 static volatile int start_thread_may_exit = 0;
-static volatile int listener_may_exit = 0;
+static volatile apr_uint32_t listener_may_exit = 0;
 static int listener_is_wakeable = 0;/* Pollset supports APR_POLLSET_WAKEABLE */
 static int num_listensocks = 0;
 static apr_int32_t conns_this_child;/* MaxConnectionsPerChild, only access
@@ -481,8 +481,7 @@ static void disable_listensocks(void)
 static void enable_listensocks(void)
 {
 int i;
-if (listener_may_exit
-|| apr_atomic_cas32(_disabled, 0, 1) != 1) {
+if (dying || apr_atomic_cas32(_disabled, 0, 1) != 1) {
 return;
 }
 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
@@ -575,8 +574,7 @@ static void wakeup_listener(void)
 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
  "wake up listener%s", listener_may_exit ? " again" : "");
 
-listener_may_exit = 1;
-disable_listensocks();
+apr_atomic_cas32(_may_exit, 1, 0);
 
 /* Unblock the listener if it's poll()ing */
 if (event_pollset && listener_is_wakeable) {
@@ -1184,12 +1182,9 @@ read_request:
 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
 goto read_request;
 }
-else if (!listener_may_exit) {
+else {
 cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
 }
-else {
-cs->pub.state = CONN_STATE_LINGER;
-}
 }
 
 if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
@@ -1256,18 +1251,21 @@ static void check_infinite_requests(void)
 }
 }
 
-static int close_listeners(int *closed)
+static int close_listeners(void)
 {
 ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
  "clos%s listeners (connection_count=%u)",
- *closed ? "ed" : "ing", apr_atomic_read32(_count));
-if (!*closed) {
+ dying ? "ed" : "ing", apr_atomic_read32(_count));
+if (!dying) {
 int i;
 
+dying = 1; /* once */
+
+ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
+ "XXX: closing");
+
 ap_close_listeners_ex(my_bucket->listeners);
-*closed = 1; /* once */
 
-dying = 1;
 ap_scoreboard_image->parent[ap_child_slot].quiescing = 1;
 for (i = 0; i < threads_per_child; ++i) {
 ap_update_child_status_from_indexes(ap_child_slot, i,
@@ -1654,8 +1652,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 proc_info *ti = dummy;
 int process_slot = ti->pslot;
 struct process_score *ps = ap_get_scoreboard_process(process_slot);
-int closed = 0;
-int have_idle_worker = 0;
+int have_idle_worker = 0, exiting = 0;
 apr_time_t last_log;
 
 last_log = apr_time_now();
@@ -1678,8 +1675,8 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 if (conns_this_child <= 0)
 check_infinite_requests();
 
-if (listener_may_exit) {
-int first_close = close_listeners();
+if (exiting) {
+int first_close = close_listeners();
 
 if (terminate_mode == ST_UNGRACEFUL
 || apr_atomic_read32(_count) == 0)
@@ -1710,7 +1707,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_
  apr_atomic_read32(keepalive_q->total),
  apr_atomic_read32(_count),
  apr_atomic_read32(_count));
-if (dying) {
+if (exiting) {
 ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
  "%u/%u workers shutdown",
  apr_atomic_read32(_shutdown),
@@ -1792,6 +1789,13 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 }
 num = 0;
 }
+if (!exiting && apr_atomic_read32(_may_exit)) {
+

Re: [users@httpd] graceful-stop closes established connections without response

2024-01-30 Thread Yann Ylavic
On Tue, Jan 30, 2024 at 4:37 AM Sherrard Burton  wrote:
>
> i was going to add some debugging lines, but when i took a quick look at
> the patch, i wasn't clear on which sections of the code i should be
> guaranteed to hit. can you be so kind as to send an updated patch with
> some gratuitous logging in the appropriate sections so that there will
> be positive affirmation that the patch has (or hasn't) been applied and
> is falling into the expected sections?

Sure, here is a v2 (which also includes a fix w.r.t. v1).

Regards;
Yann.
Index: server/mpm/event/event.c
===
--- server/mpm/event/event.c	(revision 1915442)
+++ server/mpm/event/event.c	(working copy)
@@ -174,7 +174,7 @@ static int had_healthy_child = 0;
 static volatile int dying = 0;
 static volatile int workers_may_exit = 0;
 static volatile int start_thread_may_exit = 0;
-static volatile int listener_may_exit = 0;
+static volatile apr_uint32_t listener_may_exit = 0;
 static int listener_is_wakeable = 0;/* Pollset supports APR_POLLSET_WAKEABLE */
 static int num_listensocks = 0;
 static apr_int32_t conns_this_child;/* MaxConnectionsPerChild, only access
@@ -481,8 +481,7 @@ static void disable_listensocks(void)
 static void enable_listensocks(void)
 {
 int i;
-if (listener_may_exit
-|| apr_atomic_cas32(_disabled, 0, 1) != 1) {
+if (dying || apr_atomic_cas32(_disabled, 0, 1) != 1) {
 return;
 }
 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
@@ -575,8 +574,7 @@ static void wakeup_listener(void)
 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
  "wake up listener%s", listener_may_exit ? " again" : "");
 
-listener_may_exit = 1;
-disable_listensocks();
+apr_atomic_cas32(_may_exit, 1, 0);
 
 /* Unblock the listener if it's poll()ing */
 if (event_pollset && listener_is_wakeable) {
@@ -1184,12 +1182,9 @@ read_request:
 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
 goto read_request;
 }
-else if (!listener_may_exit) {
+else {
 cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
 }
-else {
-cs->pub.state = CONN_STATE_LINGER;
-}
 }
 
 if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
@@ -1256,18 +1251,21 @@ static void check_infinite_requests(void)
 }
 }
 
-static int close_listeners(int *closed)
+static int close_listeners(void)
 {
 ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
  "clos%s listeners (connection_count=%u)",
- *closed ? "ed" : "ing", apr_atomic_read32(_count));
-if (!*closed) {
+ dying ? "ed" : "ing", apr_atomic_read32(_count));
+if (!dying) {
 int i;
 
+dying = 1; /* once */
+
+ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
+ "XXX: closing");
+
 ap_close_listeners_ex(my_bucket->listeners);
-*closed = 1; /* once */
 
-dying = 1;
 ap_scoreboard_image->parent[ap_child_slot].quiescing = 1;
 for (i = 0; i < threads_per_child; ++i) {
 ap_update_child_status_from_indexes(ap_child_slot, i,
@@ -1654,8 +1652,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 proc_info *ti = dummy;
 int process_slot = ti->pslot;
 struct process_score *ps = ap_get_scoreboard_process(process_slot);
-int closed = 0;
-int have_idle_worker = 0;
+int have_idle_worker = 0, exiting = 0;
 apr_time_t last_log;
 
 last_log = apr_time_now();
@@ -1678,8 +1675,8 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 if (conns_this_child <= 0)
 check_infinite_requests();
 
-if (listener_may_exit) {
-int first_close = close_listeners();
+if (exiting) {
+int first_close = close_listeners();
 
 if (terminate_mode == ST_UNGRACEFUL
 || apr_atomic_read32(_count) == 0)
@@ -1710,7 +1707,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_
  apr_atomic_read32(keepalive_q->total),
  apr_atomic_read32(_count),
  apr_atomic_read32(_count));
-if (dying) {
+if (exiting) {
 ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf,
  "%u/%u workers shutdown",
  apr_atomic_read32(_shutdown),
@@ -1792,6 +1789,10 @@ static void * APR_THREAD_FUNC listener_thread(apr_
 }
 num = 0;
 }
+if (!exiting && apr_atomic_read32(_may_exit)) {
+ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
+ "XXX: may exit (%d, %d)", rc, num);
+}
 
 if (APLOGtrace7(ap_server_conf)) {
 now =