merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 721c98aad016cd1227ceab395c346793f44e9fee
parent 7137acc7578790f79d81d6f85c72a537e03d3abf
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 11 Aug 2026 13:51:36 +0200

fix #11107: return ECs that are more specific about what went wrong during transmission

Diffstat:
Msrc/backend/taler-merchant-httpd_post-challenge-ID.c | 91++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 86 insertions(+), 5 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_post-challenge-ID.c b/src/backend/taler-merchant-httpd_post-challenge-ID.c @@ -155,6 +155,19 @@ struct MfaState * Set to true if sending worked. */ bool send_ok; + + /** + * Exit status of the transmission helper, valid if it exited normally. + * Retained (and not just collapsed into @e send_ok) because the helpers + * classify *why* transmission failed; see classify_helper_status(). + */ + unsigned long int exit_code; + + /** + * True if the transmission helper exited normally, so that @e exit_code + * is meaningful. + */ + bool exited; }; @@ -278,6 +291,49 @@ respond_with_error (struct MfaState *mfa, /** + * Map the exit status of a challenge transmission helper onto an HTTP status + * and error code. + * + * The helpers shipped with Challenger use a banded exit-code scheme documented + * in challenger-send-sms(1): anything below 10 means the challenge was + * transmitted, 10-19 blames the address configured for this step, 20-29 is a + * recipient that is temporarily unreachable, 30-39 is the transmission + * provider and 40-49 is our own configuration. + * + * Codes we do not recognise are reported as an upstream failure rather than + * blamed on the client, so that a helper predating this scheme -- which used + * small ad-hoc exit codes -- never yields a client error. + * + * @param exit_code exit status of the helper, which must have exited normally + * @param[out] http_status set to the HTTP status to return + * @return error code to return + */ +static enum TALER_ErrorCode +classify_helper_status (unsigned long int exit_code, + unsigned int *http_status) +{ + if (exit_code < 20) + { + *http_status = MHD_HTTP_BAD_REQUEST; + return TALER_EC_MERCHANT_TAN_ADDRESS_UNUSABLE; + } + if (exit_code < 30) + { + *http_status = MHD_HTTP_SERVICE_UNAVAILABLE; + return TALER_EC_MERCHANT_TAN_ADDRESS_UNREACHABLE; + } + if ( (exit_code >= 40) && + (exit_code < 50) ) + { + *http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + return TALER_EC_MERCHANT_TAN_HELPER_MISCONFIGURED; + } + *http_status = MHD_HTTP_BAD_GATEWAY; + return TALER_EC_MERCHANT_TAN_MFA_HELPER_EXEC_FAILED; +} + + +/** * Challenge code transmission complete. Continue based on the result. * * @param[in,out] mfa process to send the challenge for @@ -289,10 +345,30 @@ phase_sent (struct MfaState *mfa) if (! mfa->send_ok) { + char es[32]; + unsigned int http_status; + enum TALER_ErrorCode ec; + + if (! mfa->exited) + { + /* Killed by a signal or otherwise abnormal: there is no exit code to + classify. */ + http_status = MHD_HTTP_BAD_GATEWAY; + ec = TALER_EC_MERCHANT_TAN_MFA_HELPER_EXEC_FAILED; + } + else + { + ec = classify_helper_status (mfa->exit_code, + &http_status); + } + GNUNET_snprintf (es, + sizeof (es), + "process exited with %u", + (unsigned int) mfa->exit_code); respond_with_error (mfa, - MHD_HTTP_BAD_GATEWAY, - TALER_EC_MERCHANT_TAN_MFA_HELPER_EXEC_FAILED, - "process exited with error"); + http_status, + ec, + es); return; } qs = TALER_MERCHANTDB_update_mfa_challenge (TMH_db, @@ -369,8 +445,13 @@ transmission_done_cb (void *cls, GNUNET_process_destroy (mfa->child); mfa->child = NULL; } - mfa->send_ok = ( (GNUNET_OS_PROCESS_EXITED == type) && - (0 == exit_code) ); + mfa->exited = (GNUNET_OS_PROCESS_EXITED == type); + mfa->exit_code = exit_code; + /* Exit codes below 10 all mean the challenge was transmitted: 0 confirmed + on the handset, 1 accepted by the provider, 2 suppressed as a duplicate + of a message already in flight. See challenger-send-sms(1). */ + mfa->send_ok = (mfa->exited && + (exit_code < 10) ); if (! mfa->send_ok) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MFA helper failed with status %d/%u\n",