Example #1
0
        /// <summary>
        /// Start kmod and connect to it.
        /// </summary>
        private void StartKmod()
        {
            FileStream file = null;
            Socket listenSock = null;
            RegistryKey kwmRegKey = null;

            try
            {
                // Get the path to the kmod executable in the registry.
                kwmRegKey = Base.GetKwmLMRegKey();
                String Kmod = "\"" + (String)kwmRegKey.GetValue("InstallDir", @"C:\Program Files\Teambox\Teambox Manager") + "\\kmod\\kmod.exe\"";

                // The directory where KMOD will save logs and its database for use with the kwm.
                String KmodDir = Misc.GetKmodDirPath();
                Directory.CreateDirectory(KmodDir);

                // Start listening for kmod to connect when it'll be started.
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
                listenSock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSock.Bind(endPoint);
                listenSock.Listen(1);
                int port = ((IPEndPoint)listenSock.LocalEndPoint).Port;

                // Start KMOD in debugging mode if our settings say so.
                String debug = Misc.ApplicationSettings.ktlstunnelLoggingLevel > 0 ? " -l 3" : "";
                String args = " -C kmod_connect -p " + port + debug + " -m 20000 -k \"" + KmodDir + "\"";
                String cmdLine = Kmod + args;
                Logging.Log("About to start kmod.exe: " + cmdLine);
                m_kmodProc = new RawProcess(cmdLine);
                m_kmodProc.InheritHandles = false;
                m_kmodProc.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW;
                m_kmodProc.Start();

                // Wait for KMOD to connect for about 10 seconds.
                DateTime startTime = DateTime.Now;
                while (true)
                {
                    SelectSockets select = new SelectSockets();
                    select.AddRead(listenSock);
                    SetSelectTimeout(startTime, 10000, select, "no KMOD connection received");
                    Block(select);

                    if (select.InRead(listenSock))
                    {
                        m_kmodSock = listenSock.Accept();
                        m_kmodSock.Blocking = false;
                        break;
                    }
                }

                // Read the authentication data.
                byte[] authSockData = new byte[32];
                byte[] authFileData = new byte[32];

                startTime = DateTime.Now;
                int nbRead = 0;
                while (nbRead != 32)
                {
                    SelectSockets select = new SelectSockets();
                    select.AddRead(m_kmodSock);
                    SetSelectTimeout(startTime, 2000, select, "no authentication data received");
                    Block(select);
                    int r = Base.SockRead(m_kmodSock, authSockData, nbRead, 32 - nbRead);
                    if (r > 0) nbRead += r;
                }

                file = File.Open(KmodDir + "\\connect_secret", FileMode.Open);
                file.Read(authFileData, 0, 32);
                if (!Base.ByteArrayEqual(authFileData, authSockData))
                    throw new Exception("invalid authentication data received");

                // Set the transport.
                m_transport = new K3pTransport(m_kmodSock);
            }

            finally
            {
                if (file != null) file.Close();
                if (listenSock != null) listenSock.Close();
                if (kwmRegKey != null) kwmRegKey.Close();
            }
        }
Example #2
0
File: Misc.cs Project: tmbx/kwm
        /// <summary>
        /// Display an error message to the user and exit the application if 
        /// required.
        /// </summary>
        public static void HandleError(String errorMessage, bool fatalFlag)
        {
            string msg = "An error has been detected." +
                                     Environment.NewLine + Environment.NewLine +
                                     errorMessage +
                                     Environment.NewLine + Environment.NewLine;
            if (fatalFlag)
            {
                msg += "Please restart your " + Base.GetKwmString();
            }
            else
            {
                msg += "Please contact your technical support for further information.";
            }

            if (!fatalFlag)
            {
                Misc.KwmTellUser(msg, MessageBoxIcon.Error);
                return;
            }

            // The .Net framework is critically brain damaged when it comes to
            // handling fatal errors. There are basically two choices: exit
            // the process right away or try to get the application to display
            // the error and quit.
            //
            // The former choice is sane; there is no risk of further data
            // corruption if the process exits right away. The lack of any
            // error message is problematic however. We work around this by
            // spawning an external program, if possible, to report the error
            // before exiting the process.
            //
            // The second choice cannot be done sanely. If a MessageBox()
            // call is made immediately when the error is detected, then
            // the UI will be reentered and the damage may spread further.
            // Typically this causes multiple fatal error messages to
            // appear. After some investigation, I believe this is impossible
            // to prevent. The best available thing is ThreadAbortException,
            // which has weird semantics and is considered deprecated and
            // doesn't do the right thing in worker threads.

            // Exit right away.
            if (!FatalErrorMsgOKFlag || m_fatalErrorCaughtFlag)
                Environment.Exit(1);

            // We have caught a fatal error. Prevent the other threads from
            // spawning a fatal error. There is an inherent race condition
            // here which is best left alone; mutexes have no business here.
            m_fatalErrorCaughtFlag = true;

            // Spawn a program to display the message.
            try
            {
                String startupLine = '"' + Application.ExecutablePath + '"' + " ";
                startupLine += "\"-M\" \"" + EscapeArgForFatalError(msg) + "\"";
                RawProcess p = new RawProcess(startupLine);
                p.InheritHandles = false;
                p.Start();
            }

            // Ignore all exceptions.
            catch (Exception)
            {
            }

            // Get out.
            Environment.Exit(1);
        }
Example #3
0
        /// <summary>
        /// Clean up the KMOD process and socket.
        /// </summary>
        private void CleanUpKmod()
        {
            if (m_kmodProc != null)
            {
                m_kmodProc.Terminate();
                m_kmodProc = null;
            }

            if (m_kmodSock != null)
            {
                m_kmodSock.Close();
                m_kmodSock = null;
            }
        }
Example #4
0
File: Tunnel.cs Project: tmbx/kwm
        /// <summary>
        /// Disconnect and close ktlstunnel.
        /// </summary>
        public void Terminate()
        {
            Disconnect();

            if (TunnelProcess != null)
            {
                TunnelProcess.Terminate();
                TunnelProcess = null;
            }
        }
Example #5
0
File: Tunnel.cs Project: tmbx/kwm
        /// <summary>
        /// Create a listening socket and spawn ktlstunnel process.
        /// </summary>
        public void BeginTls(string extraParams)
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
            Sock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            Sock.Bind(endPoint);
            Sock.Listen(1);

            /* Create a logging dir for ktlstunnel, if it does not exist */
            if (!Directory.Exists(Misc.GetKtlstunnelLogFilePath()))
            {
                Directory.CreateDirectory(Misc.GetKtlstunnelLogFilePath());
            }

            // Start ktlstunnel as such.
            // ktlstunnel localhost ((IPEndPoint)Listener.LocalEndPoint).Port Host Port [-r host:port]
            String loggingPath = "-L " + "\"" + Misc.GetKtlstunnelLogFilePath() + "ktlstunnel-" + Base.GetLogFileName() + "\" ";
            String loggingLevel = "";

            if(Misc.ApplicationSettings.ktlstunnelLoggingLevel == 1)
            {
                loggingLevel = "-l minimal ";
                loggingLevel += loggingPath;
            }
            else if (Misc.ApplicationSettings.ktlstunnelLoggingLevel == 2)
            {
                loggingLevel = "-l debug ";
                loggingLevel += loggingPath;
            }

            string startupLine = "\"" + Base.GetKcsInstallationPath() +  @"ktlstunnel\ktlstunnel.exe" + "\" " +
                                 loggingLevel +
                                 "localhost " + ((IPEndPoint)Sock.LocalEndPoint).Port.ToString() + " " +
                                 Host + " " + Port + " " + extraParams;

            Logging.Log("Starting ktlstunnel.exe : " + startupLine);

            TunnelProcess = new RawProcess(startupLine);
            TunnelProcess.InheritHandles = false;
            TunnelProcess.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW;
            TunnelProcess.Start();
        }
Example #6
0
        /// <summary>
        /// Handles when a Start Ticket is received.
        /// </summary>
        /// <param name="_context"></param>
        private void OnStartTicketResponse(KasQuery ctx)
        {
            Debug.Assert(m_state == AppSharingState.StartTicket);

            AnpMsg cmd = ctx.Cmd;
            AnpMsg res = ctx.Res;

            if (m_state != AppSharingState.StartTicket)
            {
                Logging.Log(2, "Received spurious Screen Sharing Start ticket.");
                return;
            }

            if (res.Type == KAnpType.KANP_RES_VNC_START_TICKET)
            {
                m_ticket = res.Elements[0].Bin;

                /* Start MetaVNC (specify the desired window's handle)*/
                int handle = Int32.Parse((String)ctx.MetaData[0]);
                bool supportSession = (bool)ctx.MetaData[2];

                String vncServerPath = "\"" + Base.GetKwmInstallationPath() + @"vnc\kappserver.exe" + "\"";
                String args = (handle == 0) ? " -shareall" : " -sharehwnd " + (String)ctx.MetaData[0];

                // If a window is being shared (not the desktop), set
                // it visible and in foreground.
                if (handle != 0)
                {
                    IntPtr hWnd = new IntPtr(handle);

                    if (Syscalls.IsIconic(hWnd))
                        Syscalls.ShowWindowAsync(hWnd, (int)Syscalls.WindowStatus.SW_RESTORE);

                    Base.KSetForegroundWindow(hWnd);
                }

                /* Remove any indication of previous server's listening port */
                RegistryKey port = Base.GetKwmCURegKey();
                port.DeleteValue(m_portRegItem, false);
                port.DeleteValue(m_portRegItemWritten, false);
                port.Close();

                // Set registry options in order to allow/deny
                // remote control.
                SetSupportSessionMode(supportSession);

                Logging.Log("Starting the first instance of MetaVNC (no args).");

                m_serverProcess = new RawProcess(vncServerPath);
                m_serverProcess.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW;
                m_serverProcess.InheritHandles = false;
                Syscalls.STARTUPINFO si = new Syscalls.STARTUPINFO();
                si.dwFlags = 1;
                m_serverProcess.StartupInfo = si;

                m_serverProcess.ProcessEnd += HandleOnProcessEnd;

                m_serverProcess.Start();

                Logging.Log("Started.");

                /* Wait until we can get our hands on the process's window handle */
                int retries = 15;
                bool found = false;
                while (retries > 0)
                {
                    Logging.Log("Trying to start WinVNC ( " + retries + ")");

                    IntPtr serverHandle = Syscalls.FindWindow("WinVNC Tray Icon", 0);
                    if (serverHandle != IntPtr.Zero)
                    {
                        found = true;
                        break;
                    }
                    System.Threading.Thread.Sleep(250);
                    retries--;
                }

                if (!found)
                    throw new Exception("Screen sharing error: server could not be started.");

                /* Start another process of metaVNC.
                 * This is needed to pass the window handle
                 * we want, it was easier to do this that way
                 * than to pass it directly on the cmd line when
                 * starting the process the first time. */
                Logging.Log("Starting MetaVNC for the second time (this is normal): " + vncServerPath + args);
                m_dummyServerProcess = new RawProcess(vncServerPath + args);
                m_dummyServerProcess.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW;
                m_dummyServerProcess.InheritHandles = false;
                m_dummyServerProcess.StartupInfo = si;
                m_dummyServerProcess.ProcessEnd += HandleOnProcessEnd;

                m_dummyServerProcess.Start();

                // Find out on which port we need to tell ktlstunnel to
                // connect to the server
                RegistryKey kwmKey = Base.GetKwmCURegKey();
                object readPort = null;
                object portOK = null;

                // Actively poll the synchronization key for 6 seconds.
                retries = 30;
                found = false;

                while (retries > 0)
                {
                    portOK = kwmKey.GetValue(m_portRegItemWritten);

                    if (portOK != null)
                    {
                        found = true;
                        break;
                    }
                    System.Threading.Thread.Sleep(200);
                    retries--;
                }

                if (!found)
                {
                    if (kwmKey != null)
                        kwmKey.Close();

                    ResetToIdle();
                    Misc.KwmTellUser("Screen sharing error: a timeout occured while waiting for the server's listening port.");
                    return;
                }

                // At this stage we can presume the port was
                // correctly really written by the VNC server.
                readPort = kwmKey.GetValue(m_portRegItem);
                kwmKey.Close();

                if (port == null)
                {
                    ResetToIdle();
                    Misc.KwmTellUser("Screen sharing error: unable to read the server's listening port.");
                    return;
                }

                Logging.Log("Screen Sharing server's port: " + (int)readPort);

                /* Connect a new tunnel */
                m_tunnel = Helper.CreateTunnel();
                m_tunnel.Connect("localhost", (int)readPort);

                /* Negociate role */
                AnpMsg inMsg = Helper.NewKAnpMsg(KAnpType.KANP_CMD_MGT_SELECT_ROLE);

                inMsg.AddUInt32(KAnpType.KANP_KCD_ROLE_APP_SHARE);
                m_tunnel.SendMsg(inMsg);
                AnpMsg outMsg = m_tunnel.GetMsg();

                if (outMsg.Type == KAnpType.KANP_RES_FAIL)
                {
                    ResetToIdle();
                    Misc.KwmTellUser(outMsg.Elements[1].String);
                    return;
                }

                Debug.Assert(outMsg.Type == KAnpType.KANP_RES_OK);

                AnpMsg startSession = Helper.NewKAnpMsg(KAnpType.KANP_CMD_VNC_START_SESSION);
                startSession.AddBin(m_ticket);
                startSession.AddString((String)ctx.MetaData[1]);

                m_tunnel.SendMsg(startSession);
                outMsg = m_tunnel.GetMsg();
                if (outMsg.Type == KAnpType.KANP_RES_FAIL)
                {
                    ResetToIdle();
                    Misc.KwmTellUser(outMsg.Elements[1].String);
                    return;
                }
                Debug.Assert(outMsg.Type == KAnpType.KANP_RES_VNC_START_SESSION);

                m_createdSessionID = outMsg.Elements[0].UInt64;

                /* Disconnect tunnel so it can connect to metaVNC server */
                Logging.Log("About to call disconnect on ktlstunnel.");
                m_tunnel.Disconnect();
                CurrentState = AppSharingState.Started;
                m_connectedSessionID = 0;

                StopInactivityMonitor();

                // 10 minutes
                inactivityMonitor = MonitorCreator.CreateInstance(MonitorType.GlobalHookMonitor);
                inactivityMonitor.Interval = 600000;
                inactivityMonitor.Elapsed += new ElapsedEventHandler(HandleSessionTimeout);
                inactivityMonitor.Enabled = true;
            }
            else if (res.Type == KAnpType.KANP_RES_FAIL)
            {
                ResetToIdle();
                Misc.KwmTellUser(res.Elements[1].String);
            }
            else
            {
                Logging.Log(2, "unexpected response in OnStartTicketResponse");
            }
        }
Example #7
0
        private void OnConnectTicketResponse(KasQuery ctx)
        {
            Debug.Assert(m_state == AppSharingState.ConnectTicket);

            AnpMsg cmd = ctx.Cmd;
            AnpMsg res = ctx.Res;

            if (m_state != AppSharingState.ConnectTicket)
            {
                Logging.Log(2, "Received spurious Screen Sharing Connect ticket.");
                return;
            }

            if (res.Type == KAnpType.KANP_RES_VNC_CONNECT_TICKET)
            {
                m_ticket = res.Elements[0].Bin;

                // Remove any indication of previous client's listening port
                RegistryKey port = Base.GetKwmCURegKey();
                port.DeleteValue(m_portRegItem, false);
                port.DeleteValue(m_portRegItemWritten, false);
                port.Close();

                /* Start client. Force one parameter so that it does not
                 * prompt for connection parameters */
                String vncClientPath = "\"" + Base.GetKwmInstallationPath() + @"vnc\kappviewer.exe" + "\"";
                String args = " /shared /notoolbar /disableclipboard /encoding tight /compresslevel 9 localhost";

                m_viewerProcess = new RawProcess(vncClientPath + args);
                m_viewerProcess.InheritHandles = false;
                m_viewerProcess.ProcessEnd += HandleOnProcessEnd;
                m_viewerProcess.Start();

                RegistryKey kwmKey = Base.GetKwmCURegKey();
                object _port = null;
                object _portOK = null;

                // Actively poll the synchronization
                // key for 6 secs
                int retries = 30;
                bool found = false;

                while (retries > 0)
                {
                    _portOK = kwmKey.GetValue(m_portRegItemWritten);

                    if (_portOK != null)
                    {
                        found = true;
                        break;
                    }
                    System.Threading.Thread.Sleep(200);
                    retries--;
                }

                if (!found)
                {
                    if (kwmKey != null)
                        kwmKey.Close();

                    ResetToIdle();
                    Misc.KwmTellUser("a timeout occured while waiting for the client's listening port.");
                    return;
                }

                // At this stage we can presume the port was
                // correctly really written by the VNC server.
                _port = kwmKey.GetValue(m_portRegItem);
                kwmKey.Close();

                if (_port == null)
                {
                    ResetToIdle();
                    Misc.KwmTellUser("could not read client's listening port.");
                    return;
                }

                Logging.Log("Read VNC client's port: " + (int)_port);

                /* Connect a new tunnel */
                IAnpTunnel tunnel = Helper.CreateTunnel();
                tunnel.Connect("localhost", (int)_port);

                /* Negociate role */
                AnpMsg inMsg = Helper.NewKAnpMsg(KAnpType.KANP_CMD_MGT_SELECT_ROLE);
                inMsg.AddUInt32(KAnpType.KANP_KCD_ROLE_APP_SHARE);
                tunnel.SendMsg(inMsg);
                AnpMsg outMsg = tunnel.GetMsg();

                if (outMsg.Type == KAnpType.KANP_RES_FAIL)
                {
                    ResetToIdle();
                    Misc.KwmTellUser(outMsg.Elements[1].String);
                    return;
                }

                Debug.Assert(outMsg.Type == KAnpType.KANP_RES_OK);

                AnpMsg startSession = Helper.NewKAnpMsg(KAnpType.KANP_CMD_VNC_CONNECT_SESSION);
                startSession.AddBin(m_ticket);
                tunnel.SendMsg(startSession);
                outMsg = tunnel.GetMsg();

                if (outMsg.Type == KAnpType.KANP_RES_FAIL)
                {
                    ResetToIdle();
                    Misc.KwmTellUser(outMsg.Elements[1].String);
                    return;
                }

                Debug.Assert(outMsg.Type == KAnpType.KANP_RES_OK);

                Logging.Log("About to call disconnect");
                tunnel.Disconnect();
                CurrentState = AppSharingState.Connected;
            }
            else if (res.Type == KAnpType.KANP_RES_FAIL)
            {
                ResetToIdle();
                Misc.KwmTellUser(res.Elements[1].String);
            }
            else
            {
                Logging.Log("unexpected response in OnConnectTicketResponse");
            }
        }
Example #8
0
        /// <summary>
        /// Callback when one of our child processes (VNC client or server) die.
        /// </summary>
        private void HandleOnProcessEnd(object _sender, EventArgs _args)
        {
            if (Misc.MainForm.InvokeRequired)
            {
                Misc.MainForm.BeginInvoke(new EventHandler(HandleOnProcessEnd), new object[] { _sender, _args });
                return;
            }

            RawProcess.ProcEndEventArgs args = (RawProcess.ProcEndEventArgs)_args;
            RawProcess process = (RawProcess)_sender;
            if (process == m_dummyServerProcess)
            {
                Logging.Log("m_dummyServerProcess exited: " + args.ExitCode);
                m_dummyServerProcess = null;
            }
            else if (process == m_serverProcess)
            {
                Logging.Log("m_serverProcess exited");
                // Do not change our CurrentState here: we will catch the
                // SessionEnd event sometime.
                m_serverProcess = null;
            }
            else if (process == m_viewerProcess)
            {
                Logging.Log("m_viewerProcess exited");
                CurrentState = AppSharingState.Idle;
                m_viewerProcess = null;
            }
            else
            {
                Logging.Log("Unknown process exited! (" + process.CommandLine + ")");
            }
        }