OSDN Git Service

* autoload.cc (GetNamedPipeClientProcessId): Define.
authorcorinna <corinna>
Mon, 19 Apr 2010 19:52:42 +0000 (19:52 +0000)
committercorinna <corinna>
Mon, 19 Apr 2010 19:52:42 +0000 (19:52 +0000)
* fhandler.h (fhandler_tty_slave::fch_open_handles): Declare private.
(fhandler_tty_slave::fch_close_handles): Ditto.
(fhandler_tty_slave::cygserver_attach_tty): Drop declaration.
(fhandler_tty_slave::fstat): Declare public.
(fhandler_tty_slave::fchmod): Declare public.
(fhandler_tty_slave::fchown): Declare public.
(class fhandler_pty_master): Add master_ctl handle.
(fhandler_pty_master::pty_master_thread): Declare public.
* fhandler_termios.cc (fhandler_termios::tcinit): If the process
is started from a non-Cygwin process, make it tty process group
leader.
* fhandler_tty.cc: Throughout accommodate additional security related
arguments in calls to functions creating or opening objects.
(close_maybe): Move to start of file to reuse it
in other methods.
(struct pipe_request): Define.
(struct pipe_reply): Define.
(fhandler_tty_slave::open): Throughout, try to open synchronization
objects with MAXIMUM_ALLOWED permissions.  Drop call to cygserver.
Try to duplicate pipe handles via master_ctl pipe if duplicating
directly doesn't work.
(fhandler_tty_slave::cygserver_attach_tty): Remove.
(fhandler_tty_slave::init): Close unused incoming pipe handle.
(fhandler_pty_master::close): Send exit message to master control
thread and close master_ctl handle.
(fhandler_pty_master::pty_master_thread): New method, implementing the
master control thread.
(pty_master_thread): Static helper to start master control thread.
(fhandler_pty_master::setup): Simplify creating pipe inheritance.
Make sure we're the one creating the input_available_event.  Add
comment to explain why.  Create master_ctl pipe and start master
control thread.  Close master_ctl handle in case of error.
* security.cc (alloc_sd): Add code to handle tty objects.  Add comments
to explain what exactly is required.
(get_object_sd): New function.
(get_object_attribute): New function.
(create_object_sd_from_attribute): New function.
(set_object_sd): New function.
(set_object_attribute): New function.
(set_file_attribute): Change attribute type to mode_t.
* security.h (set_file_attribute): Change attribute type to mode_t.
(get_object_sd): Declare.
(get_object_attribute): Declare.
(create_object_sd_from_attribute): Declare.
(set_object_sd): Declare.
(set_object_attribute): Declare.
* tty.cc (tty::slave_alive): Implement directly instead of via alive.
(tty::exists): Open mutex handle with READ_CONTROL access.
(tty::alive): Remove.
(tty::open_output_mutex): Convert to inline method.
(tty::open_input_mutex): Ditto.
(tty::open_mutex): Take additional ACCESS_MASK parameter for the
mutex open access mask.
(tty::open_inuse): New method.
(tty::create_inuse): Take PSECURITY_ATTRIBUTES parameter.  Drop fmt
name parameter.  Always create TTY_SLAVE_ALIVE event.
(tty::get_event): Take additional PSECURITY_ATTRIBUTES parameter for
CreateEvent.
* tty.h (class tty): Change declarations according to aforementioned
changes.
(tty::open_output_mutex): Implement as inline method.
(tty::open_input_mutex): Ditto.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_termios.cc
winsup/cygwin/fhandler_tty.cc
winsup/cygwin/security.cc
winsup/cygwin/security.h
winsup/cygwin/tty.cc
winsup/cygwin/tty.h

index 68334b3..f1e3b7b 100644 (file)
@@ -1,5 +1,71 @@
 2010-04-19  Corinna Vinschen  <corinna@vinschen.de>
 
+       * autoload.cc (GetNamedPipeClientProcessId): Define.
+       * fhandler.h (fhandler_tty_slave::fch_open_handles): Declare private.
+       (fhandler_tty_slave::fch_close_handles): Ditto.
+       (fhandler_tty_slave::cygserver_attach_tty): Drop declaration.
+       (fhandler_tty_slave::fstat): Declare public.
+       (fhandler_tty_slave::fchmod): Declare public.
+       (fhandler_tty_slave::fchown): Declare public.
+       (class fhandler_pty_master): Add master_ctl handle.
+       (fhandler_pty_master::pty_master_thread): Declare public.
+       * fhandler_termios.cc (fhandler_termios::tcinit): If the process
+       is started from a non-Cygwin process, make it tty process group
+       leader.
+       * fhandler_tty.cc: Throughout accommodate additional security related
+       arguments in calls to functions creating or opening objects.
+       (close_maybe): Move to start of file to reuse it
+       in other methods.
+       (struct pipe_request): Define.
+       (struct pipe_reply): Define.
+       (fhandler_tty_slave::open): Throughout, try to open synchronization
+       objects with MAXIMUM_ALLOWED permissions.  Drop call to cygserver.
+       Try to duplicate pipe handles via master_ctl pipe if duplicating
+       directly doesn't work.
+       (fhandler_tty_slave::cygserver_attach_tty): Remove.
+       (fhandler_tty_slave::init): Close unused incoming pipe handle.
+       (fhandler_pty_master::close): Send exit message to master control
+       thread and close master_ctl handle.
+       (fhandler_pty_master::pty_master_thread): New method, implementing the
+       master control thread.
+       (pty_master_thread): Static helper to start master control thread.
+       (fhandler_pty_master::setup): Simplify creating pipe inheritance.
+       Make sure we're the one creating the input_available_event.  Add
+       comment to explain why.  Create master_ctl pipe and start master
+       control thread.  Close master_ctl handle in case of error.
+       * security.cc (alloc_sd): Add code to handle tty objects.  Add comments
+       to explain what exactly is required.
+       (get_object_sd): New function.
+       (get_object_attribute): New function.
+       (create_object_sd_from_attribute): New function.
+       (set_object_sd): New function.
+       (set_object_attribute): New function.
+       (set_file_attribute): Change attribute type to mode_t.
+       * security.h (set_file_attribute): Change attribute type to mode_t.
+       (get_object_sd): Declare.
+       (get_object_attribute): Declare.
+       (create_object_sd_from_attribute): Declare.
+       (set_object_sd): Declare.
+       (set_object_attribute): Declare.
+       * tty.cc (tty::slave_alive): Implement directly instead of via alive.
+       (tty::exists): Open mutex handle with READ_CONTROL access.
+       (tty::alive): Remove.
+       (tty::open_output_mutex): Convert to inline method.
+       (tty::open_input_mutex): Ditto.
+       (tty::open_mutex): Take additional ACCESS_MASK parameter for the
+       mutex open access mask.
+       (tty::open_inuse): New method.
+       (tty::create_inuse): Take PSECURITY_ATTRIBUTES parameter.  Drop fmt
+       name parameter.  Always create TTY_SLAVE_ALIVE event.
+       (tty::get_event): Take additional PSECURITY_ATTRIBUTES parameter for
+       CreateEvent.
+       * tty.h (class tty): Change declarations according to aforementioned
+       changes.
+       (tty::open_output_mutex): Implement as inline method.
+       (tty::open_input_mutex): Ditto.
+
+2010-04-19  Corinna Vinschen  <corinna@vinschen.de>
+
        * dtable.cc (dtable::init_std_file_from_handle): Set dev to
        valid content for ptys.  Remove setting FILE_CREATE_PIPE_INSTANCE
        in access flags since it's not needed.  Set the access mask for
index f5bdade..67a93f9 100644 (file)
@@ -419,6 +419,7 @@ LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
 LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
 LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
 LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1)
+LoadDLLfuncEx (GetNamedPipeClientProcessId, 8, kernel32, 1)
 LoadDLLfuncEx (GetSystemWindowsDirectoryW, 8, kernel32, 1)
 LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1)
 LoadDLLfuncEx (GetSystemDEPPolicy, 0, kernel32, 1)
index cf9d7b9..1255a3f 100644 (file)
@@ -1089,6 +1089,12 @@ class fhandler_tty_common: public fhandler_termios
 class fhandler_tty_slave: public fhandler_tty_common
 {
   HANDLE inuse;                        // used to indicate that a tty is in use
+
+  /* Helper functions for fchmod and fchown. */
+  bool fch_open_handles ();
+  int fch_set_sd (security_descriptor &sd, bool chown);
+  void fch_close_handles ();
+
  public:
   /* Constructor */
   fhandler_tty_slave ();
@@ -1108,14 +1114,18 @@ class fhandler_tty_slave: public fhandler_tty_common
   void fixup_after_exec ();
 
   select_record *select_read (select_stuff *);
-  int cygserver_attach_tty (HANDLE*, HANDLE*);
   int get_unit ();
   virtual char const *ttyname () { return pc.dev.name; }
+  int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+  int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
+  int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
 };
 
 class fhandler_pty_master: public fhandler_tty_common
 {
   int pktmode;                 // non-zero if pty in a packet mode.
+  HANDLE master_ctl;           // Control socket for handle duplication
+
 public:
   int need_nl;                 // Next read should start with \n
   DWORD dwProcessId;           // Owner of master handles
@@ -1123,6 +1133,7 @@ public:
   /* Constructor */
   fhandler_pty_master ();
 
+  DWORD pty_master_thread ();
   int process_slave_output (char *buf, size_t len, int pktmode_on);
   void doecho (const void *str, DWORD len);
   int accept_input ();
index b5d9f2e..b7f7860 100644 (file)
@@ -58,6 +58,13 @@ fhandler_termios::tcinit (tty_min *this_tc, bool force)
       tc->pgid = myself->pgid;
       tc->initialized (true);
     }
+  else if (myself->ppid == 1 && myself->pid == myself->pgid
+          && myself->pgid == myself->sid)
+    /* We have been started from a non-Cygwin process. So we just become
+       tty process group leader.
+       TODO: Investigate how SIGTTIN should be handled with pure-windows
+       programs. */
+    tc->pgid = myself->pgid;
 }
 
 int
index 30b6dda..b95bd5f 100644 (file)
@@ -19,12 +19,29 @@ details. */
 #include "dtable.h"
 #include "sigproc.h"
 #include "pinfo.h"
+#include "ntdll.h"
 #include "cygheap.h"
 #include "shared_info.h"
-#include "cygserver.h"
 #include "cygthread.h"
 #include "child_info.h"
 
+#define close_maybe(h) \
+  do { \
+    if (h && h != INVALID_HANDLE_VALUE) \
+      CloseHandle (h); \
+  } while (0)
+
+/* pty master control pipe messages */
+struct pipe_request {
+  DWORD pid;
+};
+
+struct pipe_reply {
+  HANDLE from_master;
+  HANDLE to_master;
+  DWORD error;
+};
+
 /* tty master stuff */
 
 fhandler_tty_master NO_COPY *tty_master;
@@ -490,20 +507,20 @@ fhandler_tty_slave::open (int flags, mode_t)
      pty opened by fhandler_pty_master::open.  In the former case, tty
      output is handled by a separate thread which controls output.  */
   shared_name (buf, OUTPUT_DONE_EVENT, get_unit ());
-  output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+  output_done_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
 
-  if (!(output_mutex = get_ttyp ()->open_output_mutex ()))
+  if (!(output_mutex = get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED)))
     {
       errmsg = "open output mutex failed, %E";
       goto err;
     }
-  if (!(input_mutex = get_ttyp ()->open_input_mutex ()))
+  if (!(input_mutex = get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED)))
     {
       errmsg = "open input mutex failed, %E";
       goto err;
     }
   shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
-  if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf)))
+  if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf)))
     {
       errmsg = "open input event failed, %E";
       goto err;
@@ -512,14 +529,23 @@ fhandler_tty_slave::open (int flags, mode_t)
   /* The ioctl events may or may not exist.  See output_done_event,
      above.  */
   shared_name (buf, IOCTL_REQUEST_EVENT, get_unit ());
-  ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+  ioctl_request_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
   shared_name (buf, IOCTL_DONE_EVENT, get_unit ());
-  ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf);
+  ioctl_done_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
 
   /* FIXME: Needs a method to eliminate tty races */
   {
+    /* Create security attribute.  Default permissions are 0620. */
+    security_descriptor sd;
+    sd.malloc (sizeof (SECURITY_DESCRIPTOR));
+    InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
+    SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
+    if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid,
+                                         S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
+                                         sd))
+      sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
     acquire_output_mutex (500);
-    inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE);
+    inuse = get_ttyp ()->create_inuse (&sa);
     get_ttyp ()->was_opened = true;
     release_output_mutex ();
   }
@@ -531,43 +557,40 @@ fhandler_tty_slave::open (int flags, mode_t)
       goto err_no_errno;
     }
 
-  if (myself->pid == get_ttyp ()->master_pid
-      || cygserver_running == CYGSERVER_UNAVAIL
-      || !cygserver_attach_tty (&from_master_local, &to_master_local))
+  if (get_ttyp ()->master_pid < 0)
+    {
+      errmsg = "*** master is closed";
+      set_errno (EAGAIN);
+      goto err_no_errno;
+    }
+  /* Three case for duplicating the pipe handles:
+     - Either we're the master.  In this case, just duplicate the handles.
+     - Or, we have the right to open the master process for handle duplication.
+       In this case, just duplicate the handles.
+     - Or, we have to ask the master process itself.  In this case, send our
+       pid to the master process and check the reply.  The reply contains
+       either the handles, or an error code which tells us why we didn't
+       get the handles. */
+  if (myself->pid == get_ttyp ()->master_pid)
+    {
+      /* This is the most common case, just calling openpty. */
+      termios_printf ("dup handles within myself.");
+      tty_owner = GetCurrentProcess ();
+    }
+  else
     {
-      if (get_ttyp ()->master_pid < 0)
-       {
-         errmsg = "*** master is closed";
-         set_errno (EAGAIN);
-         goto err_no_errno;
-       }
       pinfo p (get_ttyp ()->master_pid);
       if (!p)
-       {
-         errmsg = "*** couldn't find tty master";
-         set_errno (EAGAIN);
-         goto err_no_errno;
-       }
-      HANDLE tty_owner;
-      if (myself->pid == get_ttyp ()->master_pid)
-       {
-         /* This is the most common case, just calling openpty. */
-         termios_printf ("dup handles within myself.");
-         tty_owner = GetCurrentProcess ();
-       }
+       termios_printf ("*** couldn't find tty master");
       else
        {
-         termios_printf ("cannot dup handles via server. using old method.");
          tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
-         if (tty_owner == NULL)
-           {
-             termios_printf ("can't open tty (%d) handle process %d",
-                             get_unit (), get_ttyp ()->master_pid);
-             __seterrno ();
-             goto err_no_msg;
-           }
+         if (tty_owner)
+           termios_printf ("dup handles directly since I'm allmighty.");
        }
-
+    }
+  if (tty_owner)
+    {
       if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
                            GetCurrentProcess (), &from_master_local, 0, TRUE,
                            DUPLICATE_SAME_ACCESS))
@@ -577,8 +600,6 @@ fhandler_tty_slave::open (int flags, mode_t)
          __seterrno ();
          goto err_no_msg;
        }
-
-      VerifyHandle (from_master_local);
       if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
                          GetCurrentProcess (), &to_master_local, 0, TRUE,
                          DUPLICATE_SAME_ACCESS))
@@ -586,10 +607,35 @@ fhandler_tty_slave::open (int flags, mode_t)
          errmsg = "can't duplicate output, %E";
          goto err;
        }
-      VerifyHandle (to_master_local);
       if (tty_owner != GetCurrentProcess ())
        CloseHandle (tty_owner);
     }
+  else
+    {
+      pipe_request req = { GetCurrentProcessId () };
+      pipe_reply repl;
+      DWORD len;
+
+      __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
+                      &installation_key, get_unit ());
+      termios_printf ("dup handles via master control pipe %s", buf);
+      if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl,
+                         &len, 500))
+       {
+         errmsg = "can't call master, %E";
+         goto err;
+       }
+      from_master_local = repl.from_master;
+      to_master_local = repl.to_master;
+      if (!from_master_local || !to_master_local)
+       {
+         SetLastError (repl.error);
+         errmsg = "error duplicating pipes, %E";
+         goto err;
+       }
+    }
+  VerifyHandle (from_master_local);
+  VerifyHandle (to_master_local);
 
   termios_printf ("duplicated from_master %p->%p from tty_owner",
                  get_ttyp ()->from_master, from_master_local);
@@ -660,31 +706,7 @@ fhandler_tty_slave::close ()
 }
 
 int
-fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr,
-                                         LPHANDLE to_master_ptr)
-{
-  if (!from_master_ptr || !to_master_ptr)
-    return 0;
-
-  pinfo p (get_ttyp ()->master_pid);
-  if (!p)
-    return 0;
-
-  client_request_attach_tty req (p->dwProcessId,
-                                (HANDLE) get_ttyp ()->from_master,
-                                (HANDLE) get_ttyp ()->to_master);
-
-  if (req.make_request () == -1 || req.error_code ())
-    return 0;
-
-  *from_master_ptr = req.from_master ();
-  *to_master_ptr = req.to_master ();
-
-  return 1;
-}
-
-int
-fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
+fhandler_tty_slave::init (HANDLE f, DWORD a, mode_t)
 {
   int flags = 0;
 
@@ -696,7 +718,12 @@ fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
   if (a == (GENERIC_READ | GENERIC_WRITE))
     flags = O_RDWR;
 
-  return open (flags);
+  int ret = open (flags);
+
+  if (f != INVALID_HANDLE_VALUE)
+    CloseHandle (f);   /* Reopened by open */
+
+  return ret;
 }
 
 ssize_t __stdcall
@@ -1117,6 +1144,177 @@ out:
   return retval;
 }
 
+int __stdcall
+fhandler_tty_slave::fstat (struct __stat64 *st)
+{
+  fhandler_base::fstat (st);
+
+  bool to_close = false;
+  if (!input_available_event)
+    {
+      char buf[MAX_PATH];
+      shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
+      input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
+      if (input_available_event)
+       to_close = true;
+    }
+  if (!input_available_event
+      || get_object_attribute (input_available_event, &st->st_uid, &st->st_gid,
+                              &st->st_mode))
+    {
+      /* If we can't access the ACL, or if the tty doesn't actually exist,
+         then fake uid and gid to strict, system-like values. */
+      st->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
+      st->st_uid = 18;
+      st->st_gid = 544;
+    }
+  if (to_close)
+    CloseHandle (input_available_event);
+  return 0;
+}
+
+/* Helper function for fchmod and fchown, which just opens all handles
+   and signals success via bool return. */
+bool
+fhandler_tty_slave::fch_open_handles ()
+{
+  char buf[MAX_PATH];
+
+  tc = cygwin_shared->tty[get_unit ()];
+  shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
+  input_available_event = OpenEvent (READ_CONTROL | WRITE_DAC | WRITE_OWNER,
+                                    TRUE, buf);
+  output_mutex = get_ttyp ()->open_output_mutex (WRITE_DAC | WRITE_OWNER);
+  input_mutex = get_ttyp ()->open_input_mutex (WRITE_DAC | WRITE_OWNER);
+  inuse = get_ttyp ()->open_inuse (WRITE_DAC | WRITE_OWNER);
+  if (!input_available_event || !output_mutex || !input_mutex || !inuse)
+    {
+      __seterrno ();
+      return false;
+    }
+  /* These members are optional, no error checking */
+  shared_name (buf, OUTPUT_DONE_EVENT, get_unit ());
+  output_done_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
+  shared_name (buf, IOCTL_REQUEST_EVENT, get_unit ());
+  ioctl_request_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
+  shared_name (buf, IOCTL_DONE_EVENT, get_unit ());
+  ioctl_done_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
+  return true;
+}
+
+/* Helper function for fchmod and fchown, which sets the new security
+   descriptor on all objects representing the tty. */
+int
+fhandler_tty_slave::fch_set_sd (security_descriptor &sd, bool chown)
+{
+  security_descriptor sd_old;
+
+  get_object_sd (input_available_event, sd_old);
+  if (/*!set_object_sd (get_io_handle (), sd, chown)
+      && !set_object_sd (get_output_handle (), sd, chown)
+      && */ !set_object_sd (input_available_event, sd, chown)
+      && !set_object_sd (output_mutex, sd, chown)
+      && !set_object_sd (input_mutex, sd, chown)
+      && !set_object_sd (inuse, sd, chown)
+      && (!output_done_event
+         || !set_object_sd (output_done_event, sd, chown))
+      && (!ioctl_request_event
+         || !set_object_sd (ioctl_request_event, sd, chown))
+      && (!ioctl_done_event
+         || !set_object_sd (ioctl_done_event, sd, chown)))
+    return 0;
+  /*set_object_sd (get_io_handle (), sd_old, chown);
+  set_object_sd (get_output_handle (), sd_old, chown);*/
+  set_object_sd (input_available_event, sd_old, chown);
+  set_object_sd (output_mutex, sd_old, chown);
+  set_object_sd (input_mutex, sd_old, chown);
+  set_object_sd (inuse, sd_old, chown);
+  if (!output_done_event)
+      set_object_sd (output_done_event, sd_old, chown);
+  if (!ioctl_request_event)
+      set_object_sd (ioctl_request_event, sd_old, chown);
+  if (!ioctl_done_event)
+      set_object_sd (ioctl_done_event, sd_old, chown);
+  return -1;
+}
+
+/* Helper function for fchmod and fchown, which closes all object handles in
+   the tty. */
+void
+fhandler_tty_slave::fch_close_handles ()
+{
+  close_maybe (get_io_handle ());
+  close_maybe (get_output_handle ());
+  close_maybe (output_done_event);
+  close_maybe (ioctl_done_event);
+  close_maybe (ioctl_request_event);
+  close_maybe (input_available_event);
+  close_maybe (output_mutex);
+  close_maybe (input_mutex);
+  close_maybe (inuse);
+}
+
+int __stdcall
+fhandler_tty_slave::fchmod (mode_t mode)
+{
+  int ret = -1;
+  bool to_close = false;
+  security_descriptor sd;
+  __uid32_t uid;
+  __gid32_t gid;
+
+  if (!input_available_event)
+    {
+      to_close = true;
+      if (!fch_open_handles ())
+       goto errout;
+    }
+  sd.malloc (sizeof (SECURITY_DESCRIPTOR));
+  InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
+  if (!get_object_attribute (input_available_event, &uid, &gid, NULL)
+      && !create_object_sd_from_attribute (NULL, uid, gid, S_IFCHR | mode, sd))
+    ret = fch_set_sd (sd, false);
+errout:
+  if (to_close)
+    fch_close_handles ();
+  return ret;
+}
+
+int __stdcall
+fhandler_tty_slave::fchown (__uid32_t uid, __gid32_t gid)
+{
+  int ret = -1;
+  bool to_close = false;
+  mode_t mode;
+  __uid32_t o_uid;
+  __gid32_t o_gid;
+  security_descriptor sd;
+
+  if (uid == ILLEGAL_UID && gid == ILLEGAL_GID)
+    return 0;
+  if (!input_available_event)
+    {
+      to_close = true;
+      if (!fch_open_handles ())
+       goto errout;
+    }
+  sd.malloc (sizeof (SECURITY_DESCRIPTOR));
+  InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
+  if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode))
+    {
+      if ((uid == ILLEGAL_UID || uid == o_uid)
+         && (gid == ILLEGAL_GID || gid == o_gid))
+       ret = 0;
+      else if (!create_object_sd_from_attribute (input_available_event,
+                                                uid, gid, S_IFCHR | mode, sd))
+       ret = fch_set_sd (sd, true);
+    }
+errout:
+  if (to_close)
+    fch_close_handles ();
+  return ret;
+}
+
 /*******************************************************
  fhandler_pty_master
 */
@@ -1215,6 +1413,18 @@ fhandler_pty_master::close ()
                  arch->from_master, arch->to_master, arch->dwProcessId);
   if (cygwin_finished_initializing)
     {
+      if (arch->master_ctl && get_ttyp ()->master_pid == myself->pid)
+       {
+         char buf[MAX_PATH];
+         pipe_request req = { (DWORD) -1 };
+         pipe_reply repl;
+         DWORD len;
+
+         __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
+                          &installation_key, get_unit ());
+         CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, &len, 500);
+         CloseHandle (arch->master_ctl);
+       }
       if (!ForceCloseHandle (arch->from_master))
        termios_printf ("error closing from_master %p, %E", arch->from_master);
       if (!ForceCloseHandle (arch->to_master))
@@ -1361,16 +1571,154 @@ fhandler_tty_master::init_console ()
   return 0;
 }
 
-#define close_maybe(h) \
-  do { \
-    if (h && h != INVALID_HANDLE_VALUE) \
-      CloseHandle (h); \
-  } while (0)
+extern "C" BOOL WINAPI GetNamedPipeClientProcessId (HANDLE, PULONG);
+
+/* This thread function handles the master control pipe.  It waits for a
+   client to connect.  Then it checks if the client process has permissions
+   to access the tty handles.  If so, it opens the client process and
+   duplicates the handles into that process.  If that fails, it sends a reply
+   with at least one handle set to NULL and an error code.  Last but not
+   least, the client is disconnected and the thread waits for the next client.
+
+   A special case is when the master side of the tty is about to be closed.
+   The client side is the fhandler_pty_master::close function and it sends
+   a PID -1 in that case.  On Vista and later a check is performed that the
+   request to leave really comes from the master process itself.  On earlier
+   OSes there's no function to check for the PID of the client process so
+   we have to trust the client side.
+
+   Since there's
+   always only one pipe instance, there's a chance that clients have to
+   wait to connect to the master control pipe.  Therefore the client calls
+   to CallNamedPipe should have a big enough timeout value.  For now this
+   is 500ms.  Hope that's enough. */
+
+DWORD
+fhandler_pty_master::pty_master_thread ()
+{
+  bool exit = false;
+  GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0,
+                         EVENT_QUERY_STATE | EVENT_MODIFY_STATE };
+  pipe_request req;
+  DWORD len;
+  security_descriptor sd;
+  HANDLE token;
+  PRIVILEGE_SET ps;
+  BOOL ret;
+  DWORD pid;
+
+  termios_printf ("Entered");
+  while (!exit && ConnectNamedPipe (master_ctl, NULL))
+    {
+      pipe_reply repl = { NULL, NULL, 0 };
+      bool deimp = false;
+      BOOL allow = FALSE;
+      ACCESS_MASK access = EVENT_MODIFY_STATE;
+      HANDLE client = NULL;
+
+      if (!ReadFile (master_ctl, &req, sizeof req, &len, NULL))
+       {
+         termios_printf ("ReadFile, %E");
+         goto reply;
+       }
+      /* This function is only available since Vista, unfortunately.
+        In earlier OSes we simply have to believe that the client
+        has no malicious intent (== sends arbitrary PIDs). */
+      if (!GetNamedPipeClientProcessId (master_ctl, &pid))
+       pid = req.pid;
+      if (get_object_sd (input_available_event, sd))
+       {
+         termios_printf ("get_object_sd, %E");
+         goto reply;
+       }
+      cygheap->user.deimpersonate ();
+      deimp = true;
+      if (!ImpersonateNamedPipeClient (master_ctl))
+       {
+         termios_printf ("ImpersonateNamedPipeClient, %E");
+         goto reply;
+       }
+      if (!OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE, &token))
+       {
+         termios_printf ("OpenThreadToken, %E");
+         goto reply;
+       }
+      len = sizeof ps;
+      ret = AccessCheck (sd, token, access, &map, &ps, &len, &access, &allow);
+      CloseHandle (token);
+      if (!ret)
+       {
+         termios_printf ("AccessCheck, %E");
+         goto reply;
+       }
+      if (!RevertToSelf ())
+       {
+         termios_printf ("RevertToSelf, %E");
+         goto reply;
+       }
+      if (req.pid == (DWORD) -1)       /* Request to finish thread. */
+       {
+         /* Pre-Vista: Just believe in the good of the client process.
+            Post-Vista: Check if the requesting process is the master
+            process itself. */
+         if (pid == (DWORD) -1 || pid == GetCurrentProcessId ())
+           exit = true;
+         goto reply;
+       }
+      if (allow)
+       {
+         client = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
+         if (!client)
+           {
+             termios_printf ("OpenProcess, %E");
+             goto reply;
+           }
+         if (!DuplicateHandle (GetCurrentProcess (), from_master,
+                              client, &repl.from_master,
+                              0, TRUE, DUPLICATE_SAME_ACCESS))
+           {
+             termios_printf ("DuplicateHandle (from_master), %E");
+             goto reply;
+           }
+         if (!DuplicateHandle (GetCurrentProcess (), to_master,
+                               client, &repl.to_master,
+                               0, TRUE, DUPLICATE_SAME_ACCESS))
+           {
+             termios_printf ("DuplicateHandle (to_master), %E");
+             goto reply;
+           }
+       }
+reply:
+      repl.error = GetLastError ();
+      if (client)
+       CloseHandle (client);
+      if (deimp)
+       cygheap->user.reimpersonate ();
+      sd.free ();
+      termios_printf ("Reply: from %p, to %p, error %lu",
+                     repl.from_master, repl.to_master, repl.error );
+      if (!WriteFile (master_ctl, &repl, sizeof repl, &len, NULL))
+       termios_printf ("WriteFile, %E");
+      if (!DisconnectNamedPipe (master_ctl))
+       termios_printf ("DisconnectNamedPipe, %E");
+    }
+  termios_printf ("Leaving");
+  return 0;
+}
+
+static DWORD WINAPI
+pty_master_thread (VOID *arg)           
+{ 
+  return ((fhandler_pty_master *) arg)->pty_master_thread ();
+} 
 
 bool
 fhandler_pty_master::setup (bool ispty)
 {
   int res;
+  security_descriptor sd;
+  SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
+
   tty& t = *cygwin_shared->tty[get_unit ()];
 
   tcinit (&t, true);           /* Set termios information.  Force initialization. */
@@ -1379,78 +1727,97 @@ fhandler_pty_master::setup (bool ispty)
   DWORD pipe_mode = PIPE_NOWAIT;
 
   /* Create communication pipes */
-
   char pipename[sizeof("ttyNNNN-from-master")];
   __small_sprintf (pipename, "tty%d-from-master", get_unit ());
-  res = fhandler_pipe::create_selectable (&sec_none_nih, from_master,
-                                         get_output_handle (), 128 * 1024,
-                                         pipename);
+  res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
+                                         from_master, get_output_handle (),
+                                         128 * 1024, pipename);
   if (res)
     {
       errstr = "input pipe";
       goto err;
     }
-  /* Only ptys should create inheritable handles by default.  ttys are
-     parcelled out on an as-needed basis and handle inheritance differently. */
-  if (ispty && !SetHandleInformation (get_output_handle (), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
-    {
-      errstr = "inheritable get_output_handle ()";
-      goto err;
-    }
 
   if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL))
     termios_printf ("can't set output_handle(%p) to non-blocking mode",
                    get_output_handle ());
 
   __small_sprintf (pipename, "tty%d-to-master", get_unit ());
-  res = fhandler_pipe::create_selectable (&sec_none_nih, get_io_handle (),
-                                         to_master, 128 * 1024, pipename);
+  res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
+                                         get_io_handle (), to_master,
+                                         128 * 1024, pipename);
   if (res)
     {
       errstr = "output pipe";
       goto err;
     }
-  /* Only ptys should create inheritable handles by default.  ttys are
-     parcelled out on an as-needed basis and handle inheritance differently. */
-  if (ispty && !SetHandleInformation (get_io_handle (), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
-    {
-      errstr = "inheritable get_io_handle ()";
-      goto err;
-    }
 
   need_nl = 0;
 
-  /* We do not allow others to open us (for handle duplication)
-     but rely on cygheap->inherited_ctty for descendant processes.
-     In the future the cygserver may allow access by others. */
-
-  if (cygserver_running == CYGSERVER_UNKNOWN)
-    cygserver_init ();
+  /* Create security attribute.  Default permissions are 0620. */
+  sd.malloc (sizeof (SECURITY_DESCRIPTOR));
+  InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
+  if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid,
+                                       S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
+                                       sd))
+    sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
 
   /* Create synchronisation events */
 
   if (!ispty)
     {
-      if (!(output_done_event = t.get_event (errstr = OUTPUT_DONE_EVENT)))
+      if (!(output_done_event = t.get_event (errstr = OUTPUT_DONE_EVENT, &sa)))
        goto err;
-      if (!(ioctl_done_event = t.get_event (errstr = IOCTL_DONE_EVENT)))
+      if (!(ioctl_done_event = t.get_event (errstr = IOCTL_DONE_EVENT, &sa)))
        goto err;
-      if (!(ioctl_request_event = t.get_event (errstr = IOCTL_REQUEST_EVENT)))
+      if (!(ioctl_request_event = t.get_event (errstr = IOCTL_REQUEST_EVENT,
+                                              &sa)))
        goto err;
     }
 
-  if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT, TRUE)))
+  /* Carefully check that the input_available_event didn't already exist.
+     This is a measure to make sure that the event security descriptor
+     isn't occupied by a malicious process.  We must make sure that the
+     event's security descriptor is what we expect it to be. */
+  if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT,
+                                            &sa, TRUE))
+      || GetLastError () == ERROR_ALREADY_EXISTS)
     goto err;
 
   char buf[MAX_PATH];
   errstr = shared_name (buf, OUTPUT_MUTEX, t.ntty);
-  if (!(output_mutex = CreateMutex (&sec_all, FALSE, buf)))
+  if (!(output_mutex = CreateMutex (&sa, FALSE, buf)))
     goto err;
 
   errstr = shared_name (buf, INPUT_MUTEX, t.ntty);
-  if (!(input_mutex = CreateMutex (&sec_all, FALSE, buf)))
+  if (!(input_mutex = CreateMutex (&sa, FALSE, buf)))
     goto err;
 
+  if (ispty)
+    {
+      /* Create master control pipe which allows the master to duplicate
+        the pty pipe handles to processes which deserve it. */
+      cygthread *h;
+      __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
+                      &installation_key, get_unit ());
+      master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX,
+                                   PIPE_WAIT | PIPE_TYPE_MESSAGE
+                                   | PIPE_READMODE_MESSAGE, 1, 4096, 4096,
+                                   0, &sec_all_nih);
+      if (master_ctl == INVALID_HANDLE_VALUE)
+       {
+         errstr = "pty master control pipe";
+         goto err;
+       }
+      h = new cygthread (::pty_master_thread, 0, this, "pty_master");
+      if (!h)
+       {
+         errstr = "pty master control thread";
+         goto err;
+       }
+      h->zap_h ();
+    }
+
   t.from_master = from_master;
   t.to_master = to_master;
   // /* screws up tty master */ ProtectHandle1INH (output_mutex, output_mutex);
@@ -1475,6 +1842,7 @@ err:
   close_maybe (input_mutex);
   close_maybe (from_master);
   close_maybe (to_master);
+  close_maybe (master_ctl);
   termios_printf ("tty%d open failed - failed to create %s", errstr);
   return false;
 }
index b09a719..c180197 100644 (file)
@@ -1,7 +1,7 @@
 /* security.cc: NT file access control functions
 
    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008, 2009 Red Hat, Inc.
+   2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
 
    Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
    Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
@@ -464,6 +464,10 @@ alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute,
   /* From here fill ACL. */
   size_t acl_len = sizeof (ACL);
   int ace_off = 0;
+  /* Only used for sync objects (for ttys).  The admins group should
+     always have the right to manipulate the ACL, so we have to make sure
+     that the ACL gives the admins group STANDARD_RIGHTS_ALL access. */
+  bool saw_admins = false;
 
   /* Construct allow attribute for owner.
      Don't set FILE_READ/WRITE_ATTRIBUTES unconditionally on Samba, otherwise
@@ -480,9 +484,12 @@ alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute,
   if (S_ISDIR (attribute)
       && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR))
     owner_allow |= FILE_DELETE_CHILD;
+  /* For sync objects note that the owner is admin. */
+  if (S_ISCHR (attribute) && owner_sid == well_known_admins_sid)
+    saw_admins = true;
 
   /* Construct allow attribute for group. */
-  DWORD group_allow = STANDARD_RIGHTS_READ
+  DWORD group_allow = STANDARD_RIGHTS_READ | SYNCHRONIZE
                      | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
   if (attribute & S_IRGRP)
     group_allow |= FILE_GENERIC_READ;
@@ -494,9 +501,15 @@ alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute,
       && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP)
       && !(attribute & S_ISVTX))
     group_allow |= FILE_DELETE_CHILD;
+  /* For sync objects, add STANDARD_RIGHTS_ALL for admins group. */
+  if (S_ISCHR (attribute) && group_sid == well_known_admins_sid)
+    {
+      group_allow |= STANDARD_RIGHTS_ALL;
+      saw_admins = true;
+    }
 
   /* Construct allow attribute for everyone. */
-  DWORD other_allow = STANDARD_RIGHTS_READ
+  DWORD other_allow = STANDARD_RIGHTS_READ | SYNCHRONIZE
                      | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
   if (attribute & S_IROTH)
     other_allow |= FILE_GENERIC_READ;
@@ -560,6 +573,17 @@ alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute,
                                  group_sid, acl_len, NO_INHERITANCE))
     return NULL;
 
+  /* For sync objects, if we didn't see the admins group so far, add entry
+     with STANDARD_RIGHTS_ALL access. */
+  if (S_ISCHR (attribute) && !saw_admins)
+    {
+      if (!add_access_allowed_ace (acl, ace_off++, STANDARD_RIGHTS_ALL,
+                                  well_known_admins_sid, acl_len,
+                                  NO_INHERITANCE))
+       return NULL;
+      saw_admins = true;
+    }
+
   /* Set allow ACE for everyone. */
   if (!add_access_allowed_ace (acl, ace_off++, other_allow,
                               well_known_world_sid, acl_len, NO_INHERITANCE))
@@ -582,7 +606,8 @@ alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute,
          cygpsid ace_sid ((PSID) &ace->SidStart);
 
          /* Check for related ACEs. */
-         if (ace_sid == well_known_null_sid)
+         if (ace_sid == well_known_null_sid
+             || (S_ISCHR (attribute) && ace_sid == well_known_admins_sid))
            continue;
          if ((ace_sid == cur_owner_sid)
              || (ace_sid == owner_sid)
@@ -717,8 +742,85 @@ set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa,
 }
 
 int
+get_object_sd (HANDLE handle, security_descriptor &sd)
+{
+  ULONG len = 0;
+  NTSTATUS status;
+
+  status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
+                                 sd, len, &len);
+  if (status != STATUS_BUFFER_TOO_SMALL)
+    {
+      __seterrno_from_nt_status (status);
+      return -1;
+    }
+  if (!sd.malloc (len))
+    {
+      set_errno (ENOMEM);
+      return -1;
+    }
+  status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
+                                 sd, len, &len);
+  if (!NT_SUCCESS (status))
+    {
+      __seterrno_from_nt_status (status);
+      return -1;
+    }
+  return 0;
+}
+
+int
+get_object_attribute (HANDLE handle, __uid32_t *uidret, __gid32_t *gidret,
+                     mode_t *attribute)
+{
+  security_descriptor sd;
+
+  if (get_object_sd (handle, sd))
+    return -1;
+  get_info_from_sd (sd, attribute, uidret, gidret);
+  return 0;
+}
+
+int
+create_object_sd_from_attribute (HANDLE handle, __uid32_t uid, __gid32_t gid,
+                                mode_t attribute, security_descriptor &sd)
+{
+  path_conv pc;
+  if ((handle && get_object_sd (handle, sd))
+      || !alloc_sd (pc, uid, gid, attribute, sd))
+    return -1;
+  return 0;
+}
+
+int
+set_object_sd (HANDLE handle, security_descriptor &sd, bool chown)
+{
+  NTSTATUS status;
+  status = NtSetSecurityObject (handle, chown ? ALL_SECURITY_INFORMATION
+                                             : DACL_SECURITY_INFORMATION, sd);
+  if (!NT_SUCCESS (status))
+    {
+      __seterrno_from_nt_status (status);
+      return -1;
+    }
+  return 0;
+}
+
+int
+set_object_attribute (HANDLE handle, __uid32_t uid, __gid32_t gid,
+                     mode_t attribute)
+{
+  security_descriptor sd;
+
+  if (create_object_sd_from_attribute (handle, uid, gid, attribute, sd)
+      || set_object_sd (handle, sd, uid != ILLEGAL_UID || gid != ILLEGAL_GID))
+    return -1;
+  return 0;
+}
+
+int
 set_file_attribute (HANDLE handle, path_conv &pc,
-                   __uid32_t uid, __gid32_t gid, int attribute)
+                   __uid32_t uid, __gid32_t gid, mode_t attribute)
 {
   int ret = -1;
 
index dcc080f..dde4d21 100644 (file)
@@ -350,7 +350,14 @@ class path_conv;
 int __stdcall get_file_attribute (HANDLE, path_conv &, mode_t *,
                                  __uid32_t *, __gid32_t *);
 int __stdcall set_file_attribute (HANDLE, path_conv &,
-                                 __uid32_t, __gid32_t, int);
+                                 __uid32_t, __gid32_t, mode_t);
+int __stdcall get_object_sd (HANDLE, security_descriptor &);
+int __stdcall get_object_attribute (HANDLE, __uid32_t *, __gid32_t *, mode_t *);
+int __stdcall set_object_attribute (HANDLE, __uid32_t, __gid32_t, mode_t);
+int __stdcall create_object_sd_from_attribute (HANDLE, __uid32_t, __gid32_t,
+                                              mode_t, security_descriptor &);
+int __stdcall set_object_sd (HANDLE, security_descriptor &, bool);
+
 int __stdcall get_reg_attribute (HKEY hkey, mode_t *, __uid32_t *, __gid32_t *);
 LONG __stdcall get_file_sd (HANDLE fh, path_conv &, security_descriptor &sd);
 LONG __stdcall set_file_sd (HANDLE fh, path_conv &, security_descriptor &sd,
index e701810..0991cd6 100644 (file)
@@ -1,7 +1,7 @@
 /* tty.cc
 
-   Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009
-   Red Hat, Inc.
+   Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009,
+   2010 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -287,12 +287,6 @@ out:
 }
 
 bool
-tty::slave_alive ()
-{
-  return alive (TTY_SLAVE_ALIVE);
-}
-
-bool
 tty::exists ()
 {
   /* Attempt to open the from-master side of the tty.  If it is accessible
@@ -307,7 +301,7 @@ tty::exists ()
   CloseHandle (r);
   CloseHandle (w);
 
-  HANDLE h = open_output_mutex ();
+  HANDLE h = open_output_mutex (READ_CONTROL);
   if (h)
     {
       CloseHandle (h);
@@ -317,45 +311,38 @@ tty::exists ()
 }
 
 bool
-tty::alive (const char *fmt)
+tty::slave_alive ()
 {
   HANDLE ev;
-  char buf[MAX_PATH];
-
-  shared_name (buf, fmt, ntty);
-  if ((ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf)))
+  if ((ev = open_inuse (READ_CONTROL)))
     CloseHandle (ev);
   return ev != NULL;
 }
 
 HANDLE
-tty::open_output_mutex ()
+tty::open_mutex (const char *mutex, ACCESS_MASK access)
 {
-  return open_mutex (OUTPUT_MUTEX);
-}
-
-HANDLE
-tty::open_input_mutex ()
-{
-  return open_mutex (INPUT_MUTEX);
+  char buf[MAX_PATH];
+  shared_name (buf, mutex, ntty);
+  return OpenMutex (access, TRUE, buf);
 }
 
 HANDLE
-tty::open_mutex (const char *mutex)
+tty::open_inuse (ACCESS_MASK access)
 {
   char buf[MAX_PATH];
-  shared_name (buf, mutex, ntty);
-  return OpenMutex (MUTEX_ALL_ACCESS, TRUE, buf);
+  shared_name (buf, TTY_SLAVE_ALIVE, ntty);
+  return OpenEvent (access, FALSE, buf);
 }
 
 HANDLE
-tty::create_inuse (const char *fmt)
+tty::create_inuse (PSECURITY_ATTRIBUTES sa)
 {
   HANDLE h;
   char buf[MAX_PATH];
 
-  shared_name (buf, fmt, ntty);
-  h = CreateEvent (&sec_all, TRUE, FALSE, buf);
+  shared_name (buf, TTY_SLAVE_ALIVE, ntty);
+  h = CreateEvent (sa, TRUE, FALSE, buf);
   termios_printf ("%s %p", buf, h);
   if (!h)
     termios_printf ("couldn't open inuse event, %E", buf);
@@ -374,13 +361,15 @@ tty::init ()
 }
 
 HANDLE
-tty::get_event (const char *fmt, BOOL manual_reset)
+tty::get_event (const char *fmt, PSECURITY_ATTRIBUTES sa, BOOL manual_reset)
 {
   HANDLE hev;
   char buf[MAX_PATH];
 
   shared_name (buf, fmt, ntty);
-  if (!(hev = CreateEvent (&sec_all, manual_reset, FALSE, buf)))
+  if (!sa)
+    sa = &sec_all;
+  if (!(hev = CreateEvent (sa, manual_reset, FALSE, buf)))
     {
       termios_printf ("couldn't create %s", buf);
       set_errno (ENOENT);      /* FIXME this can't be the right errno */
index b4c02a4..630bdb0 100644 (file)
@@ -1,6 +1,6 @@
 /* tty.h: shared tty info for cygwin
 
-   Copyright 2000, 2001, 2002, 2003, 2004, 2006 Red Hat, Inc.
+   Copyright 2000, 2001, 2002, 2003, 2004, 2006, 2009, 2010 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -84,7 +84,8 @@ class fhandler_pty_master;
 
 class tty: public tty_min
 {
-  HANDLE get_event (const char *fmt, BOOL manual_reset = FALSE)
+  HANDLE get_event (const char *fmt, PSECURITY_ATTRIBUTES sa,
+                   BOOL manual_reset = FALSE);
     __attribute__ ((regparm (3)));
 public:
   pid_t master_pid;    /* PID of tty master process */
@@ -95,13 +96,14 @@ public:
   bool was_opened;     /* True if opened at least once. */
 
   void init ();
-  HANDLE create_inuse (const char *);
-  bool alive (const char *fmt);
+  HANDLE open_inuse (ACCESS_MASK access);
+  HANDLE create_inuse (PSECURITY_ATTRIBUTES);
   bool slave_alive ();
-  bool master_alive ();
-  HANDLE open_mutex (const char *mutex);
-  HANDLE open_output_mutex ();
-  HANDLE open_input_mutex ();
+  HANDLE open_mutex (const char *mutex, ACCESS_MASK access);
+  inline HANDLE open_output_mutex (ACCESS_MASK access)
+    { return open_mutex (OUTPUT_MUTEX, access); }
+  inline HANDLE open_input_mutex (ACCESS_MASK access)
+    { return open_mutex (INPUT_MUTEX, access); }
   bool exists ();
   void set_master_closed () {master_pid = -1;}
   static void __stdcall create_master (int);