]> xenbits.xensource.com Git - pvdrivers/win/xencons.git/commitdiff
Add a TTY utility
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 15:02:26 +0000 (16:02 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 15:09:33 +0000 (16:09 +0100)
This patch adds a new TTY utility which will open the console device and
pipe it to a command shell (cmd.exe) process. It also provides login
functionality for a local user such that the command shell is invoked as
that user.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
src/monitor/monitor.c
src/tty/tty.c [new file with mode: 0644]
src/tty/xencons_tty.rc [new file with mode: 0644]
src/xencons.inf
vs2015/package/package.vcxproj
vs2015/xencons.sln
vs2015/xencons_tty/xencons_tty.vcxproj [new file with mode: 0644]
vs2015/xencons_tty/xencons_tty.vcxproj.user [new file with mode: 0644]

index fabca772000db148dd1517bef6d92b20493f52c5..a8ae21bfa2f8970e53295a874617b7844ab91974 100644 (file)
@@ -58,10 +58,13 @@ typedef struct _MONITOR_CONTEXT {
     HANDLE                  StopEvent;
     HANDLE                  AddEvent;
     HANDLE                  RemoveEvent;
+    PTCHAR                  Executable;
     HDEVNOTIFY              InterfaceNotification;
     PTCHAR                  DevicePath;
     HDEVNOTIFY              DeviceNotification;
     HANDLE                  Device;
+    HANDLE                  ThreadEvent;
+    HANDLE                  Thread;
 } MONITOR_CONTEXT, *PMONITOR_CONTEXT;
 
 MONITOR_CONTEXT MonitorContext;
@@ -342,6 +345,117 @@ fail1:
     return FALSE;
 }
 
+DWORD WINAPI
+MonitorThread(
+    IN  LPVOID          Argument
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    DWORD               CommandLineLength;
+    PTCHAR              CommandLine;
+    PROCESS_INFORMATION ProcessInfo;
+    STARTUPINFO         StartupInfo;
+    BOOL                Success;
+    HANDLE              Handle[2];
+    DWORD               Object;
+    HRESULT             Error;
+
+    UNREFERENCED_PARAMETER(Argument);
+
+    Log("====>");
+
+    CommandLineLength = (DWORD)(_tcslen(Context->Executable) +
+                                2 +
+                                _tcslen(Context->DevicePath) +
+                                2) * sizeof (TCHAR);
+
+    CommandLine = calloc(1, CommandLineLength);
+
+    if (CommandLine == NULL)
+        goto fail1;
+
+    (VOID) _sntprintf(CommandLine,
+                      CommandLineLength - 1,
+                      TEXT("%s \"%s\""),
+                      Context->Executable,
+                      Context->DevicePath);
+
+again:
+    ZeroMemory(&ProcessInfo, sizeof (ProcessInfo));
+    ZeroMemory(&StartupInfo, sizeof (StartupInfo));
+    StartupInfo.cb = sizeof (StartupInfo);
+
+    Log("Executing: %s", CommandLine);
+
+#pragma warning(suppress:6053) // CommandLine might not be NUL-terminated
+    Success = CreateProcess(NULL,
+                            CommandLine,
+                            NULL,
+                            NULL,
+                            FALSE,
+                            CREATE_NO_WINDOW |
+                            CREATE_NEW_PROCESS_GROUP,
+                            NULL,
+                            NULL,
+                            &StartupInfo,
+                            &ProcessInfo);
+    if (!Success)
+        goto fail2;
+
+    Handle[0] = Context->ThreadEvent;
+    Handle[1] = ProcessInfo.hProcess;
+
+    Object = WaitForMultipleObjects(ARRAYSIZE(Handle),
+                                   Handle,
+                                   FALSE,
+                                   INFINITE);
+
+#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
+
+    switch (Object) {
+    case WAIT_OBJECT_0:
+        ResetEvent(Context->ThreadEvent);
+
+        TerminateProcess(ProcessInfo.hProcess, 1);
+        CloseHandle(ProcessInfo.hProcess);
+        CloseHandle(ProcessInfo.hThread);
+        break;
+
+    case WAIT_OBJECT_1:
+        CloseHandle(ProcessInfo.hProcess);
+        CloseHandle(ProcessInfo.hThread);
+        goto again;
+
+    default:
+        break;
+    }
+
+//#undef WAIT_OBJECT_1
+
+    free(CommandLine);
+
+    Log("<====");
+
+    return 0;
+
+fail2:
+    Log("fail2");
+
+    free(CommandLine);
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return 1;
+}
+
 static VOID
 PutString(
     IN  HANDLE      Handle,
@@ -419,10 +533,43 @@ MonitorAdd(
 
     Context->DevicePath = Path;
 
+    Context->ThreadEvent = CreateEvent(NULL,
+                                       TRUE,
+                                       FALSE,
+                                       NULL);
+
+    if (Context->ThreadEvent == NULL)
+        goto fail4;
+
+    Context->Thread = CreateThread(NULL,
+                                   0,
+                                   MonitorThread,
+                                   NULL,
+                                   0,
+                                   NULL);
+
+    if (Context->Thread == INVALID_HANDLE_VALUE)
+        goto fail5;
+
     Log("<====");
 
     return;
 
+fail5:
+    Log("fail5");
+
+    CloseHandle(Context->ThreadEvent);
+    Context->ThreadEvent = NULL;
+
+fail4:
+    Log("fail4");
+
+    free(Context->DevicePath);
+    Context->DevicePath = NULL;
+
+    UnregisterDeviceNotification(Context->DeviceNotification);
+    Context->DeviceNotification = NULL;
+
 fail3:
     Log("fail3");
 
@@ -457,6 +604,12 @@ MonitorRemove(
 
     Log("====>");
 
+    SetEvent(Context->ThreadEvent);
+    WaitForSingleObject(Context->Thread, INFINITE);
+
+    CloseHandle(Context->ThreadEvent);
+    Context->ThreadEvent = NULL;
+
     free(Context->DevicePath);
     Context->DevicePath = NULL;
 
@@ -528,6 +681,84 @@ MonitorCtrlHandlerEx(
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
+static BOOL
+GetExecutable(
+    OUT PTCHAR          *Executable
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    DWORD               MaxValueLength;
+    DWORD               ExecutableLength;
+    DWORD               Type;
+    HRESULT             Error;
+
+    Error = RegQueryInfoKey(Context->ParametersKey,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            &MaxValueLength,
+                            NULL,
+                            NULL);
+    if (Error != ERROR_SUCCESS) {
+        SetLastError(Error);
+        goto fail1;
+    }
+
+    ExecutableLength = MaxValueLength + sizeof (TCHAR);
+
+    *Executable = calloc(1, ExecutableLength);
+    if (Executable == NULL)
+        goto fail2;
+
+    Error = RegQueryValueEx(Context->ParametersKey,
+                            "Executable",
+                            NULL,
+                            &Type,
+                            (LPBYTE)(*Executable),
+                            &ExecutableLength);
+    if (Error != ERROR_SUCCESS) {
+        SetLastError(Error);
+        goto fail3;
+    }
+
+    if (Type != REG_SZ) {
+        SetLastError(ERROR_BAD_FORMAT);
+        goto fail4;
+    }
+
+    Log("%s", *Executable);
+
+    return TRUE;
+
+fail4:
+    Log("fail4");
+
+fail3:
+    Log("fail3");
+
+    free(*Executable);
+
+fail2:
+    Log("fail2");
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
 VOID WINAPI
 MonitorMain(
     _In_    DWORD                   argc,
@@ -537,6 +768,7 @@ MonitorMain(
     PMONITOR_CONTEXT                Context = &MonitorContext;
     DEV_BROADCAST_DEVICEINTERFACE   Interface;
     HRESULT                         Error;
+    BOOL                            Success;
 
     UNREFERENCED_PARAMETER(argc);
     UNREFERENCED_PARAMETER(argv);
@@ -591,6 +823,10 @@ MonitorMain(
     if (Context->RemoveEvent == NULL)
         goto fail6;
 
+    Success = GetExecutable(&Context->Executable);
+    if (!Success)
+        goto fail7;
+
     Context->Device = INVALID_HANDLE_VALUE;
 
     ZeroMemory(&Interface, sizeof (Interface));
@@ -603,7 +839,7 @@ MonitorMain(
                                    &Interface,
                                    DEVICE_NOTIFY_SERVICE_HANDLE);
     if (Context->InterfaceNotification == NULL)
-        goto fail7;
+        goto fail8;
 
     // The device may already by present
     SetEvent(Context->AddEvent);
@@ -655,6 +891,8 @@ done:
 
     UnregisterDeviceNotification(Context->InterfaceNotification);
 
+    free(Context->Executable);
+
     CloseHandle(Context->RemoveEvent);
 
     CloseHandle(Context->AddEvent);
@@ -671,6 +909,11 @@ done:
 
     return;
 
+fail8:
+    Log("fail8");
+
+    free(Context->Executable);
+
 fail7:
     Log("fail7");
 
diff --git a/src/tty/tty.c b/src/tty/tty.c
new file mode 100644 (file)
index 0000000..c47634c
--- /dev/null
@@ -0,0 +1,509 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <windows.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <userenv.h>
+
+typedef struct _TTY_STREAM {
+    HANDLE  Read;
+    HANDLE  Write;
+} TTY_STREAM, *PTTY_STREAM;
+
+#define MAXIMUM_BUFFER_SIZE 1024
+
+typedef struct _TTY_CONTEXT {
+    TTY_STREAM          ChildStdIn;
+    TTY_STREAM          ChildStdOut;
+    TTY_STREAM          Device;
+    TCHAR               UserName[MAXIMUM_BUFFER_SIZE];
+    TCHAR               Password[MAXIMUM_BUFFER_SIZE];
+    HANDLE              Token;
+    PROCESS_INFORMATION ProcessInfo;
+} TTY_CONTEXT, *PTTY_CONTEXT;
+
+TTY_CONTEXT TtyContext;
+
+static BOOL
+CreateChild(
+    VOID
+    )
+{
+    PTTY_CONTEXT            Context = &TtyContext;
+    TCHAR                   CommandLine[] = TEXT("c:\\windows\\system32\\cmd.exe /q /a");
+    PVOID                   Environment;
+    PROFILEINFO             ProfileInfo;
+    DWORD                   Size;
+    TCHAR                   ProfileDir[MAXIMUM_BUFFER_SIZE];
+    STARTUPINFO             StartupInfo;
+    BOOL                    Success;
+
+    Success = CreateEnvironmentBlock(&Environment,
+                                     Context->Token,
+                                     FALSE);
+    if (!Success)
+        return FALSE;
+
+    ZeroMemory(&ProfileInfo, sizeof (ProfileInfo));
+    ProfileInfo.dwSize = sizeof (ProfileInfo);
+    ProfileInfo.lpUserName = Context->UserName;
+
+    Success = LoadUserProfile(Context->Token, &ProfileInfo);
+    if (!Success)
+        return FALSE;
+
+    Size = sizeof (ProfileDir);
+
+    Success = GetUserProfileDirectory(Context->Token,
+                                      ProfileDir,
+                                      &Size);
+    if (!Success)
+        return FALSE;
+
+    Success = ImpersonateLoggedOnUser(Context->Token);
+    if (!Success)
+        return FALSE;
+
+    ZeroMemory(&StartupInfo, sizeof (StartupInfo));
+    StartupInfo.cb = sizeof (StartupInfo);
+
+    StartupInfo.hStdInput = Context->ChildStdIn.Read;
+    StartupInfo.hStdOutput = Context->ChildStdOut.Write;
+    StartupInfo.hStdError = Context->ChildStdOut.Write;
+
+    StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+#pragma warning(suppress:6335) // leaking handle information
+    Success = CreateProcessAsUser(Context->Token,
+                                  NULL,
+                                  CommandLine,
+                                  NULL,
+                                  NULL,
+                                  TRUE,
+                                  CREATE_UNICODE_ENVIRONMENT,
+                                  Environment,
+                                  ProfileDir,
+                                  &StartupInfo,
+                                  &Context->ProcessInfo);
+
+    DestroyEnvironmentBlock(Environment);
+
+    if (!Success)
+        return FALSE;
+
+    SetConsoleCtrlHandler(NULL, TRUE);
+
+    return TRUE;
+}
+
+static VOID
+PutCharacter(
+    IN  PTTY_STREAM Stream,
+    IN  TCHAR       Character
+    )
+{
+    WriteFile(Stream->Write,
+              &Character,
+              1,
+              NULL,
+              NULL);
+}
+
+static VOID
+PutString(
+    IN  PTTY_STREAM Stream,
+    IN  PTCHAR      Buffer,
+    IN  DWORD       Length
+    )
+{
+    DWORD           Offset;
+
+    Offset = 0;
+    while (Offset < Length) {
+        DWORD   Written;
+        BOOL    Success;
+
+        Success = WriteFile(Stream->Write,
+                            &Buffer[Offset],
+                            Length - Offset,
+                            &Written,
+                            NULL);
+        if (!Success)
+            break;
+
+        Offset += Written;
+    }
+}
+
+#define ECHO(_Stream, _Buffer) \
+    PutString((_Stream), TEXT(_Buffer), (DWORD)_tcslen(_Buffer))
+
+static BOOL
+GetLine(
+    IN  PTTY_STREAM Stream,
+    IN  PTCHAR      Buffer,
+    IN  DWORD       NumberOfBytesToRead,
+    OUT LPDWORD     NumberOfBytesRead,
+    IN  BOOL        NoEcho
+    )
+{
+    DWORD           Offset;
+    BOOL            Success = TRUE;
+
+    Offset = 0;
+    while (Offset < NumberOfBytesToRead) {
+        TCHAR   Sequence[MAXIMUM_BUFFER_SIZE];
+        PTCHAR  Character;
+        DWORD   Read;
+
+        Success = ReadFile(Stream->Read,
+                           &Sequence,
+                           sizeof (Sequence),
+                           &Read,
+                           NULL);
+        if (!Success)
+            break;
+
+        Character = &Sequence[0];
+        while (Read-- != 0) {
+            Buffer[Offset] = *Character++;
+
+            if (!iscntrl(Buffer[Offset])) {
+                if (!NoEcho)
+                    PutCharacter(Stream, Buffer[Offset]);
+                Offset++;
+            } else {
+                if (Buffer[Offset] == 0x7F && // DEL
+                    Offset != 0) {
+                    --Offset;
+
+                    if (Buffer[Offset] >= 0x00 &&
+                        Buffer[Offset] < 0x20)
+                        ECHO(Stream, "\b\b  \b\b");
+                    else if (!NoEcho)
+                        ECHO(Stream, "\b \b");
+                } else if (Buffer[Offset] == 0x03 || // ^C
+                           Buffer[Offset] == 0x0D) { // ^M
+                    Offset++;
+                    break;
+                } else if (Buffer[Offset] >= 0x00 &&
+                           Buffer[Offset] < 0x20) {
+                    ECHO(Stream, "^");
+                    PutCharacter(Stream, Buffer[Offset] + 0x40);
+                    Offset++;
+                }
+            }
+
+            if (Offset >= NumberOfBytesToRead)
+                break;
+        }
+
+        if (Offset == 0)
+            continue;
+
+        if (Buffer[Offset - 1] == 0x03 || // ^C
+            Buffer[Offset - 1] == 0x0D)   // ^M
+            break;
+    }
+
+    ECHO(Stream, "\r\n");
+
+    *NumberOfBytesRead = Offset;
+
+    return Success;
+}
+
+static BOOL
+GetCredentials(
+    VOID
+    )
+{
+    PTTY_CONTEXT    Context = &TtyContext;
+    TCHAR           ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
+    PTCHAR          End;
+    DWORD           Size;
+    BOOL            Success;
+
+    ZeroMemory(ComputerName, sizeof (ComputerName));
+    Size = sizeof (ComputerName);
+
+    Success = GetComputerName(ComputerName, &Size);
+    if (!Success)
+        return FALSE;
+
+    ECHO(&Context->Device, "\r\n");
+    PutString(&Context->Device, ComputerName, Size);
+    ECHO(&Context->Device, " login: ");
+
+    ZeroMemory(Context->UserName, sizeof (Context->UserName));
+
+    Success = GetLine(&Context->Device,
+                      Context->UserName,
+                      sizeof (Context->UserName),
+                      &Size,
+                      FALSE);
+    if (!Success)
+        return FALSE;
+
+    End = _tcschr(Context->UserName, TEXT('\r'));
+    if (End == NULL)
+        return FALSE;
+
+    *End = TEXT('\0');
+
+    if (_tcslen(Context->UserName) == 0)
+        return FALSE;
+
+    ECHO(&Context->Device, "Password: ");
+
+    ZeroMemory(Context->Password, sizeof (Context->Password));
+
+    Success = GetLine(&Context->Device,
+                      Context->Password,
+                      sizeof (Context->Password),
+                      &Size,
+                      TRUE);
+    if (!Success)
+        return FALSE;
+
+    End = _tcschr(Context->Password, TEXT('\r'));
+    if (End == NULL)
+        return FALSE;
+
+    *End = TEXT('\0');
+
+    return TRUE;
+}
+
+static DWORD WINAPI
+TtyIn(
+    IN  LPVOID      Argument
+    )
+{
+    PTTY_CONTEXT    Context = &TtyContext;
+
+    UNREFERENCED_PARAMETER(Argument);
+
+    for (;;) {
+        DWORD       Read;
+        CHAR        Buffer[MAXIMUM_BUFFER_SIZE];
+        BOOL        Success;
+
+        Success = GetLine(&Context->Device,
+                          Buffer,
+                          sizeof (Buffer) - 1,
+                          &Read,
+                          FALSE);
+        if (!Success)
+            break;
+
+        if (Read == 0)
+            continue;
+
+        if (Buffer[Read - 1] == 0x03) { // ^C
+            GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
+            continue;
+        } else if (Buffer[Read - 1] == 0x0D) { // ^M
+            Buffer[Read++] = '\n';
+
+            Success = WriteFile(Context->ChildStdIn.Write,
+                                Buffer,
+                                Read,
+                                NULL,
+                                NULL);
+            if (!Success)
+                break;
+        }
+    }
+
+    return 0;
+}
+
+static DWORD WINAPI
+TtyOut(
+    IN  LPVOID      Argument
+    )
+{
+    PTTY_CONTEXT    Context = &TtyContext;
+
+    UNREFERENCED_PARAMETER(Argument);
+
+    for (;;) {
+        DWORD       Read;
+        DWORD       Written;
+        CHAR        Buffer[MAXIMUM_BUFFER_SIZE];
+        BOOL        Success;
+
+        Success = ReadFile(Context->ChildStdOut.Read,
+                           Buffer,
+                           sizeof (Buffer),
+                           &Read,
+                           NULL);
+        if (!Success)
+            break;
+
+        if (Read == 0)
+            continue;
+
+        Success = WriteFile(Context->Device.Write,
+                            Buffer,
+                            Read,
+                            &Written,
+                            NULL);
+        if (!Success)
+            break;
+    }
+
+    return 0;
+}
+
+void __cdecl
+_tmain(
+    IN  int             argc,
+    IN  TCHAR           *argv[]
+    )
+{
+    PTTY_CONTEXT        Context = &TtyContext;
+    PTCHAR              DeviceName;
+    SECURITY_ATTRIBUTES Attributes;
+    HANDLE              Handle[3];
+    DWORD               Index;
+    BOOL                Success;
+
+    if (argc != 2)
+        ExitProcess(1);
+
+    DeviceName = argv[1];
+
+    Context->Device.Read = CreateFile(DeviceName,
+                                      GENERIC_READ,
+                                      FILE_SHARE_WRITE,
+                                      NULL,
+                                      OPEN_EXISTING,
+                                      FILE_ATTRIBUTE_NORMAL,
+                                      NULL);
+
+    if (Context->Device.Read == INVALID_HANDLE_VALUE)
+        ExitProcess(1);
+
+    Context->Device.Write = CreateFile(DeviceName,
+                                       GENERIC_WRITE,
+                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                       NULL,
+                                       OPEN_EXISTING,
+                                       FILE_ATTRIBUTE_NORMAL,
+                                       NULL);
+
+    if (Context->Device.Read == INVALID_HANDLE_VALUE)
+        ExitProcess(1);
+
+    Success = GetCredentials();
+    if (!Success)
+        ExitProcess(1);
+
+    Success = LogonUser(Context->UserName,
+                        NULL,
+                        Context->Password,
+                        LOGON32_LOGON_INTERACTIVE,
+                        LOGON32_PROVIDER_DEFAULT,
+                        &Context->Token);
+    if (!Success)
+        ExitProcess(1);
+
+    Attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+    Attributes.bInheritHandle = TRUE;
+    Attributes.lpSecurityDescriptor = NULL;
+
+    Success = CreatePipe(&Context->ChildStdOut.Read,
+                         &Context->ChildStdOut.Write,
+                         &Attributes,
+                         0);
+    if (!Success)
+        ExitProcess(1);
+
+    Success = SetHandleInformation(Context->ChildStdOut.Read,
+                                   HANDLE_FLAG_INHERIT,
+                                   0);
+    if (!Success)
+        ExitProcess(1);
+
+    Success = CreatePipe(&Context->ChildStdIn.Read,
+                         &Context->ChildStdIn.Write,
+                         &Attributes,
+                         0);
+    if (!Success)
+        ExitProcess(1);
+
+    Success = SetHandleInformation(Context->ChildStdIn.Write,
+                                   HANDLE_FLAG_INHERIT,
+                                   0);
+    if (!Success)
+        ExitProcess(1);
+
+    Success = CreateChild();
+
+    if (!Success)
+        ExitProcess(1);
+
+    Handle[0] = Context->ProcessInfo.hThread;
+
+    Handle[1] = CreateThread(NULL,
+                             0,
+                             TtyIn,
+                             NULL,
+                             0,
+                             NULL);
+
+    if (Handle[1] == INVALID_HANDLE_VALUE)
+        ExitProcess(1);
+
+    Handle[2] = CreateThread(NULL,
+                             0,
+                             TtyOut,
+                             NULL,
+                             0,
+                             NULL);
+
+    if (Handle[2] == INVALID_HANDLE_VALUE)
+        ExitProcess(1);
+
+    WaitForMultipleObjects(ARRAYSIZE(Handle),
+                           Handle,
+                           FALSE,
+                           INFINITE);
+
+    for (Index = 0; Index < ARRAYSIZE(Handle); Index++)
+        if ( Handle[Index] != 0 )
+            CloseHandle(Handle[Index]);
+
+    CloseHandle(Context->ProcessInfo.hProcess);
+}
diff --git a/src/tty/xencons_tty.rc b/src/tty/xencons_tty.rc
new file mode 100644 (file)
index 0000000..2a72104
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <windows.h>
+#include <ntverp.h>
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#include <version.h>
+
+#define VER_COMPANYNAME_STR         VENDOR_NAME_STR
+#define VER_LEGALCOPYRIGHT_STR      "Copyright (c) Citrix Systems Inc."
+
+#define VER_PRODUCTNAME_STR         "XENCONS"
+#define VER_PRODUCTVERSION          MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER
+#define VER_PRODUCTVERSION_STR      MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR
+
+#define VER_INTERNALNAME_STR       "XENCONS_TTY.EXE"
+#define VER_FILEDESCRIPTION_STR     "XENCONS_TTY"
+
+#define VER_FILETYPE               VFT_APP
+#define VER_FILESUBTYPE                    VFT2_UNKNOWN
+
+#include "common.ver"
index dbff121149acba13286b3a1d46243272c6d81026..3cbdd96db28249f00f27b6c7163afb0cc0779e89 100644 (file)
@@ -42,6 +42,7 @@ DriverPackageDisplayName=%DiskDesc%
 DefaultDestDir=12
 CoInst_CopyFiles=11
 Monitor_CopyFiles=11
+Tty_CopyFiles=11
 
 [SourceDisksNames]
 0=%DiskDesc%
@@ -51,6 +52,7 @@ xencons.sys=0,,
 xencons_coinst.dll=0,,
 xencons_monitor.exe=0,,
 xencons_monitor.dll=0,,
+xencons_tty.exe=0,,
 
 [CoInst_CopyFiles]
 xencons_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xencons_coinst.dll
@@ -59,6 +61,9 @@ xencons_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dl
 xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe,xencons_monitor.exe
 xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xencons_monitor.dll
 
+[Tty_CopyFiles]
+xencons_tty_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe,xencons_tty.exe
+
 [Manufacturer]
 %Vendor%=Inst,NT$ARCH$
 
@@ -73,6 +78,7 @@ xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.d
 [XenCons_Inst]
 CopyFiles=XenCons_Copyfiles
 CopyFiles=Monitor_Copyfiles
+CopyFiles=Tty_Copyfiles
 
 [XenCons_Copyfiles]
 xencons.sys
@@ -107,6 +113,7 @@ AddReg = Monitor_Parameters
 
 [Monitor_Parameters]
 HKR,"Parameters",,0x00000010
+HKR,"Parameters","Executable",0x00000000,"xencons_tty_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe"
 
 [Monitor_EventLog]
 AddReg=Monitor_EventLog_AddReg
index 65f912554d1eef2155e7b7b327ee7a5f598c02a6..2e5c0eb472a44224c9c87f7d1e5703ec77d23a7a 100644 (file)
@@ -42,6 +42,9 @@
     <ProjectReference Include="..\xencons_monitor\xencons_monitor.vcxproj">
       <Project>{8991F0A5-408B-43E0-88CC-9550D4AAE616}</Project>
     </ProjectReference>
+    <ProjectReference Include="..\xencons_tty\xencons_tty.vcxproj">
+      <Project>{79D98F83-5A2F-4DE6-B62C-530D70B88C3F}</Project>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <FilesToPackage Include="$(DPINST_REDIST)\x86\dpinst.exe" Condition="'$(Platform)'=='Win32'" />
index 6801b45631acd8cbea9d444d48cc47159c6576fb..7f55d78c66e1ccf00327a0cca9ec3f436a464e9a 100644 (file)
@@ -8,11 +8,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons_coinst", "xencons_c
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons_monitor", "xencons_monitor\xencons_monitor.vcxproj", "{8991F0A5-408B-43E0-88CC-9550D4AAE616}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons_tty", "xencons_tty\xencons_tty.vcxproj", "{79D98F83-5A2F-4DE6-B62C-530D70B88C3F}"
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{8B5B8F4B-7FF3-4B64-AC4A-5246026217E7}"
        ProjectSection(ProjectDependencies) = postProject
                {4674B8C2-876B-4F2A-AB71-BAC968A9B529} = {4674B8C2-876B-4F2A-AB71-BAC968A9B529}
                {6CC9B8DD-A5AE-427D-8157-E91D21DD7E19} = {6CC9B8DD-A5AE-427D-8157-E91D21DD7E19}
                {8991F0A5-408B-43E0-88CC-9550D4AAE616} = {8991F0A5-408B-43E0-88CC-9550D4AAE616}
+               {79D98F83-5A2F-4DE6-B62C-530D70B88C3F} = {79D98F83-5A2F-4DE6-B62C-530D70B88C3F}
        EndProjectSection
 EndProject
 Global
diff --git a/vs2015/xencons_tty/xencons_tty.vcxproj b/vs2015/xencons_tty/xencons_tty.vcxproj
new file mode 100644 (file)
index 0000000..135126c
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\configs.props" />
+  <PropertyGroup Label="PropertySheets">
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{79D98F83-5A2F-4DE6-B62C-530D70B88C3F}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="..\targets.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup>
+    <IncludePath>$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <EnableInf2cat>false</EnableInf2cat>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <DisableSpecificWarnings>4127;4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <EnablePREfast>true</EnablePREfast>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>setupapi.lib;userenv.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\tty\tty.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="..\..\src\tty\xencons_tty.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2015/xencons_tty/xencons_tty.vcxproj.user b/vs2015/xencons_tty/xencons_tty.vcxproj.user
new file mode 100644 (file)
index 0000000..a427c80
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <SignMode>TestSign</SignMode>
+    <TestCertificate>..\..\src\xencons.pfx</TestCertificate>
+    <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+  </PropertyGroup>
+</Project>