Пример #1
0
        /// <summary>
        /// Connects to update service (opens named pipe stream).
        /// </summary>
        /// <returns>True on success, false on failure.</returns>
        private bool doConnectToService()
        {
            DateTime  startTime = DateTime.Now;
            Exception connectEx = null;

            while (DateTime.Now.Subtract(startTime).TotalMilliseconds < Magic.ServicePipeTimeoutMsec)
            {
                try
                {
                    pstream = new NamedPipeStream(@"\\.\pipe\" + Magic.ServiceShortName, FileAccess.ReadWrite);
                    break;
                }
                catch (Exception ex)
                {
                    connectEx = ex;
                    FileLogger.Instance.LogInfo("Failed to connect to named pipe; retrying in 0.5 sec.");
                }
                Thread.Sleep(500);
            }
            if (pstream == null)
            {
                FileLogger.Instance.LogError(connectEx, "Gave up trying to connect to named pipe; last exception below.");
                return(false);
            }
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Reads local path of installer, and its EXE signature, from named pipe.
        /// </summary>
        private static void doReadRequest(NamedPipeStream pstream, out string fname, out string fhash)
        {
            // Buffer to hold a long integer.
            byte[] longBuf = new byte[4];

            // Reading EXE Path length
            Helper.ForceReadBytes(pstream, ref longBuf, longBuf.Length);
            uint strlen = Helper.DeserializeUInt32(longBuf);

            if (strlen > 4096)
            {
                throw new Exception("Way too much info: " + strlen + " bytes.");
            }

            // Deserializing EXE Path
            byte[] strbuf = new byte[strlen];
            Helper.ForceReadBytes(pstream, ref strbuf, strbuf.Length);
            fname = Encoding.Unicode.GetString(strbuf);

            // Reading binary hash length
            Helper.ForceReadBytes(pstream, ref longBuf, longBuf.Length);
            strlen = Helper.DeserializeUInt32(longBuf);
            if (strlen > 4096)
            {
                throw new Exception("Way too much info: " + strlen + " bytes.");
            }

            // Deserializing binary hash
            strbuf = new byte[strlen];
            Helper.ForceReadBytes(pstream, ref strbuf, strbuf.Length);
            fhash = Encoding.Unicode.GetString(strbuf);
        }
Пример #3
0
        /// <summary>
        /// Create a named pipe instance.
        /// </summary>
        /// <param name="pipeName">Local name (the part after \\.\pipe\)</param>
        public static NamedPipeStream Create(string pipeName, ServerMode mode, FileSecurity fileSec)
        {
            SECURITY_ATTRIBUTES pipeSecurity = new SECURITY_ATTRIBUTES();

            pipeSecurity.nLength = Marshal.SizeOf(pipeSecurity);
            byte[] src  = fileSec.GetSecurityDescriptorBinaryForm();
            IntPtr dest = Marshal.AllocHGlobal(src.Length);

            Marshal.Copy(src, 0, dest, src.Length);
            pipeSecurity.lpSecurityDescriptor = dest;
            IntPtr pipeSecPtr = Marshal.AllocHGlobal(pipeSecurity.nLength);

            Marshal.StructureToPtr(pipeSecurity, pipeSecPtr, true);

            IntPtr handle = IntPtr.Zero;
            string name   = @"\\.\pipe\" + pipeName;

            handle = CreateNamedPipe(
                name,
                (uint)mode, PIPE_TYPE_MESSAGE | PIPE_WAIT,
                PIPE_UNLIMITED_INSTANCES,
                0,    // outBuffer,
                1024, // inBuffer,
                NMPWAIT_WAIT_FOREVER,
                pipeSecPtr);
            if (handle == INVALID_HANDLE_VALUE)
            {
                throw new Win32Exception("Error creating named pipe " + name + " . Internal error: " + Marshal.GetLastWin32Error().ToString());
            }

            // Set members persistently...
            NamedPipeStream self = new NamedPipeStream();

            self._handle = handle;
            switch (mode)
            {
            case ServerMode.InboundOnly:
                self._mode = FileAccess.Read;
                break;

            case ServerMode.OutboundOnly:
                self._mode = FileAccess.Write;
                break;

            case ServerMode.Bidirectional:
                self._mode = FileAccess.ReadWrite;
                break;
            }
            return(self);
        }
Пример #4
0
        /// <summary>
        /// Waits a bit, then deletes name pipe's file. Ugly, but the only way to achieve a quasi-timeout.
        /// </summary>
        private static void doClosePipeAfterWaiting(object ctxt)
        {
            NamedPipeStream pstream = (NamedPipeStream)ctxt;

            Thread.Sleep(Magic.ServicePipeTimeoutMsec);
            lock (isConnectedLO)
            {
                // If still no connection has been made, kill named pipe now.
                if (isConnected == 0)
                {
                    // It doesn't get uglier than this. But it works.
                    // http://stackoverflow.com/questions/1353263/how-to-unblock-connectnamedpipe-and-readfile-c
                    DeleteFile(@"\\.\pipe\" + Magic.ServiceShortName);
                    isConnected = -1;
                }
            }
        }
Пример #5
0
 /// <summary>
 /// Waits for incoming connection over named pipe.
 /// </summary>
 /// <returns>True if connected, false if got tired of waiting.</returns>
 private static bool doListen(ref NamedPipeStream pstream)
 {
     ThreadPool.QueueUserWorkItem(doClosePipeAfterWaiting, pstream);
     // This call blocks. It will return in one of two ways:
     // 1: Client connected
     // 2: File was deleted
     // Both return true :(
     pstream.Listen();
     lock (isConnectedLO)
     {
         // -1 value here means thread killed the named pipe.
         if (isConnected == -1)
         {
             pstream.Dispose();
             pstream = null;
             return(false);
         }
         // Tell thread not to kill named pipe now
         isConnected = 1;
         return(true);
     }
 }
Пример #6
0
        /// <summary>
        /// Runs as LOCAL SYSTEM from temp path; receives info from updater UI; checks package; executes installer.
        /// </summary>
        public static void Work()
        {
            // The service pipe we're listening through.
            NamedPipeStream pstream = null;

            try
            {
                // Create service pipe
                FileLogger.Instance.LogInfo("Creating named pipe.");
                FileSecurity pipeSecurity = new FileSecurity();
                pipeSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier("S-1-5-11"), FileSystemRights.FullControl, AccessControlType.Allow));
                pstream = NamedPipeStream.Create(Magic.ServiceShortName, NamedPipeStream.ServerMode.Bidirectional, pipeSecurity);

                // Wait for client (updater UI) to connect; but not too long.
                FileLogger.Instance.LogInfo("Waiting for client to connect.");
                if (!doListen(ref pstream))
                {
                    throw new Exception("Client didn't show up; tired of waiting.");
                }
                FileLogger.Instance.LogInfo("Client connected, reading paths and hash.");

                // Read location of downloaded installer and its file hash.
                string fname, fhash;
                doReadRequest(pstream, out fname, out fhash);

                // Verify signature
                FileLogger.Instance.LogInfo("Info received; verifying signature.");
                if (!SignatureCheck.VerifySignature(new FileInfo(fname), fhash))
                {
                    throw new Exception("Signature incorrect.");
                }
                FileLogger.Instance.LogInfo("Installer signature OK; launching installer");

                // Let caller know we've started installer
                pstream.WriteByte(Magic.SrvCodeInstallStarted);

                // Launch installer
                int exitCode = doRunInstaller(fname);
                FileLogger.Instance.LogInfo("Installer returned exit code " + exitCode.ToString());

                // Exit code 1 is failure
                if (exitCode == 1)
                {
                    throw new Exception("Installer failed.");
                }

                // We've succeeded; let caller know.
                pstream.WriteByte(Magic.SrvCodeSuccess);
                FileLogger.Instance.LogInfo("Finished with success; quitting.");
            }
            catch
            {
                // Upon error, return failure code to caller.
                if (pstream != null)
                {
                    try { pstream.WriteByte(Magic.SrvCodeFail); }
                    catch { }
                }
                throw;
            }
            finally
            {
                // Close & dispose of service pipe before we exit left.
                if (pstream != null)
                {
                    try
                    {
                        pstream.Close();
                        pstream.Dispose();
                        pstream = null;
                    }
                    catch { }
                }
            }
        }