* 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.
This commit is contained in:
Corinna Vinschen 2010-04-19 19:52:43 +00:00
parent 02a33ea774
commit cc01c77f7e
9 changed files with 705 additions and 152 deletions

View File

@ -1,3 +1,69 @@
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> 2010-04-19 Corinna Vinschen <corinna@vinschen.de>
* dtable.cc (dtable::init_std_file_from_handle): Set dev to * dtable.cc (dtable::init_std_file_from_handle): Set dev to

View File

@ -419,6 +419,7 @@ LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1)
LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1) LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1)
LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1) LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1)
LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1) LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1)
LoadDLLfuncEx (GetNamedPipeClientProcessId, 8, kernel32, 1)
LoadDLLfuncEx (GetSystemWindowsDirectoryW, 8, kernel32, 1) LoadDLLfuncEx (GetSystemWindowsDirectoryW, 8, kernel32, 1)
LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1) LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1)
LoadDLLfuncEx (GetSystemDEPPolicy, 0, kernel32, 1) LoadDLLfuncEx (GetSystemDEPPolicy, 0, kernel32, 1)

View File

@ -1089,6 +1089,12 @@ class fhandler_tty_common: public fhandler_termios
class fhandler_tty_slave: public fhandler_tty_common class fhandler_tty_slave: public fhandler_tty_common
{ {
HANDLE inuse; // used to indicate that a tty is in use 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: public:
/* Constructor */ /* Constructor */
fhandler_tty_slave (); fhandler_tty_slave ();
@ -1108,14 +1114,18 @@ class fhandler_tty_slave: public fhandler_tty_common
void fixup_after_exec (); void fixup_after_exec ();
select_record *select_read (select_stuff *); select_record *select_read (select_stuff *);
int cygserver_attach_tty (HANDLE*, HANDLE*);
int get_unit (); int get_unit ();
virtual char const *ttyname () { return pc.dev.name; } 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 class fhandler_pty_master: public fhandler_tty_common
{ {
int pktmode; // non-zero if pty in a packet mode. int pktmode; // non-zero if pty in a packet mode.
HANDLE master_ctl; // Control socket for handle duplication
public: public:
int need_nl; // Next read should start with \n int need_nl; // Next read should start with \n
DWORD dwProcessId; // Owner of master handles DWORD dwProcessId; // Owner of master handles
@ -1123,6 +1133,7 @@ public:
/* Constructor */ /* Constructor */
fhandler_pty_master (); fhandler_pty_master ();
DWORD pty_master_thread ();
int process_slave_output (char *buf, size_t len, int pktmode_on); int process_slave_output (char *buf, size_t len, int pktmode_on);
void doecho (const void *str, DWORD len); void doecho (const void *str, DWORD len);
int accept_input (); int accept_input ();

View File

@ -58,6 +58,13 @@ fhandler_termios::tcinit (tty_min *this_tc, bool force)
tc->pgid = myself->pgid; tc->pgid = myself->pgid;
tc->initialized (true); 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 int

View File

@ -19,12 +19,29 @@ details. */
#include "dtable.h" #include "dtable.h"
#include "sigproc.h" #include "sigproc.h"
#include "pinfo.h" #include "pinfo.h"
#include "ntdll.h"
#include "cygheap.h" #include "cygheap.h"
#include "shared_info.h" #include "shared_info.h"
#include "cygserver.h"
#include "cygthread.h" #include "cygthread.h"
#include "child_info.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 */ /* tty master stuff */
fhandler_tty_master NO_COPY *tty_master; 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 pty opened by fhandler_pty_master::open. In the former case, tty
output is handled by a separate thread which controls output. */ output is handled by a separate thread which controls output. */
shared_name (buf, OUTPUT_DONE_EVENT, get_unit ()); 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"; errmsg = "open output mutex failed, %E";
goto err; 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"; errmsg = "open input mutex failed, %E";
goto err; goto err;
} }
shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ()); 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"; errmsg = "open input event failed, %E";
goto err; 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, /* The ioctl events may or may not exist. See output_done_event,
above. */ above. */
shared_name (buf, IOCTL_REQUEST_EVENT, get_unit ()); 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 ()); 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 */ /* 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); acquire_output_mutex (500);
inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE); inuse = get_ttyp ()->create_inuse (&sa);
get_ttyp ()->was_opened = true; get_ttyp ()->was_opened = true;
release_output_mutex (); release_output_mutex ();
} }
@ -531,24 +557,20 @@ fhandler_tty_slave::open (int flags, mode_t)
goto err_no_errno; 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) if (get_ttyp ()->master_pid < 0)
{ {
errmsg = "*** master is closed"; errmsg = "*** master is closed";
set_errno (EAGAIN); set_errno (EAGAIN);
goto err_no_errno; goto err_no_errno;
} }
pinfo p (get_ttyp ()->master_pid); /* Three case for duplicating the pipe handles:
if (!p) - 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.
errmsg = "*** couldn't find tty master"; In this case, just duplicate the handles.
set_errno (EAGAIN); - Or, we have to ask the master process itself. In this case, send our
goto err_no_errno; 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
HANDLE tty_owner; get the handles. */
if (myself->pid == get_ttyp ()->master_pid) if (myself->pid == get_ttyp ()->master_pid)
{ {
/* This is the most common case, just calling openpty. */ /* This is the most common case, just calling openpty. */
@ -557,17 +579,18 @@ fhandler_tty_slave::open (int flags, mode_t)
} }
else else
{ {
termios_printf ("cannot dup handles via server. using old method."); pinfo p (get_ttyp ()->master_pid);
tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId); if (!p)
if (tty_owner == NULL) termios_printf ("*** couldn't find tty master");
else
{ {
termios_printf ("can't open tty (%d) handle process %d", tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
get_unit (), get_ttyp ()->master_pid); if (tty_owner)
__seterrno (); termios_printf ("dup handles directly since I'm allmighty.");
goto err_no_msg;
} }
} }
if (tty_owner)
{
if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master, if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
GetCurrentProcess (), &from_master_local, 0, TRUE, GetCurrentProcess (), &from_master_local, 0, TRUE,
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS))
@ -577,8 +600,6 @@ fhandler_tty_slave::open (int flags, mode_t)
__seterrno (); __seterrno ();
goto err_no_msg; goto err_no_msg;
} }
VerifyHandle (from_master_local);
if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master, if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
GetCurrentProcess (), &to_master_local, 0, TRUE, GetCurrentProcess (), &to_master_local, 0, TRUE,
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS))
@ -586,10 +607,35 @@ fhandler_tty_slave::open (int flags, mode_t)
errmsg = "can't duplicate output, %E"; errmsg = "can't duplicate output, %E";
goto err; goto err;
} }
VerifyHandle (to_master_local);
if (tty_owner != GetCurrentProcess ()) if (tty_owner != GetCurrentProcess ())
CloseHandle (tty_owner); 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", termios_printf ("duplicated from_master %p->%p from tty_owner",
get_ttyp ()->from_master, from_master_local); get_ttyp ()->from_master, from_master_local);
@ -660,31 +706,7 @@ fhandler_tty_slave::close ()
} }
int int
fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, fhandler_tty_slave::init (HANDLE f, DWORD a, mode_t)
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)
{ {
int flags = 0; int flags = 0;
@ -696,7 +718,12 @@ fhandler_tty_slave::init (HANDLE, DWORD a, mode_t)
if (a == (GENERIC_READ | GENERIC_WRITE)) if (a == (GENERIC_READ | GENERIC_WRITE))
flags = O_RDWR; 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 ssize_t __stdcall
@ -1117,6 +1144,177 @@ out:
return retval; 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 fhandler_pty_master
*/ */
@ -1215,6 +1413,18 @@ fhandler_pty_master::close ()
arch->from_master, arch->to_master, arch->dwProcessId); arch->from_master, arch->to_master, arch->dwProcessId);
if (cygwin_finished_initializing) 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)) if (!ForceCloseHandle (arch->from_master))
termios_printf ("error closing from_master %p, %E", arch->from_master); termios_printf ("error closing from_master %p, %E", arch->from_master);
if (!ForceCloseHandle (arch->to_master)) if (!ForceCloseHandle (arch->to_master))
@ -1361,16 +1571,154 @@ fhandler_tty_master::init_console ()
return 0; return 0;
} }
#define close_maybe(h) \ extern "C" BOOL WINAPI GetNamedPipeClientProcessId (HANDLE, PULONG);
do { \
if (h && h != INVALID_HANDLE_VALUE) \ /* This thread function handles the master control pipe. It waits for a
CloseHandle (h); \ client to connect. Then it checks if the client process has permissions
} while (0) 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 bool
fhandler_pty_master::setup (bool ispty) fhandler_pty_master::setup (bool ispty)
{ {
int res; int res;
security_descriptor sd;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
tty& t = *cygwin_shared->tty[get_unit ()]; tty& t = *cygwin_shared->tty[get_unit ()];
tcinit (&t, true); /* Set termios information. Force initialization. */ tcinit (&t, true); /* Set termios information. Force initialization. */
@ -1379,78 +1727,97 @@ fhandler_pty_master::setup (bool ispty)
DWORD pipe_mode = PIPE_NOWAIT; DWORD pipe_mode = PIPE_NOWAIT;
/* Create communication pipes */ /* Create communication pipes */
char pipename[sizeof("ttyNNNN-from-master")]; char pipename[sizeof("ttyNNNN-from-master")];
__small_sprintf (pipename, "tty%d-from-master", get_unit ()); __small_sprintf (pipename, "tty%d-from-master", get_unit ());
res = fhandler_pipe::create_selectable (&sec_none_nih, from_master, res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
get_output_handle (), 128 * 1024, from_master, get_output_handle (),
pipename); 128 * 1024, pipename);
if (res) if (res)
{ {
errstr = "input pipe"; errstr = "input pipe";
goto err; 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)) if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL))
termios_printf ("can't set output_handle(%p) to non-blocking mode", termios_printf ("can't set output_handle(%p) to non-blocking mode",
get_output_handle ()); get_output_handle ());
__small_sprintf (pipename, "tty%d-to-master", get_unit ()); __small_sprintf (pipename, "tty%d-to-master", get_unit ());
res = fhandler_pipe::create_selectable (&sec_none_nih, get_io_handle (), res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
to_master, 128 * 1024, pipename); get_io_handle (), to_master,
128 * 1024, pipename);
if (res) if (res)
{ {
errstr = "output pipe"; errstr = "output pipe";
goto err; 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; need_nl = 0;
/* We do not allow others to open us (for handle duplication) /* Create security attribute. Default permissions are 0620. */
but rely on cygheap->inherited_ctty for descendant processes. sd.malloc (sizeof (SECURITY_DESCRIPTOR));
In the future the cygserver may allow access by others. */ InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid,
if (cygserver_running == CYGSERVER_UNKNOWN) S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
cygserver_init (); sd))
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
/* Create synchronisation events */ /* Create synchronisation events */
if (!ispty) 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; 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; 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; 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; goto err;
char buf[MAX_PATH]; char buf[MAX_PATH];
errstr = shared_name (buf, OUTPUT_MUTEX, t.ntty); 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; goto err;
errstr = shared_name (buf, INPUT_MUTEX, t.ntty); 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; 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.from_master = from_master;
t.to_master = to_master; t.to_master = to_master;
// /* screws up tty master */ ProtectHandle1INH (output_mutex, output_mutex); // /* screws up tty master */ ProtectHandle1INH (output_mutex, output_mutex);
@ -1475,6 +1842,7 @@ err:
close_maybe (input_mutex); close_maybe (input_mutex);
close_maybe (from_master); close_maybe (from_master);
close_maybe (to_master); close_maybe (to_master);
close_maybe (master_ctl);
termios_printf ("tty%d open failed - failed to create %s", errstr); termios_printf ("tty%d open failed - failed to create %s", errstr);
return false; return false;
} }

View File

@ -1,7 +1,7 @@
/* security.cc: NT file access control functions /* security.cc: NT file access control functions
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 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 Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
Completely rewritten by Corinna Vinschen <corinna@vinschen.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. */ /* From here fill ACL. */
size_t acl_len = sizeof (ACL); size_t acl_len = sizeof (ACL);
int ace_off = 0; 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. /* Construct allow attribute for owner.
Don't set FILE_READ/WRITE_ATTRIBUTES unconditionally on Samba, otherwise 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) if (S_ISDIR (attribute)
&& (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)) && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR))
owner_allow |= FILE_DELETE_CHILD; 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. */ /* 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); | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
if (attribute & S_IRGRP) if (attribute & S_IRGRP)
group_allow |= FILE_GENERIC_READ; 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_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP)
&& !(attribute & S_ISVTX)) && !(attribute & S_ISVTX))
group_allow |= FILE_DELETE_CHILD; 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. */ /* 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); | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
if (attribute & S_IROTH) if (attribute & S_IROTH)
other_allow |= FILE_GENERIC_READ; 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)) group_sid, acl_len, NO_INHERITANCE))
return NULL; 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. */ /* Set allow ACE for everyone. */
if (!add_access_allowed_ace (acl, ace_off++, other_allow, if (!add_access_allowed_ace (acl, ace_off++, other_allow,
well_known_world_sid, acl_len, NO_INHERITANCE)) 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); cygpsid ace_sid ((PSID) &ace->SidStart);
/* Check for related ACEs. */ /* 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; continue;
if ((ace_sid == cur_owner_sid) if ((ace_sid == cur_owner_sid)
|| (ace_sid == owner_sid) || (ace_sid == owner_sid)
@ -716,9 +741,86 @@ set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa,
attribute, sd); attribute, sd);
} }
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 int
set_file_attribute (HANDLE handle, path_conv &pc, 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; int ret = -1;

View File

@ -350,7 +350,14 @@ class path_conv;
int __stdcall get_file_attribute (HANDLE, path_conv &, mode_t *, int __stdcall get_file_attribute (HANDLE, path_conv &, mode_t *,
__uid32_t *, __gid32_t *); __uid32_t *, __gid32_t *);
int __stdcall set_file_attribute (HANDLE, path_conv &, 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 *); 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 get_file_sd (HANDLE fh, path_conv &, security_descriptor &sd);
LONG __stdcall set_file_sd (HANDLE fh, path_conv &, security_descriptor &sd, LONG __stdcall set_file_sd (HANDLE fh, path_conv &, security_descriptor &sd,

View File

@ -1,7 +1,7 @@
/* tty.cc /* tty.cc
Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Copyright 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009,
Red Hat, Inc. 2010 Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -286,12 +286,6 @@ out:
return freetty; return freetty;
} }
bool
tty::slave_alive ()
{
return alive (TTY_SLAVE_ALIVE);
}
bool bool
tty::exists () tty::exists ()
{ {
@ -307,7 +301,7 @@ tty::exists ()
CloseHandle (r); CloseHandle (r);
CloseHandle (w); CloseHandle (w);
HANDLE h = open_output_mutex (); HANDLE h = open_output_mutex (READ_CONTROL);
if (h) if (h)
{ {
CloseHandle (h); CloseHandle (h);
@ -317,45 +311,38 @@ tty::exists ()
} }
bool bool
tty::alive (const char *fmt) tty::slave_alive ()
{ {
HANDLE ev; HANDLE ev;
char buf[MAX_PATH]; if ((ev = open_inuse (READ_CONTROL)))
shared_name (buf, fmt, ntty);
if ((ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf)))
CloseHandle (ev); CloseHandle (ev);
return ev != NULL; return ev != NULL;
} }
HANDLE 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);
}
HANDLE
tty::open_mutex (const char *mutex)
{ {
char buf[MAX_PATH]; char buf[MAX_PATH];
shared_name (buf, mutex, ntty); shared_name (buf, mutex, ntty);
return OpenMutex (MUTEX_ALL_ACCESS, TRUE, buf); return OpenMutex (access, TRUE, buf);
} }
HANDLE HANDLE
tty::create_inuse (const char *fmt) tty::open_inuse (ACCESS_MASK access)
{
char buf[MAX_PATH];
shared_name (buf, TTY_SLAVE_ALIVE, ntty);
return OpenEvent (access, FALSE, buf);
}
HANDLE
tty::create_inuse (PSECURITY_ATTRIBUTES sa)
{ {
HANDLE h; HANDLE h;
char buf[MAX_PATH]; char buf[MAX_PATH];
shared_name (buf, fmt, ntty); shared_name (buf, TTY_SLAVE_ALIVE, ntty);
h = CreateEvent (&sec_all, TRUE, FALSE, buf); h = CreateEvent (sa, TRUE, FALSE, buf);
termios_printf ("%s %p", buf, h); termios_printf ("%s %p", buf, h);
if (!h) if (!h)
termios_printf ("couldn't open inuse event, %E", buf); termios_printf ("couldn't open inuse event, %E", buf);
@ -374,13 +361,15 @@ tty::init ()
} }
HANDLE HANDLE
tty::get_event (const char *fmt, BOOL manual_reset) tty::get_event (const char *fmt, PSECURITY_ATTRIBUTES sa, BOOL manual_reset)
{ {
HANDLE hev; HANDLE hev;
char buf[MAX_PATH]; char buf[MAX_PATH];
shared_name (buf, fmt, ntty); 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); termios_printf ("couldn't create %s", buf);
set_errno (ENOENT); /* FIXME this can't be the right errno */ set_errno (ENOENT); /* FIXME this can't be the right errno */

View File

@ -1,6 +1,6 @@
/* tty.h: shared tty info for cygwin /* 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. This file is part of Cygwin.
@ -84,7 +84,8 @@ class fhandler_pty_master;
class tty: public tty_min 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))); __attribute__ ((regparm (3)));
public: public:
pid_t master_pid; /* PID of tty master process */ pid_t master_pid; /* PID of tty master process */
@ -95,13 +96,14 @@ public:
bool was_opened; /* True if opened at least once. */ bool was_opened; /* True if opened at least once. */
void init (); void init ();
HANDLE create_inuse (const char *); HANDLE open_inuse (ACCESS_MASK access);
bool alive (const char *fmt); HANDLE create_inuse (PSECURITY_ATTRIBUTES);
bool slave_alive (); bool slave_alive ();
bool master_alive (); HANDLE open_mutex (const char *mutex, ACCESS_MASK access);
HANDLE open_mutex (const char *mutex); inline HANDLE open_output_mutex (ACCESS_MASK access)
HANDLE open_output_mutex (); { return open_mutex (OUTPUT_MUTEX, access); }
HANDLE open_input_mutex (); inline HANDLE open_input_mutex (ACCESS_MASK access)
{ return open_mutex (INPUT_MUTEX, access); }
bool exists (); bool exists ();
void set_master_closed () {master_pid = -1;} void set_master_closed () {master_pid = -1;}
static void __stdcall create_master (int); static void __stdcall create_master (int);