vsh: Fix 'stdin' closing in 'cmdComplete'

While the 'complete' command is meant to be hidden and used only for
the completion script, there's nothing preventing it being used in all
virsh modes.

This poses a problem as the command tries to close 'stdin' to avoid the
possibility that an auth callback would want to read the password.

In interactive mode this immediately terminates virsh and in
non-interactive mode it attempts to close it multiple times if you use
virsh in batch mode.

Fix the issues by using virOnce() to close it exactly once and do so
only in non-interactive mode.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Peter Krempa 2024-03-26 16:28:33 +01:00
parent 0d687d13ed
commit bb9bb55211

View File

@ -3405,11 +3405,25 @@ const vshCmdInfo info_complete = {
#ifdef WITH_READLINE #ifdef WITH_READLINE
static virOnceControl vshCmdCompleteCloseStdinOnce = VIR_ONCE_CONTROL_INITIALIZER;
static void
vshCmdCompleteCloseStdin(void)
{
/* In non-interactive mode which is how the 'complete' command is intended
* to be used we need to ensure that any authentication callback will not
* attempt to read any input which would break the completion */
int stdin_fileno = STDIN_FILENO;
VIR_FORCE_CLOSE(stdin_fileno);
}
bool bool
cmdComplete(vshControl *ctl, const vshCmd *cmd) cmdComplete(vshControl *ctl, const vshCmd *cmd)
{ {
const vshClientHooks *hooks = ctl->hooks; const vshClientHooks *hooks = ctl->hooks;
int stdin_fileno = STDIN_FILENO;
const char *arg = ""; const char *arg = "";
const vshCmdOpt *opt = NULL; const vshCmdOpt *opt = NULL;
g_auto(GStrv) matches = NULL; g_auto(GStrv) matches = NULL;
@ -3422,7 +3436,10 @@ cmdComplete(vshControl *ctl, const vshCmd *cmd)
/* This command is flagged VSH_CMD_FLAG_NOCONNECT because we /* This command is flagged VSH_CMD_FLAG_NOCONNECT because we
* need to prevent auth hooks reading any input. Therefore, we * need to prevent auth hooks reading any input. Therefore, we
* have to close stdin and then connect ourselves. */ * have to close stdin and then connect ourselves. */
VIR_FORCE_CLOSE(stdin_fileno); if (!ctl->imode) {
if (virOnce(&vshCmdCompleteCloseStdinOnce, vshCmdCompleteCloseStdin) < 0)
return false;
}
if (!(hooks && hooks->connHandler && hooks->connHandler(ctl))) if (!(hooks && hooks->connHandler && hooks->connHandler(ctl)))
return false; return false;