commit 819981a623029949ba904a1025fb4a473f610c2f
parent a62f5547684814d9bfad5a3ad94e810626a94570
Author: Florian Dold <florian@dold.me>
Date: Fri, 8 May 2026 15:17:27 +0200
allow arguments in 2FA helper binaries
Diffstat:
1 file changed, 74 insertions(+), 11 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_post-challenge-ID.c b/src/backend/taler-merchant-httpd_post-challenge-ID.c
@@ -378,6 +378,55 @@ transmission_done_cb (void *cls,
/**
+ * Resolve a binary name via PATH.
+ *
+ * Needed because the GNUnet process helpers to not support
+ * an execp equivalent at present.
+ *
+ * @param binary_name name to search for
+ * @returns resolved path or NULL if not found
+ */
+static char *
+resolve_path (const char *binary_name)
+{
+ char *path_env;
+ char full_path[2048];
+ char *dir;
+ char *path_copy;
+
+ if (NULL != strchr (binary_name,
+ '/'))
+ {
+ /* Already a full path, do not search. */
+ return GNUNET_strdup (binary_name);
+ }
+ path_env = getenv ("PATH");
+ if (path_env == NULL)
+ return NULL;
+ /* Duplicate PATH because strtok modifies the string it parses */
+ path_copy = GNUNET_strdup (path_env);
+ dir = strtok (path_copy, ":");
+ while (dir != NULL)
+ {
+ snprintf (full_path,
+ sizeof(full_path),
+ "%s/%s",
+ dir,
+ binary_name);
+ if (0 == access (full_path,
+ X_OK))
+ {
+ GNUNET_free (path_copy);
+ return GNUNET_strdup (full_path);
+ }
+ dir = strtok (NULL, ":");
+ }
+ GNUNET_free (path_copy);
+ return NULL;
+}
+
+
+/**
* Setup challenge code for @a mfa and send it to the
* @a required_address; on success.
*
@@ -387,7 +436,9 @@ static void
phase_send_challenge (struct MfaState *mfa)
{
const char *prog = NULL;
+ char *binary_path = NULL;
unsigned long long challenge_num;
+ char **cmd_argv = NULL;
challenge_num = (unsigned long long)
GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE,
@@ -424,7 +475,7 @@ phase_send_challenge (struct MfaState *mfa)
MHD_HTTP_NOT_IMPLEMENTED,
TALER_EC_GENERIC_FEATURE_NOT_IMPLEMENTED,
"#10327");
- return;
+ goto done;
}
if (NULL == prog)
{
@@ -433,12 +484,21 @@ phase_send_challenge (struct MfaState *mfa)
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
TALER_MERCHANT_MFA_channel_to_string (mfa->channel));
- return;
+ goto done;
}
{
/* Start child process and feed pipe */
struct GNUNET_DISK_PipeHandle *p;
struct GNUNET_DISK_FileHandle *pipe_stdin;
+ const char *extra_args[] = {
+ mfa->required_address,
+ NULL,
+ };
+
+ cmd_argv = TALER_words_split (prog,
+ extra_args);
+
+ GNUNET_assert (NULL != cmd_argv[0]);
p = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
if (NULL == p)
@@ -447,7 +507,7 @@ phase_send_challenge (struct MfaState *mfa)
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_ALLOCATION_FAILURE,
"pipe");
- return;
+ goto done;
}
mfa->child = GNUNET_process_create (GNUNET_OS_INHERIT_STD_ERR);
GNUNET_assert (GNUNET_OK ==
@@ -455,12 +515,12 @@ phase_send_challenge (struct MfaState *mfa)
mfa->child,
GNUNET_process_option_inherit_rpipe (p,
STDIN_FILENO)));
- if (GNUNET_OK !=
- GNUNET_process_run_command_va (mfa->child,
- prog,
- prog,
- mfa->required_address,
- NULL))
+ binary_path = resolve_path (cmd_argv[0]);
+ if ( (NULL == binary_path) ||
+ (GNUNET_OK !=
+ GNUNET_process_run_command_argv (mfa->child,
+ binary_path,
+ (const char **) cmd_argv)) )
{
GNUNET_process_destroy (mfa->child);
mfa->child = NULL;
@@ -470,7 +530,7 @@ phase_send_challenge (struct MfaState *mfa)
MHD_HTTP_BAD_GATEWAY,
TALER_EC_MERCHANT_TAN_MFA_HELPER_EXEC_FAILED,
"exec");
- return;
+ goto done;
}
pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
@@ -510,7 +570,7 @@ phase_send_challenge (struct MfaState *mfa)
MHD_HTTP_BAD_GATEWAY,
TALER_EC_MERCHANT_TAN_MFA_HELPER_EXEC_FAILED,
"write");
- return;
+ goto done;
}
mfa->msg_off += ret;
off += ret;
@@ -520,6 +580,9 @@ phase_send_challenge (struct MfaState *mfa)
}
}
mfa->phase = MFA_PHASE_SUSPENDING;
+done:
+ GNUNET_free (binary_path);
+ TALER_words_destroy (cmd_argv);
}