I found a bug in the UAM challenge RPC implementation.
The issue is in src/redir.c, inside redir_ensure_challenge_rpc().
The current code reads the RPC response directly into the existing
redir_conn_t structure:
if (safe_read(s, conn, sizeof(*conn)) != sizeof(*conn)) {
...
}
This overwrites the entire conn structure.
This is problematic during REDIR_LOGIN because conn also contains the
current authentication result, including fields such as:
conn.response
conn.reply
conn.s_params
conn.s_state.redir.*
When the login is rejected, conn.response is set correctly before the
challenge RPC is called. The RPC then overwrites conn with the state
returned by the main chilli daemon.
As a result, conn.response can become 0 and redir_reply() receives an
invalid response:
redir_reply(..., conn.response, ...);
This produces:
For example, with an invalid username/password I get:
LOGIN REJECT: conn.response=0 hex=0x0 url= reply=(null)
redir.c: 1544: Unknown res in switch
Without the challenge RPC patch, the same login rejection works correctly
and the client is returned to the login page.
I reproduced the issue with the 1.9 source as well as with the older
version I am using.
Suggested fix:
Read the RPC response into a temporary structure instead of overwriting
conn:
struct redir_conn_t outconn;
memset(&outconn, 0, sizeof(outconn));
if (safe_read(s, &outconn, sizeof(outconn)) != sizeof(outconn)) {
syslog(LOG_ERR, "%s: short read from %s",
strerror(errno), remote.sun_path);
safe_close(s);
return -1;
}
Then copy only the fields that the RPC is supposed to update:
memcpy(conn->s_state.redir.uamchal,
outconn.s_state.redir.uamchal,
REDIR_MD5LEN);
conn->s_state.uamtime = outconn.s_state.uamtime;
This preserves conn.response, conn.reply and the other state belonging
to the current REDIR_LOGIN request while still updating the UAM
challenge.
I tested this change on my system and invalid credentials correctly
return to the login page instead of producing "Unknown res in switch".
The issue appears to be present in the current implementation because
the same safe_read(s, conn, sizeof(*conn)) pattern is present in the
1.9 source.
Expected behavior
When Access-Reject is received, the client should receive the normal
login failure/challenge response and remain on the login page.
Actual behavior
After applying the UAM challenge RPC patch, conn.response is overwritten
by the RPC response and becomes 0. redir_reply() then reports:
I found a bug in the UAM challenge RPC implementation.
The issue is in src/redir.c, inside redir_ensure_challenge_rpc().
The current code reads the RPC response directly into the existing
redir_conn_t structure:
This overwrites the entire conn structure.
This is problematic during REDIR_LOGIN because conn also contains the
current authentication result, including fields such as:
When the login is rejected, conn.response is set correctly before the
challenge RPC is called. The RPC then overwrites conn with the state
returned by the main chilli daemon.
As a result, conn.response can become 0 and redir_reply() receives an
invalid response:
This produces:
For example, with an invalid username/password I get:
Without the challenge RPC patch, the same login rejection works correctly
and the client is returned to the login page.
I reproduced the issue with the 1.9 source as well as with the older
version I am using.
Suggested fix:
Read the RPC response into a temporary structure instead of overwriting
conn:
Then copy only the fields that the RPC is supposed to update:
This preserves conn.response, conn.reply and the other state belonging
to the current REDIR_LOGIN request while still updating the UAM
challenge.
I tested this change on my system and invalid credentials correctly
return to the login page instead of producing "Unknown res in switch".
The issue appears to be present in the current implementation because
the same safe_read(s, conn, sizeof(*conn)) pattern is present in the
1.9 source.
Expected behavior
When Access-Reject is received, the client should receive the normal
login failure/challenge response and remain on the login page.
Actual behavior
After applying the UAM challenge RPC patch, conn.response is overwritten
by the RPC response and becomes 0. redir_reply() then reports: