commit c27d8132dac61656b399b0882e4f0a2b8b2cccfc
parent 4308863d8255d66cc635de39d1d6828fddbe794f
Author: Christian Grothoff <christian@grothoff.org>
Date: Tue, 11 Aug 2026 14:02:52 +0200
fix #11107
Diffstat:
2 files changed, 72 insertions(+), 5 deletions(-)
diff --git a/src/challenger/cat-once.sh b/src/challenger/cat-once.sh
@@ -4,10 +4,15 @@
# Like cat.sh, but only for the first challenge: every later invocation
# fails without delivering anything, simulating an SMS/e-mail gateway
# that went down between two TAN transmissions.
+#
+# Exit 30 ("provider outage or internal error", see challenger-send-sms(1))
+# is what a real helper reports for that. Note that exit 1 would NOT work:
+# under the helper exit-code scheme anything below 10 means the TAN was
+# transmitted, and 1 specifically means "accepted, delivery not confirmed".
TARGET="$(echo $1 | jq -r ".filename")"
if [ -e "${TARGET}.sent" ]
then
- exit 1
+ exit 30
fi
touch "${TARGET}.sent"
cat - > "${TARGET}"
diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c
@@ -305,6 +305,55 @@ reply_error (struct ChallengeContext *bc,
/**
+ * Map the exit status of a TAN transmission helper onto an HTTP status and
+ * error code.
+ *
+ * The helpers use a banded exit-code scheme documented in
+ * challenger-send-sms(1): anything below 10 means the TAN was transmitted (0
+ * confirmed on the handset, 1 accepted by the provider, 2 suppressed as a
+ * duplicate of a message already in flight), 10-19 blames the address the user
+ * gave us, 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 user, so that a helper predating this scheme -- which used
+ * small ad-hoc exit codes -- never yields a 400.
+ *
+ * @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, #TALER_EC_NONE if the TAN was transmitted
+ */
+static enum TALER_ErrorCode
+classify_helper_status (unsigned long int exit_code,
+ unsigned int *http_status)
+{
+ if (exit_code < 10)
+ {
+ *http_status = MHD_HTTP_OK;
+ return TALER_EC_NONE;
+ }
+ if (exit_code < 20)
+ {
+ *http_status = MHD_HTTP_BAD_REQUEST;
+ return TALER_EC_CHALLENGER_ADDRESS_UNUSABLE;
+ }
+ if (exit_code < 30)
+ {
+ *http_status = MHD_HTTP_SERVICE_UNAVAILABLE;
+ return TALER_EC_CHALLENGER_ADDRESS_UNREACHABLE;
+ }
+ if ( (exit_code >= 40) &&
+ (exit_code < 50) )
+ {
+ *http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ return TALER_EC_CHALLENGER_HELPER_MISCONFIGURED;
+ }
+ *http_status = MHD_HTTP_BAD_GATEWAY;
+ return TALER_EC_CHALLENGER_HELPER_EXEC_FAILED;
+}
+
+
+/**
* Function called when our TAN transmission helper has terminated.
*
* @param cls our `struct ChallengeContext *`
@@ -834,11 +883,24 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
if ( (GNUNET_OS_PROCESS_UNKNOWN != bc->pst) &&
(NULL == bc->child) &&
( (GNUNET_OS_PROCESS_EXITED != bc->pst) ||
- (0 != bc->exit_code) ) )
+ (bc->exit_code >= 10) ) )
{
char es[32];
+ unsigned int http_status;
+ enum TALER_ErrorCode ec;
- GNUNET_break (0);
+ if (GNUNET_OS_PROCESS_EXITED != bc->pst)
+ {
+ /* Killed by a signal or otherwise abnormal: there is no exit code to
+ classify. */
+ http_status = MHD_HTTP_BAD_GATEWAY;
+ ec = TALER_EC_CHALLENGER_HELPER_EXEC_FAILED;
+ }
+ else
+ {
+ ec = classify_helper_status (bc->exit_code,
+ &http_status);
+ }
GNUNET_snprintf (es,
sizeof (es),
"%u/%d",
@@ -850,8 +912,8 @@ CH_handler_challenge (struct CH_HandlerContext *hc,
(int) bc->exit_code);
return TALER_MHD_reply_with_error (
hc->connection,
- MHD_HTTP_BAD_GATEWAY,
- TALER_EC_CHALLENGER_HELPER_EXEC_FAILED,
+ http_status,
+ ec,
es);
}
/* handle upload */