commit 1570cb05a6577a4d453264168a60580942606400
parent 125dbecfcd035c21f0709b10205989e02d02f6a0
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 2 Apr 2026 22:54:13 +0200
fix #11213
Diffstat:
11 files changed, 93 insertions(+), 19 deletions(-)
diff --git a/bootstrap b/bootstrap
@@ -32,7 +32,7 @@ existence()
}
# Freeze SQL files that must no longer be edited.
-for n in 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 0030 0031 0032 0033
+for n in 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 0030 0031 0032 0033 0034
do
chmod -w src/backenddb/merchant-$n.sql*
done
diff --git a/src/backend/taler-merchant-httpd_mfa.c b/src/backend/taler-merchant-httpd_mfa.c
@@ -133,6 +133,7 @@ mfa_challenge_check (
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute confirmation_date;
enum GNUNET_GenericReturnValue ret;
+ char *instance_id = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Checking status of challenge %s\n",
@@ -156,7 +157,8 @@ mfa_challenge_check (
&confirmation_date,
&retransmission_date,
retry_counter,
- channel);
+ channel,
+ &instance_id);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -185,6 +187,7 @@ mfa_challenge_check (
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
+ GNUNET_free (instance_id);
if (xop != op)
{
@@ -276,6 +279,7 @@ mfa_challenge_start (
GNUNET_TIME_UNIT_ZERO_ABS,
channel,
required_address,
+ hc->instance->settings.id,
&challenge_serial);
GNUNET_free (code);
switch (qs)
diff --git a/src/backend/taler-merchant-httpd_post-challenge-ID.c b/src/backend/taler-merchant-httpd_post-challenge-ID.c
@@ -99,6 +99,11 @@ struct MfaState
char *msg;
/**
+ * Instance the challenge is for.
+ */
+ char *instance_id;
+
+ /**
* Offset of transmission in msg.
*/
size_t msg_off;
@@ -195,6 +200,7 @@ mfa_context_cleanup (void *cls)
}
GNUNET_free (mfa->required_address);
GNUNET_free (mfa->msg);
+ GNUNET_free (mfa->instance_id);
GNUNET_free (mfa->code);
GNUNET_free (mfa);
}
@@ -475,11 +481,11 @@ phase_send_challenge (struct MfaState *mfa)
"%s is your security code.\n"
"Do not share your code with anyone.\n\n"
"Authorizes: %s\n"
- // "Login: %s\n\n"
+ "Login: %s\n\n"
"Expires: %s (%s).\n",
mfa->code,
TALER_MERCHANT_MFA_co2s (mfa->op),
- // mfa->hc->instance->settings.id, // FIXME-#11213: this is wrong: always "admin"!
+ mfa->instance_id,
GNUNET_TIME_absolute2s (
mfa->expiration_date),
GNUNET_TIME_relative2s (
@@ -539,7 +545,8 @@ phase_lookup (struct MfaState *mfa)
&confirmation_date,
&retransmission_date,
&retry_counter,
- &mfa->channel);
+ &mfa->channel,
+ &mfa->instance_id);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
@@ -50,6 +50,7 @@ sql_DATA = \
merchant-0031.sql \
merchant-0032.sql \
merchant-0033.sql \
+ merchant-0034.sql \
drop.sql
BUILT_SOURCES = \
diff --git a/src/backenddb/merchant-0033.sql b/src/backenddb/merchant-0033.sql
@@ -13,7 +13,7 @@
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--- @file merchant-0032.sql
+-- @file merchant-0033.sql
-- @brief Add field for one-shot reports in the merchant_reports table
-- @author Christian Grothoff
diff --git a/src/backenddb/merchant-0034.sql b/src/backenddb/merchant-0034.sql
@@ -0,0 +1,40 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2026 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+-- @file merchant-0034.sql
+-- @brief Add field to allow identifying instance in TAN challenges
+-- @author Christian Grothoff
+
+BEGIN;
+
+-- Check patch versioning is in place.
+SELECT _v.register_patch('merchant-0034', NULL, NULL);
+
+SET search_path TO merchant;
+
+-- void active challenges during upgrade, to avoid them
+-- breaking the introduced invariant (harmless, as TAN
+-- challenges should be ephemeral anyway).
+DELETE FROM tan_challenges;
+
+ALTER TABLE tan_challenges
+ ADD COLUMN merchant_serial INT8 NOT NULL
+ REFERENCES merchant_instances(merchant_serial);
+
+COMMENT ON COLUMN tan_challenges.merchant_serial
+ IS 'Instance for which the challenge is being issued.';
+
+
+COMMIT;
diff --git a/src/backenddb/pg_create_mfa_challenge.c b/src/backenddb/pg_create_mfa_challenge.c
@@ -37,6 +37,7 @@ TMH_PG_create_mfa_challenge (
struct GNUNET_TIME_Absolute retransmission_date,
enum TALER_MERCHANT_MFA_Channel tan_channel,
const char *required_address,
+ const char *instance_id,
uint64_t *challenge_id)
{
struct PostgresClosure *pg = cls;
@@ -53,6 +54,7 @@ TMH_PG_create_mfa_challenge (
GNUNET_PQ_query_param_absolute_time (&retransmission_date),
GNUNET_PQ_query_param_string (channel_str),
GNUNET_PQ_query_param_string (required_address), /* $9 */
+ GNUNET_PQ_query_param_string (instance_id),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -74,8 +76,10 @@ TMH_PG_create_mfa_challenge (
" ,retry_counter" /* always set to 3 */
" ,tan_channel"
" ,required_address)"
- " VALUES"
- " ($1, $2, $3, $4, $5, $6, $7, 3, $8, $9)"
+ " SELECT"
+ " $1, $2, $3, $4, $5, $6, $7, 3, $8, $9, merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$10"
" RETURNING challenge_id;");
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"create_mfa_challenge",
diff --git a/src/backenddb/pg_create_mfa_challenge.h b/src/backenddb/pg_create_mfa_challenge.h
@@ -40,6 +40,8 @@
* @param tan_channel which channel was used
* @param required_address address
* where the challenge is to be sent
+ * @param instance_id name of the instance for which the challenge
+ * is being created
* @param[out] challenge_id set to the ID of the new challenge
* @return database result code
*/
@@ -54,6 +56,7 @@ TMH_PG_create_mfa_challenge (
struct GNUNET_TIME_Absolute retransmission_date,
enum TALER_MERCHANT_MFA_Channel tan_channel,
const char *required_address,
+ const char *instance_id,
uint64_t *challenge_id);
#endif
diff --git a/src/backenddb/pg_lookup_mfa_challenge.c b/src/backenddb/pg_lookup_mfa_challenge.c
@@ -37,7 +37,8 @@ TMH_PG_lookup_mfa_challenge (
struct GNUNET_TIME_Absolute *confirmation_date,
struct GNUNET_TIME_Absolute *retransmission_date,
uint32_t *retry_counter,
- enum TALER_MERCHANT_MFA_Channel *tan_channel)
+ enum TALER_MERCHANT_MFA_Channel *tan_channel,
+ char **instance_name)
{
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
@@ -67,6 +68,8 @@ TMH_PG_lookup_mfa_challenge (
&chan_str),
GNUNET_PQ_result_spec_string ("required_address",
required_address),
+ GNUNET_PQ_result_spec_string ("merchant_id",
+ instance_name),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
@@ -74,14 +77,17 @@ TMH_PG_lookup_mfa_challenge (
PREPARE (pg,
"lookup_mfa_challenge",
"SELECT "
- " op::TEXT"
- " ,salt"
- " ,confirmation_date"
- " ,retransmission_date"
- " ,retry_counter"
- " ,required_address"
- " ,tan_channel::TEXT"
- " FROM tan_challenges"
+ " tc.op::TEXT"
+ " ,tc.salt"
+ " ,tc.confirmation_date"
+ " ,tc.retransmission_date"
+ " ,tc.retry_counter"
+ " ,tc.required_address"
+ " ,tc.tan_channel::TEXT"
+ " ,mi.merchant_id"
+ " FROM tan_challenges.tc"
+ " JOIN merchant_instances.mi"
+ " USING (merchant_serial)"
" WHERE (challenge_id = $1)"
" AND (h_body = $2)"
" AND (expiration_date > $3)");
diff --git a/src/backenddb/pg_lookup_mfa_challenge.h b/src/backenddb/pg_lookup_mfa_challenge.h
@@ -43,6 +43,8 @@
* @param[out] retry_counter set to the number of attempts that remain
* for solving the challenge (after this time)
* @param[out] tan_channel which channel was used
+ * @param[out] instance_name name of the instance for which the
+ * challenge is being issued
* @return database result code
*/
enum GNUNET_DB_QueryStatus
@@ -56,7 +58,8 @@ TMH_PG_lookup_mfa_challenge (
struct GNUNET_TIME_Absolute *confirmation_date,
struct GNUNET_TIME_Absolute *retransmission_date,
uint32_t *retry_counter,
- enum TALER_MERCHANT_MFA_Channel *tan_channel);
+ enum TALER_MERCHANT_MFA_Channel *tan_channel,
+ char **instance_name);
#endif
diff --git a/src/include/taler/taler_merchantdb_plugin.h b/src/include/taler/taler_merchantdb_plugin.h
@@ -5114,6 +5114,8 @@ struct TALER_MERCHANTDB_Plugin
* @param[out] retry_counter set to the number of attempts that remain
* for solving the challenge (after this time)
* @param[out] tan_channel which channel was used
+ * @param[out] instance_name name of the instance for which the
+ * challenge is being issued
* @return database result code
*/
enum GNUNET_DB_QueryStatus
@@ -5127,7 +5129,8 @@ struct TALER_MERCHANTDB_Plugin
struct GNUNET_TIME_Absolute *confirmation_date,
struct GNUNET_TIME_Absolute *retransmission_date,
uint32_t *retry_counter,
- enum TALER_MERCHANT_MFA_Channel *tan_channel);
+ enum TALER_MERCHANT_MFA_Channel *tan_channel,
+ char **instance_name);
/**
@@ -5194,6 +5197,8 @@ struct TALER_MERCHANTDB_Plugin
* @param tan_channel which channel was used
* @param required_address address
* where the challenge is to be sent
+ * @param instance_id name of the instance for which the challenge
+ * is being created
* @param[out] challenge_id set to the ID of the new challenge
* @return database result code
*/
@@ -5208,6 +5213,7 @@ struct TALER_MERCHANTDB_Plugin
struct GNUNET_TIME_Absolute retransmission_date,
enum TALER_MERCHANT_MFA_Channel tan_channel,
const char *required_address,
+ const char *instance_id,
uint64_t *challenge_id);