Score:1

Windows OpenSSH Match Exec string with embedded quotes

in flag

Under Openssh for Windows, is there a way to specify an exec string for powershell with embedded quotes? It's made complex by the fact that a multiword command must be quoted, and I can't figure out a way to escape the embedded quotes. I've tried the following arguments to Match ... Exec:

# This gives error ${CMDVAR} is not recognized
"powershell -command ${CMDVAR}"

# This executes the script but hangs at script exit
"powershell myscript.ps1"

# This simply hangs
"powershell -command 'my long script with ^"embedded^" quotes"  

The goal here is to exec this nested powershell one-liner:

if ((wmic process where "ProcessID = $((Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId)" get commandline /value| measure-object -Word).Words -gt 2) { exit 1 }

Score:1
fr flag

I think this is not possible without an external script file.

The first thing to realize is that in OpenSSH, the command specified for Match Exec needs to be enclosed in double quotes (in the config file), since the argument to Exec is matched using strdelim:

readconf.c::match_cfg_line

        /* All other criteria require an argument */
        if ((arg = strdelim(&cp)) == NULL ||
            *arg == '\0' || *arg == '#') {
            error("Missing Match criteria for %s", attrib);
            result = -1;
            goto out;
        }

and strdelim only accepts double quotes as delimiters:

misc.c::strdelim_internal

#define QUOTE   "\""

/* return next token in configuration line */
static char *
strdelim_internal(char **s, int split_equals)
{
    char *old;
    int wspace = 0;

    if (*s == NULL)
        return NULL;

    old = *s;

    *s = strpbrk(*s,
        split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE);
    if (*s == NULL)
        return (old);

    if (*s[0] == '\"') {
        memmove(*s, *s + 1, strlen(*s)); /* move nul too */
        /* Find matching quote */
        if ((*s = strpbrk(*s, QUOTE)) == NULL) {
            return (NULL);      /* no matching quote */
        } else {
            *s[0] = '\0';
            *s += strspn(*s + 1, WHITESPACE) + 1;
            return (old);
        }
    }
// ...

So, only double quotes can be used to delimit the command.

Then, the second thing to realize is that in OpenSSH for Windows, the command used in the Exec directive is executed using system:

readconf.c::execute_in_shell

/*
 * Execute a command in a shell.
 * Return its exit status or -1 on abnormal exit.
 */
static int
execute_in_shell(const char *cmd)
{
    char *shell;
    pid_t pid;
    int status;

#ifdef WINDOWS
    return system(cmd);
#else

and thus it is executed in cmd.exe (see https://learn.microsoft.com/en-us/cpp/c-language/system-function?view=msvc-170). In cmd.exe, you need to use double quotes to enclose arguments, single quotes have no special meaning.

The problem is that there is no way in OpenSSH to escape the inner double quotes.


To go back to your examples:

# This gives error ${CMDVAR} is not recognized
"powershell -command ${CMDVAR}"

Here it's unclear what is in CMDVAR, and as mentioned above you would need escaped double quotes around ${CMDVAR}, which is not possible currently with OpenSSH.

# This executes the script but hangs at script exit
"powershell myscript.ps1"

Maybe this could work with "powershell -File myscript.ps1" ?

# This simply hangs
"powershell -command 'my long script with ^"embedded^" quotes"  

A mentioned, cmd.exe needs double quotes so the arguments to -command would need to be enclosed in escaped double quotes, which is not currently possible with OpenSSH.

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.