Skip to content

Refactor backend return code#8862

Open
justin-stephenson wants to merge 8 commits into
SSSD:masterfrom
justin-stephenson:refactor_backend_return_code_master_2
Open

Refactor backend return code#8862
justin-stephenson wants to merge 8 commits into
SSSD:masterfrom
justin-stephenson:refactor_backend_return_code_master_2

Conversation

@justin-stephenson

@justin-stephenson justin-stephenson commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary of changes (written by me, not AI):

  • Return only a single error code through sssd.dataprovider interfaces

  • Remove sdap_ret/sdap_err from codebase

    • Handle lost/broken ENOENT after removing sdap_ret with commit sdap: Add output variable to store sdap result of ENOENT
    Object lookup sdap `_done()` functions call tevent_req_done() for EOK and ENOENT,
    removal of 'sdap_ret/sdap_err' causes us to lose ENOENT which breaks ENOENT
    checks done by some callers.
    
    Previously actual sdap return code(sdap_ret) was stored. Callers still receive
    tevent error code from tevent_req_error(), but callers need some way to check
    if the sdap lookup function results in ENOENT.
  • sdap_id_op_{connect}_done returns ERR_OFFLINE when offline instead of EAGAIN

  • sdap_id_op_done() now returns ERR_SERVER_FAILURE when previously setting DP_ERR_FATAL

  • sdap_id_op_done() returns EAGAIN when advising retry and dp_error is no longer, callers performing retry logic with this code:

    ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
    if (dp_error == DP_ERR_OK && ret != EOK) {

are converted to

    ret = sdap_id_op_done(state->sdap_op, ret);
    if (ret == EAGAIN) 
       /* retry */
    ...
  • LDAP connection failure error codes are converted from EIO/ERR_NETWORK_IO/ETIMEDOUT to ERR_SERVER_FAILURE. Callers checking for ERR_NETWORK_IO/ETIMEDOUT now check for ERR_SERVER_FAILURE

  • Switch checks of if (dp_error == DP_ERR_OFFLINE) to if (ret == ERR_OFFLINE)

@justin-stephenson justin-stephenson added the no-backport This should go to target branch only. label Jun 30, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors and simplifies error handling across SSSD providers and responders by removing the redundant dp_error (Data Provider error) parameter and unifying error reporting under standard SSSD error codes. However, this refactoring introduces a critical bug: by discarding the sdap_ret status (which contains ENOENT when a user or group is not found), lookup operations incorrectly return EOK instead of ENOENT. This breaks critical AD failover and fallback mechanisms, as the system can no longer detect missing entries to trigger alternative connection attempts.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/providers/ldap/ldap_id.c
Comment thread src/providers/ad/ad_id.c Outdated
@justin-stephenson
justin-stephenson force-pushed the refactor_backend_return_code_master_2 branch 9 times, most recently from b171fc9 to 830cebb Compare July 1, 2026 18:38
@justin-stephenson
justin-stephenson marked this pull request as ready for review July 2, 2026 14:01
@justin-stephenson justin-stephenson changed the title Refactor backend return code master Refactor backend return code Jul 2, 2026
@justin-stephenson
justin-stephenson force-pushed the refactor_backend_return_code_master_2 branch 2 times, most recently from 698bdc1 to 0a4d279 Compare July 7, 2026 14:15
Assisted by: Claude code (Sonnet 4.5)
Replace LDAP connection related failure error codes
EIO/ERR_NETWORK_IO/ETIMEDOUT with ERR_SERVER_FAILURE
Replace LDAP connection related failure error codes
EIO/ERR_NETWORK_IO/ETIMEDOUT with ERR_SERVER_FAILURE
Replace LDAP connection related failure error codes
EIO/ERR_NETWORK_IO/ETIMEDOUT with ERR_SERVER_FAILURE
The data provider handler methods now return a single output
argument. Remove 'dp_error/dp_err' and 'error_message' usage
across provider code.

The getAccountDomain method still needs to return 'domain_name' string.

Assisted by: Claude code (Sonnet 4.5)
@justin-stephenson
justin-stephenson force-pushed the refactor_backend_return_code_master_2 branch from 0a4d279 to a122699 Compare July 13, 2026 18:11
Object lookup sdap `_done()` functions call tevent_req_done() for EOK and ENOENT,
removal of 'sdap_ret/sdap_err' causes us to lose ENOENT which breaks ENOENT
checks done by some callers.

Previously actual sdap return code(sdap_ret) was stored. Callers still receive
tevent error code from tevent_req_error(), but callers need some way to check
if the sdap lookup function results in ENOENT.
@justin-stephenson
justin-stephenson force-pushed the refactor_backend_return_code_master_2 branch from a122699 to 56c8d38 Compare July 13, 2026 18:43
@pbrezina

Copy link
Copy Markdown
Member
  • Handle lost/broken ENOENT after removing sdap_ret with commit sdap: Add output variable to store sdap result of ENOENT

Uhm, this looks weird and breaks the purpose of having one return code. Why don't you call tevent_req_error(req, ENOENT)? This looks like the cleanest thing to do.

@justin-stephenson

Copy link
Copy Markdown
Contributor Author
  • Handle lost/broken ENOENT after removing sdap_ret with commit sdap: Add output variable to store sdap result of ENOENT

Uhm, this looks weird and breaks the purpose of having one return code. Why don't you call tevent_req_error(req, ENOENT)? This looks like the cleanest thing to do.

Hi Pavel, thanks for taking a look at this PR.

I tried going with the approach you mention here first, but I found it to be much more invasive and require a lot more changes in the provider to adapt to this behavior change. In my testing I see much of the provider code was not written with ENOENT as tevent error in mind, and calling functions expect to see 'tevent_req_done' when the connection is successful and the ldap search does not find the object.

Of course I am okay going with your approach, in general I was attempting to lower the amount of invasive changes if possible., however this PR will be invasive in the end regardless.

@pbrezina

Copy link
Copy Markdown
Member

I think we should go for it and adapt the code to correctly handle ENOENT and one return code. But we can continue with this pull request as is so we move forward and then implement this refactoring on top of it. I will continue with review tomorrow.

@pbrezina pbrezina self-assigned this Jul 15, 2026
Comment on lines +1768 to 1782
bool sdap_enoent = false;
struct sdap_id_conn_ctx *user_conn;

ret = groups_get_recv(subreq, &state->dp_error, &state->sdap_ret);
ret = groups_get_recv(subreq, &sdap_enoent);
talloc_zfree(subreq);

if (ret != EOK) { /* Fatal error while looking up group */
tevent_req_error(req, ret);
return;
}
state->sdap_enoent = sdap_enoent;

if (state->sdap_ret == EOK) { /* Matching group found */
if (ret == EOK) { /* Matching group found */
tevent_req_done(req);
return;
} else if (state->sdap_ret != ENOENT) {
tevent_req_error(req, EIO);
} else if (ret != EOK && !sdap_enoent) { /* Fatal error while looking up group */
tevent_req_error(req, ret);
return;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nicely demonstrates how multiple return codes are bad design practice.

The current code can return EOK and sdap_enoent = true from groups_get_recv, the code behind the if statement that handles ENOENT will not execute.

Comment on lines 981 to 991
switch (retval) {
case EIO:
case ETIMEDOUT:
/* this currently the only possible communication error after connection is established */
communication_error = true;
break;

default:
communication_error = false;
break;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIO and ETIMEDOUT were removed and we should not get them anymore. But ERR_SERVER_FAILURE must be handled here.

state->conn = conn;
state->dp_error = DP_ERR_FATAL;
state->noexist_delete = noexist_delete;
state->sdap_enoent = true;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be set to false, as you later set it to true on ENOENT.

"Trying LDAP search while not connected.\n");
ret = ERR_NETWORK_IO;
ret = ERR_SERVER_FAILURE;
goto fail;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERR_SERVER_FAILURE is switched for ERR_AUTH_FAILED in "fail".

DEBUG(SSSDBG_CRIT_FAILURE,
"Trying LDAP rebind while not connected.\n");
return ERR_NETWORK_IO;
return ERR_SERVER_FAILURE;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ldap callback, expecting ldap return codes. We should return LDAP_SERVER_DOWN or perhaps LDAP_LOCAL_ERROR.

Comment on lines 108 to 111
<method name="sudoHandler">
<annotation name="codegen.CustomInputHandler" value="true" />
<arg name="dp_error" type="q" direction="out" />
<arg name="error" type="u" direction="out" />
<arg name="error_message" type="s" direction="out" />
</method>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still returns two error codes: dbus and operation. Let's just return the dbus one.

Instead of finishing with a valid reply (dbus returns success, sends reply that contains the error code), just fail with dbus error (dbus returns error).

msg = reply->message;
}

void dp_req_reply_std_with_msg(const char *request_name,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need the message in the dbus reply, we want to carry all information in the return code. Potential message can be logged in the provider.

* Data provider error code is returned:
* ERR_OK - connection established
* ERR_OFFLINE - backend is offline, operation result is set EAGAIN
* ERR_FATAL - operation failed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERR_SERVER_FAILURE?

* DP_ERR_FATAL - operation failed
* In data provider error code is returned:
* ERR_OK - connection established
* ERR_OFFLINE - backend is offline, operation result is set EAGAIN

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not EAGAIN anymore

Comment thread src/providers/ad/ad_pac.c
@@ -230,7 +230,6 @@ struct ad_handle_pac_initgr_state {
struct dp_id_data *ar;
const char *err;
int dp_error;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

@pbrezina

Copy link
Copy Markdown
Member

There is /* FIXME: do we need some special handling of ENOENT */inipa_get_subdom_acct_done`. It might be good to think about it and either fix or remote the comment when we are touching this part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-backport This should go to target branch only. Waiting for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants