Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wondering about piping stdin to program under winpty control #93

Open
kozmikyak opened this issue Sep 13, 2016 · 12 comments
Open

Wondering about piping stdin to program under winpty control #93

kozmikyak opened this issue Sep 13, 2016 · 12 comments

Comments

@kozmikyak
Copy link

I'm experimenting with running Windows console software under both winpty and proxywinconsole.

Of interest is whether I can pipe input into a powershell script running under winpty.

Example:

echo "$PASSWORD" | winpty -Xallow-non-pty powershell.exe "C:\script.ps1"

where script.ps1 reads the password on standard input.

Reason is that it's not safe to send passwords into the powershell script through command line parameters, as they can be inspected. Was hoping to have the script read from stdin.

As of right now, trying to redirect standard input into a program under winpty control seems to exit immediately. proxywincosnole seems capable of doing this, except that it echoes the input, making the password show up on the screen, which is undesirable.

Understanding that it's not supported, what challenges would exist in attempting to implement this?

@rprichard
Copy link
Owner

Maybe winpty is hitting EOF on stdin and immediately shutting down? Maybe it'd need to keep running instead.

It might be as simple as removing the inputHandler.isComplete() check from

if (inputHandler.isComplete() || outputHandler.isComplete() ||
:

        // Check for an I/O handler shutting down (possibly indicating that the
        // child process has exited).
        if (inputHandler.isComplete() || outputHandler.isComplete() ||
                (errorHandler != NULL && errorHandler->isComplete())) {
            break;
        }

@mattn
Copy link

mattn commented Sep 4, 2017

Any update on this?

:terminal command on Vim use winpty. And currently we have issue about echo-back. :terminal command can write standard input to the command like below.

:'<,'>terminal wc

But winpty doesn't support writing stanadard input for the command. So CUI app show echo-back. Do you have plan to use input from pipe?

https://github.com/rprichard/winpty/blob/master/src/agent/Agent.cc#L376-L382

@k-takata
Copy link

k-takata commented Sep 4, 2017

Other use cases:

  1. peco doesn't work via winpty.
    E.g.: Running ls | winpty peco on mintty doesn't work.
  2. Vim can open stdin by specifying "-" as a filename.
    E.g.: Running dir /b | vim.exe - on Command Prompt can edit a filelist of the current directory.
    However, running ls | winpty vim.exe - on mintty doesn't work.
    (Assuming this vim.exe is Win32 version, not Cygwin or MSYS2 version. Of course, if Cygwin/MSYS2 version of vim is used, ls | vim - should work. This is just an example.)

I think there are more other use cases for piping stdin.

@mattn
Copy link

mattn commented Sep 4, 2017

@rprichard How about this?

diff --git a/src/agent/Agent.cc b/src/agent/Agent.cc
index efc3e7f..b0ebca6 100644
--- a/src/agent/Agent.cc
+++ b/src/agent/Agent.cc
@@ -149,7 +149,8 @@ Agent::Agent(LPCWSTR controlPipeName,
              int initialRows) :
     m_useConerr((agentFlags & WINPTY_FLAG_CONERR) != 0),
     m_plainMode((agentFlags & WINPTY_FLAG_PLAIN_OUTPUT) != 0),
-    m_mouseMode(mouseMode)
+    m_mouseMode(mouseMode),
+    m_useStdin((agentFlags & WINPTY_FLAG_STDIN) != 0)
 {
     trace("Agent::Agent entered");
 
@@ -380,6 +381,21 @@ void Agent::handleStartProcessPacket(ReadBuffer &packet)
         sui.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
         sui.hStdError = m_errorBuffer->conout();
     }
+    HANDLE readtmp, readpipe;
+    if (m_useStdin && CreatePipe(&readtmp, &m_stdin, NULL, 0)) {
+        if (DuplicateHandle(
+            GetCurrentProcess(), readtmp,
+            GetCurrentProcess(), &readpipe,
+            0, TRUE, DUPLICATE_SAME_ACCESS)
+        ) {
+            inheritHandles = TRUE;
+            sui.dwFlags |= STARTF_USESTDHANDLES;
+            sui.hStdInput = readpipe;
+            sui.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+            sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+        }
+        CloseHandle(readtmp);
+    }
 
     const BOOL success =
         CreateProcessW(programArg, cmdlineArg, nullptr, nullptr,
@@ -429,7 +445,15 @@ void Agent::handleSetSizePacket(ReadBuffer &packet)
 void Agent::pollConinPipe()
 {
     const std::string newData = m_coninPipe->readAllToString();
-    if (hasDebugFlag("input_separated_bytes")) {
+    if (m_stdin != nullptr) {
+        if (newData.size() > 0) {
+            DWORD written = 0;
+            WriteFile(m_stdin, newData.data(), newData.size(), &written, NULL);
+        }
+        if (m_coninPipe->isClosed()) {
+            CloseHandle(m_stdin);
+        }
+    } else if (hasDebugFlag("input_separated_bytes")) {
         // This debug flag is intended to help with testing incomplete escape
         // sequences and multibyte UTF-8 encodings.  (I wonder if the normal
         // code path ought to advance a state machine one byte at a time.)
diff --git a/src/agent/Agent.h b/src/agent/Agent.h
index 5775e08..26940cc 100644
--- a/src/agent/Agent.h
+++ b/src/agent/Agent.h
@@ -76,6 +76,8 @@ private:
     const bool m_useConerr;
     const bool m_plainMode;
     const int m_mouseMode;
+    const bool m_useStdin;
+    HANDLE m_stdin = nullptr;
     Win32Console m_console;
     std::unique_ptr<Scraper> m_primaryScraper;
     std::unique_ptr<Scraper> m_errorScraper;
diff --git a/src/include/winpty_constants.h b/src/include/winpty_constants.h
index 11e34cf..316b3ed 100755
--- a/src/include/winpty_constants.h
+++ b/src/include/winpty_constants.h
@@ -76,11 +76,14 @@
  * See https://github.com/rprichard/winpty/issues/58. */
 #define WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION 0x8ull
 
+#define WINPTY_FLAG_STDIN              0x10ull
+
 #define WINPTY_FLAG_MASK (0ull \
     | WINPTY_FLAG_CONERR \
     | WINPTY_FLAG_PLAIN_OUTPUT \
     | WINPTY_FLAG_COLOR_ESCAPES \
     | WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION \
+    | WINPTY_FLAG_STDIN \
 )
 
 /* QuickEdit mode is initially disabled, and the agent does not send mouse

Maybe, this is better to have winpty_close_stdin().

@mattn
Copy link

mattn commented Sep 4, 2017

When pipe is closed, m_coninPipe->isClosed() should return true, So probably, winpty_close_stdin is not required. (AFAICS)

@mattn
Copy link

mattn commented Sep 4, 2017

Works fine for me. :)
terminal1

@mattn
Copy link

mattn commented Sep 4, 2017

This patch is not enough to use stdin. Probably stdin-pipe should be provided separated from conin-pipe.

@mattn
Copy link

mattn commented Sep 5, 2017

@rprichard do you have interesting about stdin support? If you do, I'll send pull-request based on patch above.

@rprichard
Copy link
Owner

Sorry, I'm probably not going to have time to work on this soon. I don't know when I'll be able to.

@mattn
Copy link

mattn commented Sep 11, 2017

@rprichard Do you have plan to move repository into org and assign contributors for winpty? AFAIK, winpty is used in some projects. Visual Studio Code, vim, etc.

@rprichard
Copy link
Owner

No, I don't have a plan like that.

@mattn
Copy link

mattn commented Sep 11, 2017

Okay. Can I help something to go forard for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants