Don't use safe_new but new throughout. Fix copyright dates
throughout. * Makefile.in: Accomodate all new files and name changes. Add a *.d dependency. (sbindir): Add. (etcdir): Drop in favor of more appropriate sysconfdir definition. (sysconfdir): Add. (CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition. (.SUFFIXES): Add. (install): Add action items. (libclean): New target. (fullclean): Ditto. * bsd_helper.cc: New file. * bsd_helper.h: Ditto. * bsd_log.cc: Ditto. * bsd_log.h: Ditto. * bsd_mutex.cc: Ditto. * bsd_mutex.h: Ditto. * client.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. (client_request::handle_request): Add Message Queue and Semaphore handling. * cygserver.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. Use new debug/log/panic logging functions. (DEF_CONFIG_FILE): New definition for configuration file. Use throughout. (getfunc): Remove. (__cygserver__printf): Remove. (client_request_attach_tty::serve): Return error if impersonation fails. (print_usage): Pump up help message. (print_version): Add output of default configuration file. (main): Accommodate new options. Allow overwrite of threading options from config file. Call several new initialization functions. Drop printing dots. Don't define SIGHANDLE inline. * cygserver.conf: New file. * cygserver_process.h: Rename to process.h. * cygserver_transport.h: Rename to transport.h. * cygserver_transport_pipes.h: Rename to transport_pipes.h. * cygserver_transport_sockets.h: Rename to transport_sockets.h. * msg.cc: Rewrite. * sem.cc: Rewrite. * shm.cc: Rewrite. * sysv_msg.cc: New file, derived from FreeBSD version 1.52. * sysv_sem.cc: New file, derived from FreeBSD version 1.66. * sysv_shm.cc: New file, derived from FreeBSD version 1.89. * threaded_queue.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. * transport.cc (transport_layer_base::impersonate_client): Define bool. (transport_layer_base::revert_to_self): Ditto. * transport.h (transport_layer_base::impersonate_client): Declare bool. (transport_layer_base::revert_to_self): Ditto. * transport_pipes.cc (transport_layer_pipes::transport_layer_pipes): Don't call init_security. (init_security): Remove. (transport_layer_pipes::accept): Use global sec_all_nih. (transport_layer_pipes::connect): Ditto. (transport_layer_pipes::impersonate_client): Define bool. (transport_layer_pipes::revert_to_self): Ditt. * transport_pipes.h (transport_layer_pipes::impersonate_client): Declare bool. (transport_layer_pipes::revert_to_self): Ditto. * woutsup.h: Include bsd compatibility headers. (SIGHANDLE): Add definition. (__cygserver__printf): Remove definition. (__noop_printf): Ditto. (debug_printf): Define using debug. (syscall_printf): Define using log. (system_printf): Ditto. Drop all other _printf definitions.
This commit is contained in:
parent
64cfc6f213
commit
282113ba89
|
@ -1,3 +1,76 @@
|
|||
2003-11-19 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
Don't use safe_new but new throughout. Fix copyright dates
|
||||
throughout.
|
||||
* Makefile.in: Accomodate all new files and name changes.
|
||||
Add a *.d dependency.
|
||||
(sbindir): Add.
|
||||
(etcdir): Drop in favor of more appropriate sysconfdir definition.
|
||||
(sysconfdir): Add.
|
||||
(CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition.
|
||||
(.SUFFIXES): Add.
|
||||
(install): Add action items.
|
||||
(libclean): New target.
|
||||
(fullclean): Ditto.
|
||||
* bsd_helper.cc: New file.
|
||||
* bsd_helper.h: Ditto.
|
||||
* bsd_log.cc: Ditto.
|
||||
* bsd_log.h: Ditto.
|
||||
* bsd_mutex.cc: Ditto.
|
||||
* bsd_mutex.h: Ditto.
|
||||
* client.cc: Rearrange to build as less as possible if
|
||||
__INSIDE_CYGWIN__.
|
||||
(client_request::handle_request): Add Message Queue and Semaphore
|
||||
handling.
|
||||
* cygserver.cc: Rearrange to build as less as possible if
|
||||
__INSIDE_CYGWIN__. Use new debug/log/panic logging functions.
|
||||
(DEF_CONFIG_FILE): New definition for configuration file. Use
|
||||
throughout.
|
||||
(getfunc): Remove.
|
||||
(__cygserver__printf): Remove.
|
||||
(client_request_attach_tty::serve): Return error if impersonation
|
||||
fails.
|
||||
(print_usage): Pump up help message.
|
||||
(print_version): Add output of default configuration file.
|
||||
(main): Accommodate new options. Allow overwrite of threading options
|
||||
from config file. Call several new initialization functions. Drop
|
||||
printing dots. Don't define SIGHANDLE inline.
|
||||
* cygserver.conf: New file.
|
||||
* cygserver_process.h: Rename to process.h.
|
||||
* cygserver_transport.h: Rename to transport.h.
|
||||
* cygserver_transport_pipes.h: Rename to transport_pipes.h.
|
||||
* cygserver_transport_sockets.h: Rename to transport_sockets.h.
|
||||
* msg.cc: Rewrite.
|
||||
* sem.cc: Rewrite.
|
||||
* shm.cc: Rewrite.
|
||||
* sysv_msg.cc: New file, derived from FreeBSD version 1.52.
|
||||
* sysv_sem.cc: New file, derived from FreeBSD version 1.66.
|
||||
* sysv_shm.cc: New file, derived from FreeBSD version 1.89.
|
||||
* threaded_queue.cc: Rearrange to build as less as possible if
|
||||
__INSIDE_CYGWIN__.
|
||||
* transport.cc (transport_layer_base::impersonate_client): Define bool.
|
||||
(transport_layer_base::revert_to_self): Ditto.
|
||||
* transport.h (transport_layer_base::impersonate_client): Declare bool.
|
||||
(transport_layer_base::revert_to_self): Ditto.
|
||||
* transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
|
||||
Don't call init_security.
|
||||
(init_security): Remove.
|
||||
(transport_layer_pipes::accept): Use global sec_all_nih.
|
||||
(transport_layer_pipes::connect): Ditto.
|
||||
(transport_layer_pipes::impersonate_client): Define bool.
|
||||
(transport_layer_pipes::revert_to_self): Ditt.
|
||||
* transport_pipes.h (transport_layer_pipes::impersonate_client): Declare
|
||||
bool.
|
||||
(transport_layer_pipes::revert_to_self): Ditto.
|
||||
* woutsup.h: Include bsd compatibility headers.
|
||||
(SIGHANDLE): Add definition.
|
||||
(__cygserver__printf): Remove definition.
|
||||
(__noop_printf): Ditto.
|
||||
(debug_printf): Define using debug.
|
||||
(syscall_printf): Define using log.
|
||||
(system_printf): Ditto.
|
||||
Drop all other _printf definitions.
|
||||
|
||||
2003-10-22 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
Accomodate moving cygserver header files from cygwin/include/cygwin
|
||||
|
|
|
@ -15,7 +15,8 @@ prefix:=@prefix@
|
|||
exec_prefix:=@exec_prefix@
|
||||
|
||||
bindir:=@bindir@
|
||||
etcdir:=$(exec_prefix)/etc
|
||||
sbindir:=@sbindir@
|
||||
sysconfdir:=@sysconfdir@
|
||||
program_transform_name:=@program_transform_name@
|
||||
|
||||
INSTALL:=@INSTALL@
|
||||
|
@ -28,14 +29,18 @@ CXX:=@CXX@
|
|||
CXX_FOR_TARGET:=$(CXX)
|
||||
AR:=@AR@
|
||||
|
||||
CFLAGS:=@CFLAGS@ -I$(cygwin_source)
|
||||
CXXFLAGS:=@CXXFLAGS@ -I$(cygwin_source)
|
||||
override CXXFLAGS+=-fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__
|
||||
|
||||
include $(srcdir)/../Makefile.common
|
||||
|
||||
CFLAGS:=@CFLAGS@ -I$(cygwin_source)
|
||||
CXXFLAGS:=@CXXFLAGS@ -I$(cygwin_source)
|
||||
override CXXFLAGS+=-MMD -fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__ -DSYSCONFDIR="\"$(sysconfdir)\""
|
||||
|
||||
.SUFFIXES: .c .cc .a .o .d
|
||||
|
||||
OBJS:= cygserver.o client.o process.o msg.o sem.o shm.o threaded_queue.o \
|
||||
transport.o transport_pipes.o transport_sockets.o
|
||||
transport.o transport_pipes.o transport_sockets.o \
|
||||
bsd_helper.o bsd_log.o bsd_mutex.o \
|
||||
sysv_msg.o sysv_sem.o sysv_shm.o
|
||||
LIBOBJS:=${patsubst %.o,lib%.o,$(OBJS)}
|
||||
|
||||
CYGWIN_OBJS:=$(cygwin_build)/smallprint.o $(cygwin_build)/version.o \
|
||||
|
@ -43,10 +48,17 @@ CYGWIN_OBJS:=$(cygwin_build)/smallprint.o $(cygwin_build)/version.o \
|
|||
|
||||
all: cygserver.exe
|
||||
|
||||
install: all
|
||||
install: all cygserver.conf
|
||||
$(INSTALL_PROGRAM) cygserver.exe $(sbindir)/cygserver.exe
|
||||
$(INSTALL_DATA) $(srcdir)/cygserver.conf $(sysconfdir)/cygserver.conf
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f $(OBJS) ${patsubst %.o,%.d,$(OBJS)} cygserver.exe
|
||||
|
||||
libclean:
|
||||
rm -f $(LIBOBJS) ${patsubst %.o,%.d,$(LIBOBJS)} libcygserver.a
|
||||
|
||||
fullclean: clean libclean
|
||||
|
||||
cygserver.exe: $(OBJS) $(CYGWIN_OBJS)
|
||||
$(CXX) -o $@ $^
|
||||
|
@ -64,3 +76,8 @@ lib%.o: %.cc
|
|||
|
||||
libcygserver.a: $(LIBOBJS)
|
||||
$(AR) crus $@ $?
|
||||
|
||||
deps:=${wildcard *.d}
|
||||
ifneq (,$(deps))
|
||||
include $(deps)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,694 @@
|
|||
/* bsd_helper.cc
|
||||
|
||||
Copyright 2003 Red Hat Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
#include "cygerrno.h"
|
||||
#define _KERNEL 1
|
||||
#define __BSD_VISIBLE 1
|
||||
#include <sys/smallprint.h>
|
||||
#include <sys/cygwin.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/queue.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "security.h"
|
||||
#include "cygserver.h"
|
||||
#include "process.h"
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_msg.h"
|
||||
#include "cygserver_sem.h"
|
||||
#include "cygserver_shm.h"
|
||||
|
||||
/*
|
||||
* Copy a piece of memory from the client process into the server process.
|
||||
* Returns an error code.
|
||||
*/
|
||||
int
|
||||
win_copyin (struct thread *td, const void *client_src,
|
||||
void *server_tgt, size_t len)
|
||||
{
|
||||
if (!ReadProcessMemory (td->client->handle (), client_src, server_tgt,
|
||||
len, NULL))
|
||||
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
|
||||
GetLastError (), EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a piece of memory from the server process into the client process.
|
||||
* Returns an error code.
|
||||
*/
|
||||
int
|
||||
win_copyout (struct thread *td, const void *server_src,
|
||||
void *client_tgt, size_t len)
|
||||
{
|
||||
if (!WriteProcessMemory (td->client->handle (), client_tgt, server_src,
|
||||
len, NULL))
|
||||
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
|
||||
GetLastError (), EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define enter_critical_section(c) _enter_critical_section((c),__FILE__,__LINE__)
|
||||
static void
|
||||
_enter_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
|
||||
{
|
||||
_log (file, line, LOG_DEBUG, "Try enter critical section(%p)", pcs);
|
||||
EnterCriticalSection (pcs);
|
||||
_log (file, line, LOG_DEBUG, "Entered critical section(%p)", pcs);
|
||||
}
|
||||
|
||||
#define leave_critical_section(c) _leave_critical_section((c),__FILE__,__LINE__)
|
||||
static void
|
||||
_leave_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
|
||||
{
|
||||
LeaveCriticalSection (pcs);
|
||||
_log (file, line, LOG_DEBUG, "Left critical section(%p)", pcs);
|
||||
}
|
||||
|
||||
CRITICAL_SECTION ipcht_cs;
|
||||
|
||||
struct ipc_hookthread_storage {
|
||||
HANDLE process_hdl;
|
||||
proc ipcblk;
|
||||
};
|
||||
|
||||
struct ipc_hookthread {
|
||||
SLIST_ENTRY(ipc_hookthread) sht_next;
|
||||
HANDLE thread;
|
||||
DWORD winpid;
|
||||
struct vmspace vmspace;
|
||||
};
|
||||
static SLIST_HEAD(, ipc_hookthread) ipcht_list; /* list of hook threads */
|
||||
|
||||
static HANDLE ipcexit_event;
|
||||
|
||||
struct vmspace *
|
||||
ipc_p_vmspace (struct proc *proc)
|
||||
{
|
||||
struct vmspace *ret = NULL;
|
||||
ipc_hookthread *ipcht_entry;
|
||||
enter_critical_section (&ipcht_cs);
|
||||
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
|
||||
{
|
||||
if (ipcht_entry->winpid == proc->winpid)
|
||||
{
|
||||
ret = proc->p_vmspace = &ipcht_entry->vmspace;
|
||||
break;
|
||||
}
|
||||
}
|
||||
leave_critical_section (&ipcht_cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD WINAPI
|
||||
ipcexit_hookthread(const LPVOID param)
|
||||
{
|
||||
ipc_hookthread_storage *shs = (ipc_hookthread_storage *) param;
|
||||
HANDLE obj[2] = { ipcexit_event, shs->process_hdl };
|
||||
switch (WaitForMultipleObjects (2, obj, FALSE, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
/* Cygserver shutdown. */
|
||||
/*FALLTHRU*/
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
/* Process exited. Call semexit_myhook to handle SEM_UNDOs for the
|
||||
exiting process and shmexit_myhook to keep track of shared
|
||||
memory. */
|
||||
if (Giant.owner == shs->ipcblk.winpid)
|
||||
mtx_unlock (&Giant);
|
||||
if (support_semaphores == TUN_TRUE)
|
||||
semexit_myhook (NULL, &shs->ipcblk);
|
||||
if (support_sharedmem == TUN_TRUE)
|
||||
{
|
||||
_mtx_lock (&Giant, shs->ipcblk.winpid, __FILE__, __LINE__);
|
||||
ipc_p_vmspace (&shs->ipcblk);
|
||||
shmexit_myhook (shs->ipcblk.p_vmspace);
|
||||
mtx_unlock (&Giant);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* FIXME: Panic? */
|
||||
break;
|
||||
}
|
||||
CloseHandle (shs->process_hdl);
|
||||
ipc_hookthread *ipcht_entry, *sav_entry;
|
||||
enter_critical_section (&ipcht_cs);
|
||||
SLIST_FOREACH_SAFE (ipcht_entry, &ipcht_list, sht_next, sav_entry)
|
||||
{
|
||||
if (ipcht_entry->winpid == shs->ipcblk.winpid)
|
||||
{
|
||||
SLIST_REMOVE (&ipcht_list, ipcht_entry, ipc_hookthread, sht_next);
|
||||
delete ipcht_entry;
|
||||
}
|
||||
}
|
||||
leave_critical_section (&ipcht_cs);
|
||||
delete shs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deletes all pending hook threads. Called by ipcunload() which in turn
|
||||
is called by the cygserver main routine. */
|
||||
static void
|
||||
ipcexit_dispose_hookthreads(void)
|
||||
{
|
||||
SetEvent (ipcexit_event);
|
||||
ipc_hookthread *ipcht_entry;
|
||||
enter_critical_section (&ipcht_cs);
|
||||
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
|
||||
{
|
||||
WaitForSingleObject (ipcht_entry->thread, 1000);
|
||||
/* Don't bother removing the linked list on cygserver shutdown. */
|
||||
/* FIXME: Error handling? */
|
||||
}
|
||||
leave_critical_section (&ipcht_cs);
|
||||
}
|
||||
|
||||
/* Creates the per process wait thread. Called by semget() under locked
|
||||
Giant mutex condition. */
|
||||
int
|
||||
ipcexit_creat_hookthread(struct thread *td)
|
||||
{
|
||||
ipc_hookthread *ipcht_entry;
|
||||
int ret = -1;
|
||||
enter_critical_section (&ipcht_cs);
|
||||
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
|
||||
{
|
||||
if (ipcht_entry->winpid == td->ipcblk->winpid)
|
||||
ret = 0;
|
||||
}
|
||||
leave_critical_section (&ipcht_cs);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
DWORD tid;
|
||||
ipc_hookthread_storage *shs = new ipc_hookthread_storage;
|
||||
if (!DuplicateHandle (GetCurrentProcess (), td->client->handle (),
|
||||
GetCurrentProcess (), &shs->process_hdl,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
log (LOG_CRIT, "failed to duplicate process handle, error = %lu",
|
||||
GetLastError ());
|
||||
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
|
||||
GetLastError (), ENOMEM);
|
||||
}
|
||||
shs->ipcblk = *td->ipcblk;
|
||||
HANDLE thread = CreateThread (NULL, 0, ipcexit_hookthread, shs, 0, &tid);
|
||||
if (!thread)
|
||||
{
|
||||
log (LOG_CRIT, "failed to create thread, error = %lu", GetLastError ());
|
||||
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
|
||||
GetLastError (), ENOMEM);
|
||||
}
|
||||
ipcht_entry = new ipc_hookthread;
|
||||
ipcht_entry->thread = thread;
|
||||
ipcht_entry->winpid = td->ipcblk->winpid;
|
||||
ipcht_entry->vmspace.vm_map = NULL;
|
||||
ipcht_entry->vmspace.vm_shm = NULL;
|
||||
enter_critical_section (&ipcht_cs);
|
||||
SLIST_INSERT_HEAD (&ipcht_list, ipcht_entry, sht_next);
|
||||
leave_critical_section (&ipcht_cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Need the admins group SID to compare with groups in client token.
|
||||
*/
|
||||
PSID admininstrator_group_sid;
|
||||
|
||||
static void
|
||||
init_admin_sid (void)
|
||||
{
|
||||
if (wincap.has_security ())
|
||||
{
|
||||
SID_IDENTIFIER_AUTHORITY nt_auth = {SECURITY_NT_AUTHORITY};
|
||||
if (! AllocateAndInitializeSid (&nt_auth, 2, 32, 544, 0, 0, 0, 0, 0, 0,
|
||||
&admininstrator_group_sid))
|
||||
panic ("failed to create well known sids, error = %lu",
|
||||
GetLastError ());
|
||||
}
|
||||
}
|
||||
|
||||
SECURITY_DESCRIPTOR sec_all_nih_sd;
|
||||
SECURITY_ATTRIBUTES sec_all_nih = { sizeof (SECURITY_ATTRIBUTES),
|
||||
&sec_all_nih_sd,
|
||||
FALSE };
|
||||
|
||||
/* Global vars, determining whether the IPC stuff should be started or not. */
|
||||
tun_bool_t support_sharedmem = TUN_UNDEF;
|
||||
tun_bool_t support_msgqueues = TUN_UNDEF;
|
||||
tun_bool_t support_semaphores = TUN_UNDEF;
|
||||
|
||||
void
|
||||
ipcinit ()
|
||||
{
|
||||
InitializeSecurityDescriptor (&sec_all_nih_sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl (&sec_all_nih_sd, TRUE, 0, FALSE);
|
||||
|
||||
init_admin_sid ();
|
||||
mtx_init(&Giant, "Giant", NULL, MTX_DEF);
|
||||
msleep_init ();
|
||||
ipcexit_event = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
if (!ipcexit_event)
|
||||
panic ("Failed to create ipcexit event object");
|
||||
InitializeCriticalSection (&ipcht_cs);
|
||||
if (support_msgqueues == TUN_TRUE)
|
||||
msginit ();
|
||||
if (support_semaphores == TUN_TRUE)
|
||||
seminit ();
|
||||
if (support_sharedmem == TUN_TRUE)
|
||||
shminit ();
|
||||
}
|
||||
|
||||
int
|
||||
ipcunload ()
|
||||
{
|
||||
ipcexit_dispose_hookthreads();
|
||||
CloseHandle (ipcexit_event);
|
||||
wakeup_all ();
|
||||
if (support_semaphores == TUN_TRUE)
|
||||
semunload ();
|
||||
if (support_sharedmem == TUN_TRUE)
|
||||
shmunload ();
|
||||
if (support_msgqueues == TUN_TRUE)
|
||||
msgunload();
|
||||
mtx_destroy(&Giant);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to find a gid in a list of gids.
|
||||
*/
|
||||
static bool
|
||||
is_grp_member (gid_t grp, gid_t *grplist, int listsize)
|
||||
{
|
||||
if (grplist)
|
||||
for (; listsize > 0; --listsize)
|
||||
if (grp == grplist[listsize - 1])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to get a specific token information from a token.
|
||||
* This function mallocs the necessary buffer spcae by itself. It
|
||||
* must be free'd by the calling function.
|
||||
*/
|
||||
static void *
|
||||
get_token_info (HANDLE tok, TOKEN_INFORMATION_CLASS tic)
|
||||
{
|
||||
void *buf;
|
||||
DWORD size;
|
||||
|
||||
if (!GetTokenInformation (tok, tic, NULL, 0, &size)
|
||||
&& GetLastError () != ERROR_INSUFFICIENT_BUFFER)
|
||||
return NULL;
|
||||
if (!(buf = malloc (size)))
|
||||
return NULL;
|
||||
if (!GetTokenInformation (tok, tic, buf, size, &size))
|
||||
{
|
||||
free (buf);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if client user helds "mode" permission when accessing object
|
||||
* associated with "perm" permission record.
|
||||
* Returns an error code.
|
||||
*/
|
||||
int
|
||||
ipcperm (struct thread *td, ipc_perm *perm, unsigned int mode)
|
||||
{
|
||||
proc *p = td->ipcblk;
|
||||
|
||||
if (!suser (td))
|
||||
return 0;
|
||||
if (mode & IPC_M)
|
||||
{
|
||||
return (p->uid != perm->cuid && p->uid != perm->uid)
|
||||
? EACCES : 0;
|
||||
}
|
||||
if (p->uid != perm->cuid && p->uid != perm->uid)
|
||||
{
|
||||
/* If the user is a member of the creator or owner group, test
|
||||
against group bits, otherwise against other bits. */
|
||||
mode >>= p->gid != perm->gid && p->gid != perm->cgid
|
||||
&& !is_grp_member (perm->gid, p->gidlist, p->gidcnt)
|
||||
&& !is_grp_member (perm->cgid, p->gidlist, p->gidcnt)
|
||||
? 6 : 3;
|
||||
}
|
||||
return (mode & perm->mode) != mode ? EACCES : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for client user being superuser.
|
||||
* Returns an error code.
|
||||
*/
|
||||
int
|
||||
suser (struct thread *td)
|
||||
{
|
||||
/* Always superuser on 9x. */
|
||||
if (!wincap.has_security ())
|
||||
return 0;
|
||||
|
||||
/* This value has been set at ImpersonateNamedPipeClient() time
|
||||
using the token information. See adjust_identity_info() below. */
|
||||
return td->ipcblk->is_admin ? 0 : EACCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves user and group info from impersonated token and creates the
|
||||
* correct uid, gid, gidlist and is_admin entries in p from that.
|
||||
*/
|
||||
bool
|
||||
adjust_identity_info (struct proc *p)
|
||||
{
|
||||
HANDLE tok;
|
||||
|
||||
/* No access tokens on 9x. */
|
||||
if (!wincap.has_security ())
|
||||
return true;
|
||||
|
||||
if (!OpenThreadToken (GetCurrentThread (), TOKEN_READ, TRUE, &tok))
|
||||
{
|
||||
debug ("Failed to open worker thread access token for pid %d, winpid %d",
|
||||
p->cygpid, p->winpid);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get uid from user SID in token. */
|
||||
PTOKEN_USER user;
|
||||
if (!(user = (PTOKEN_USER)get_token_info (tok, TokenUser)))
|
||||
goto faulty;
|
||||
p->uid = cygwin_internal (CW_GET_UID_FROM_SID, user->User.Sid);
|
||||
free (user);
|
||||
if (p->uid == (uid_t)-1)
|
||||
log (LOG_WARNING, "WARNING: User not found in /etc/passwd! Using uid -1!");
|
||||
|
||||
/* Get gid from primary group SID in token. */
|
||||
PTOKEN_PRIMARY_GROUP pgrp;
|
||||
if (!(pgrp = (PTOKEN_PRIMARY_GROUP)get_token_info (tok, TokenPrimaryGroup)))
|
||||
goto faulty;
|
||||
p->gid = cygwin_internal (CW_GET_GID_FROM_SID, pgrp->PrimaryGroup);
|
||||
free (pgrp);
|
||||
if (p->gid == (gid_t)-1)
|
||||
log (LOG_WARNING,"WARNING: Group not found in /etc/passwd! Using gid -1!");
|
||||
|
||||
/* Generate gid list from token group's SID list. Also look if the token
|
||||
has an enabled admin group SID. That means, the process has admin
|
||||
privileges. That knowledge is used in suser(). */
|
||||
PTOKEN_GROUPS gsids;
|
||||
if (!(gsids = (PTOKEN_GROUPS)get_token_info (tok, TokenGroups)))
|
||||
goto faulty;
|
||||
if (gsids->GroupCount)
|
||||
{
|
||||
p->gidlist = (gid_t *) calloc (gsids->GroupCount, sizeof (gid_t));
|
||||
if (p->gidlist)
|
||||
p->gidcnt = gsids->GroupCount;
|
||||
}
|
||||
for (DWORD i = 0; i < gsids->GroupCount; ++i)
|
||||
{
|
||||
if (p->gidlist)
|
||||
p->gidlist[i] = cygwin_internal (CW_GET_GID_FROM_SID,
|
||||
gsids->Groups[i].Sid);
|
||||
if (EqualSid (gsids->Groups[i].Sid, admininstrator_group_sid)
|
||||
&& (gsids->Groups[i].Attributes & SE_GROUP_ENABLED))
|
||||
p->is_admin = true;
|
||||
}
|
||||
free (gsids);
|
||||
|
||||
CloseHandle (tok);
|
||||
return true;
|
||||
|
||||
faulty:
|
||||
CloseHandle (tok);
|
||||
log (LOG_CRIT, "Failed to get token information for pid %d, winpid %d",
|
||||
p->cygpid, p->winpid);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Windows wrapper implementation of the VM functions called by sysv_shm.cc.
|
||||
*/
|
||||
|
||||
vm_object_t
|
||||
_vm_pager_allocate (int size, int shmflg)
|
||||
{
|
||||
/* Create the file mapping object with full access for everyone. This is
|
||||
necessary to allow later calls to shmctl(..., IPC_SET,...) to
|
||||
change the access rights and ownership of a shared memory region.
|
||||
The access rights are tested at the beginning of every shm... function.
|
||||
Note that this does not influence the actual read or write access
|
||||
defined in a call to shmat. */
|
||||
vm_object_t object = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_all_nih,
|
||||
PAGE_READWRITE, 0, size, NULL);
|
||||
if (!object)
|
||||
panic ("CreateFileMapping in _vm_pager_allocate failed, %E");
|
||||
return object;
|
||||
}
|
||||
|
||||
vm_object_t
|
||||
vm_object_duplicate (struct thread *td, vm_object_t object)
|
||||
{
|
||||
vm_object_t dup_object;
|
||||
if (!DuplicateHandle(GetCurrentProcess (), object,
|
||||
td->client->handle (), &dup_object,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||
panic ("!DuplicateHandle in vm_object_duplicate failed, %E");
|
||||
return dup_object;
|
||||
}
|
||||
|
||||
void
|
||||
vm_object_deallocate (vm_object_t object)
|
||||
{
|
||||
if (object)
|
||||
CloseHandle (object);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tunable parameters are read from a system wide cygserver.conf file.
|
||||
* On the first call to tunable_int_fetch, the file is read and the
|
||||
* parameters are set accordingly. Each parameter has default, max and
|
||||
* min settings.
|
||||
*/
|
||||
|
||||
enum tun_params_type {
|
||||
TUN_NULL,
|
||||
TUN_INT,
|
||||
TUN_BOOL
|
||||
};
|
||||
|
||||
union tun_value {
|
||||
long ival;
|
||||
tun_bool_t bval;
|
||||
};
|
||||
|
||||
struct tun_struct {
|
||||
const char *name;
|
||||
tun_params_type type;
|
||||
union tun_value value;
|
||||
union tun_value min;
|
||||
union tun_value max;
|
||||
void (*check_func)(tun_struct *, char *, const char *);
|
||||
};
|
||||
|
||||
static void
|
||||
default_tun_check (tun_struct *that, char *value, const char *fname)
|
||||
{
|
||||
char *c = NULL;
|
||||
tun_value val;
|
||||
switch (that->type)
|
||||
{
|
||||
case TUN_INT:
|
||||
val.ival = strtoul (value, &c, 10);
|
||||
if (!val.ival || (c && *c))
|
||||
panic ("Error in config file %s: Value of parameter %s malformed",
|
||||
fname, that->name);
|
||||
if (val.ival < that->min.ival || val.ival > that->max.ival)
|
||||
panic ("Error in config file %s: Value of parameter %s must be "
|
||||
"between %lu and %lu",
|
||||
fname, that->name, that->min.ival, that->max.ival);
|
||||
if (that->value.ival)
|
||||
panic ("Error in config file %s: Parameter %s set twice.\n",
|
||||
fname, that->name);
|
||||
that->value.ival = val.ival;
|
||||
break;
|
||||
case TUN_BOOL:
|
||||
if (!strcasecmp (value, "no") || !strcasecmp (value, "n")
|
||||
|| !strcasecmp (value, "false") || !strcasecmp (value, "f")
|
||||
|| !strcasecmp (value, "0"))
|
||||
val.bval = TUN_FALSE;
|
||||
else if (!strcasecmp (value, "yes") || !strcasecmp (value, "y")
|
||||
|| !strcasecmp (value, "true") || !strcasecmp (value, "t")
|
||||
|| !strcasecmp (value, "1"))
|
||||
val.bval = TUN_TRUE;
|
||||
else
|
||||
panic ("Error in config file %s: Value of parameter %s malformed\n"
|
||||
"Allowed values: \"yes\", \"no\", \"y\", \"n\", \"true\", \"false\", \"t\", \"f\", \"1\" and \"0\"", fname, that->name);
|
||||
that->value.bval = val.bval;
|
||||
break;
|
||||
default:
|
||||
/* Shouldn't happen. */
|
||||
panic ("Internal error: Wrong type of tunable parameter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static tun_struct tunable_params[] =
|
||||
{
|
||||
/* SRV */
|
||||
{ "kern.srv.cleanup_threads", TUN_INT, {0}, {1}, {16}, default_tun_check},
|
||||
{ "kern.srv.request_threads", TUN_INT, {0}, {1}, {64}, default_tun_check},
|
||||
{ "kern.srv.sharedmem", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
{ "kern.srv.msgqueues", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
{ "kern.srv.semaphores", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
|
||||
/* LOG */
|
||||
{ "kern.log.syslog", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
{ "kern.log.stderr", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
{ "kern.log.debug", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
|
||||
{ "kern.log.level", TUN_INT, {0}, {1}, {7}, default_tun_check},
|
||||
|
||||
/* MSG */
|
||||
{ "kern.ipc.msgseg", TUN_INT, {0}, {256}, {32767}, default_tun_check},
|
||||
{ "kern.ipc.msgssz", TUN_INT, {0}, {8}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.msgmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
|
||||
/* SEM */
|
||||
//{ "kern.ipc.semmap", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semmns", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semmnu", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semmsl", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semopm", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semume", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
//{ "kern.ipc.semusz", TUN_INT, {0}, {1}, {1024}, default_tun_check},
|
||||
{ "kern.ipc.semvmx", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
{ "kern.ipc.semaem", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
|
||||
/* SHM */
|
||||
{ "kern.ipc.shmmaxpgs", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
//{ "kern.ipc.shmmin", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
{ "kern.ipc.shmmni", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
{ "kern.ipc.shmseg", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
//{ "kern.ipc.shm_use_phys", TUN_INT, {0}, {1}, {32767}, default_tun_check},
|
||||
{ NULL, TUN_NULL, {0}, {0}, {0}, NULL}
|
||||
};
|
||||
|
||||
#define skip_whitespace(c) while (*(c) && isspace (*(c))) ++(c)
|
||||
#define skip_nonwhitespace(c) while (*(c) && !isspace (*(c)) && *(c) != '#') ++(c)
|
||||
#define end_of_content(c) (!*(c) || *(c) == '#')
|
||||
|
||||
void
|
||||
tunable_param_init (const char *config_file, bool force)
|
||||
{
|
||||
FILE *fp = fopen (config_file, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
if (force)
|
||||
panic ("can't open config file %s\n", config_file);
|
||||
return;
|
||||
}
|
||||
char line[1024];
|
||||
while (fgets (line, 1024, fp))
|
||||
{
|
||||
char *c = strrchr (line, '\n');
|
||||
if (!c)
|
||||
panic ("Line too long in confg file %s\n", config_file);
|
||||
/* Overwrite trailing NL. */
|
||||
*c = '\0';
|
||||
c = line;
|
||||
skip_whitespace (c);
|
||||
if (end_of_content (c))
|
||||
continue;
|
||||
/* So we are on the first character of a parameter name. */
|
||||
char *name = c;
|
||||
/* Find end of name. */
|
||||
skip_nonwhitespace (c);
|
||||
if (end_of_content (c))
|
||||
{
|
||||
*c++ = '\0';
|
||||
panic ("Error in config file %s: Parameter %s has no value.\n",
|
||||
config_file, name);
|
||||
}
|
||||
/* Mark end of name. */
|
||||
*c++ = '\0';
|
||||
skip_whitespace (c);
|
||||
if (end_of_content (c))
|
||||
panic ("Error in config file %s: Parameter %s has no value.\n",
|
||||
config_file, name);
|
||||
/* Now we are on the first character of a parameter's value. */
|
||||
char *value = c;
|
||||
/* This only works for simple parameters. If complex string parameters
|
||||
are added at one point, the scanning routine must be changed here. */
|
||||
/* Find end of value. */
|
||||
skip_nonwhitespace (c);
|
||||
/* Mark end of value. */
|
||||
*c++ = '\0';
|
||||
/* Now look if name is one from our list. */
|
||||
tun_struct *s;
|
||||
for (s = &tunable_params[0]; s->name; ++s)
|
||||
if (!strcmp (name, s->name))
|
||||
{
|
||||
/* Now read value and check for validity. check_func doesn't
|
||||
return on error. */
|
||||
s->check_func (s, value, config_file);
|
||||
break;
|
||||
}
|
||||
if (!s->name)
|
||||
panic ("Error in config file %s: Unknown parameter %s.\n",
|
||||
config_file, name);
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
void
|
||||
tunable_int_fetch (const char *name, long *tunable_target)
|
||||
{
|
||||
tun_struct *s;
|
||||
for (s = &tunable_params[0]; s->name; ++s)
|
||||
if (!strcmp (name, s->name))
|
||||
break;
|
||||
if (!s) /* Not found */
|
||||
return;
|
||||
if (s->type != TUN_INT) /* Wrong type */
|
||||
return;
|
||||
if (!s->value.ival) /* Not set in config file */
|
||||
return;
|
||||
*tunable_target = s->value.ival;
|
||||
debug ("\nSet %s to %lu\n", name, *tunable_target);
|
||||
}
|
||||
|
||||
void
|
||||
tunable_bool_fetch (const char *name, tun_bool_t *tunable_target)
|
||||
{
|
||||
tun_struct *s;
|
||||
const char *tun_bool_val_string[] = { "undefined", "no", "yes" };
|
||||
for (s = &tunable_params[0]; s->name; ++s)
|
||||
if (!strcmp (name, s->name))
|
||||
break;
|
||||
if (!s) /* Not found */
|
||||
return;
|
||||
if (s->type != TUN_BOOL) /* Wrong type */
|
||||
return;
|
||||
if (!s->value.ival) /* Not set in config file */
|
||||
return;
|
||||
*tunable_target = s->value.bval;
|
||||
debug ("\nSet %s to %s\n", name, tun_bool_val_string[*tunable_target]);
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
|
@ -0,0 +1,63 @@
|
|||
/* bsd_helper.h: Helps integrating BSD kernel code
|
||||
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifndef _BSD_HELPER_H
|
||||
#define _BSD_HELPER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
enum tun_bool_t {
|
||||
TUN_UNDEF = 0,
|
||||
TUN_FALSE = 1,
|
||||
TUN_TRUE = 2
|
||||
};
|
||||
|
||||
#define TUNABLE_INT_FETCH(a,b) tunable_int_fetch((a),(b))
|
||||
#define TUNABLE_BOOL_FETCH(a,b) tunable_bool_fetch((a),(b))
|
||||
|
||||
#define sys_malloc(a,b,c) (malloc(a)?:(panic("malloc failed in %s, line %d"),(void*)NULL))
|
||||
#define sys_free(a,b) free(a)
|
||||
|
||||
#define jail_sysvipc_allowed true
|
||||
#define jailed(a) false
|
||||
|
||||
extern const char *__progname;
|
||||
|
||||
/* Global vars, determining whether the IPC stuff should be started or not. */
|
||||
extern tun_bool_t support_sharedmem;
|
||||
extern tun_bool_t support_msgqueues;
|
||||
extern tun_bool_t support_semaphores;
|
||||
|
||||
extern SECURITY_ATTRIBUTES sec_all_nih;
|
||||
|
||||
int win_copyin (struct thread *, const void *, void *, size_t);
|
||||
int win_copyout (struct thread *, const void *, void *, size_t);
|
||||
#define copyin(a,b,c) win_copyin((td),(a),(b),(c))
|
||||
#define copyout(a,b,c) win_copyout((td),(a),(b),(c))
|
||||
|
||||
int ipcperm (struct thread *, struct ipc_perm *, unsigned int);
|
||||
int suser (struct thread *);
|
||||
bool adjust_identity_info (struct proc *p);
|
||||
|
||||
struct vmspace *ipc_p_vmspace (struct proc *);
|
||||
int ipcexit_creat_hookthread(struct thread *);
|
||||
void ipcinit (void);
|
||||
int ipcunload (void);
|
||||
|
||||
vm_object_t _vm_pager_allocate (int, int);
|
||||
#define vm_pager_allocate(a,b,s,c,d) _vm_pager_allocate((s),(mode))
|
||||
vm_object_t vm_object_duplicate (struct thread *td, vm_object_t object);
|
||||
void vm_object_deallocate (vm_object_t object);
|
||||
|
||||
void tunable_param_init (const char *, bool);
|
||||
void tunable_int_fetch (const char *, long *);
|
||||
void tunable_bool_fetch (const char *, tun_bool_t *);
|
||||
|
||||
#endif /* _BSD_HELPER_H */
|
|
@ -0,0 +1,95 @@
|
|||
/* bsd_log.cc
|
||||
|
||||
Copyright 2003 Red Hat Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
#define _KERNEL 1
|
||||
#define __BSD_VISIBLE 1
|
||||
#include <sys/smallprint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
long log_level = 8; /* Illegal value. Don't change! */
|
||||
tun_bool_t log_debug = TUN_UNDEF;
|
||||
tun_bool_t log_syslog = TUN_UNDEF;
|
||||
tun_bool_t log_stderr = TUN_UNDEF;
|
||||
|
||||
void
|
||||
loginit (tun_bool_t opt_stderr, tun_bool_t opt_syslog)
|
||||
{
|
||||
if (log_debug == TUN_UNDEF)
|
||||
TUNABLE_BOOL_FETCH ("kern.log.debug", &log_debug);
|
||||
if (log_debug == TUN_UNDEF)
|
||||
log_debug = TUN_FALSE;
|
||||
|
||||
if (opt_stderr != TUN_UNDEF)
|
||||
log_stderr = opt_stderr;
|
||||
else
|
||||
TUNABLE_BOOL_FETCH ("kern.log.stderr", &log_stderr);
|
||||
if (log_stderr == TUN_UNDEF)
|
||||
log_stderr = TUN_FALSE;
|
||||
|
||||
if (opt_syslog != TUN_UNDEF)
|
||||
log_syslog = opt_syslog;
|
||||
else
|
||||
TUNABLE_BOOL_FETCH ("kern.log.syslog", &log_syslog);
|
||||
if (log_syslog == TUN_UNDEF)
|
||||
log_syslog = TUN_FALSE;
|
||||
|
||||
if (log_level == 8)
|
||||
TUNABLE_INT_FETCH ("kern.log.level", &log_level);
|
||||
if (log_level == 8)
|
||||
log_level = 6;
|
||||
}
|
||||
|
||||
void
|
||||
_vlog (const char *file, int line, int level,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[16384];
|
||||
|
||||
if ((level == LOG_DEBUG && log_debug != TUN_TRUE)
|
||||
|| (level != LOG_DEBUG && level >= log_level))
|
||||
return;
|
||||
strcpy (buf, "cygserver: ");
|
||||
if (file && log_debug == TUN_TRUE)
|
||||
__small_sprintf (strchr (buf, '\0'), "%s, line %d: ", file, line);
|
||||
__small_vsprintf (strchr (buf, '\0'), fmt, ap);
|
||||
if (log_syslog == TUN_TRUE && level != LOG_DEBUG)
|
||||
syslog (level, buf);
|
||||
if (log_stderr == TUN_TRUE || level == LOG_DEBUG)
|
||||
{
|
||||
fputs (buf, stderr);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_log (const char *file, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
_vlog (file, line, level, fmt, ap);
|
||||
}
|
||||
|
||||
void
|
||||
_vpanic (const char *file, int line, const char *fmt, va_list ap)
|
||||
{
|
||||
_vlog (file, line, LOG_EMERG, fmt, ap);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void
|
||||
_panic (const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
_vpanic (file, line, fmt, ap);
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
|
@ -0,0 +1,33 @@
|
|||
/* bsd_log.h: Helps integrating BSD kernel code
|
||||
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifndef _BSD_LOG_H
|
||||
#define _BSD_LOG_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
extern long log_level;
|
||||
extern tun_bool_t log_debug;
|
||||
extern tun_bool_t log_syslog;
|
||||
extern tun_bool_t log_stderr;
|
||||
|
||||
void loginit (tun_bool_t, tun_bool_t);
|
||||
void _vlog (const char *, int, int, const char *, va_list);
|
||||
void _log (const char *, int, int, const char *, ...);
|
||||
void _vpanic (const char *, int, const char *, va_list) __attribute__ ((noreturn));
|
||||
void _panic (const char *, int, const char *, ...) __attribute__ ((noreturn));
|
||||
#define vlog(l,f,a) _vlog(NULL,0,(l),(f),(a))
|
||||
#define log(l,f,...) _log(NULL,0,(l),(f),##__VA_ARGS__)
|
||||
#define vdebug(f,a) _vlog(__FILE__,__LINE__,LOG_DEBUG,(f),(a))
|
||||
#define debug(f,...) _log(__FILE__,__LINE__,LOG_DEBUG,(f),##__VA_ARGS__)
|
||||
#define vpanic(f,a) _vpanic(__FILE__,__LINE__,(f),(a))
|
||||
#define panic(f,...) _panic(__FILE__,__LINE__,(f),##__VA_ARGS__)
|
||||
|
||||
#endif /* _BSD_LOG_H */
|
|
@ -0,0 +1,253 @@
|
|||
/* bsd_mutex.cc
|
||||
|
||||
Copyright 2003 Red Hat Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
#include "cygerrno.h"
|
||||
#define _KERNEL 1
|
||||
#define __BSD_VISIBLE 1
|
||||
#include <sys/smallprint.h>
|
||||
|
||||
#include "process.h"
|
||||
#include "cygserver_ipc.h"
|
||||
|
||||
/* A BSD kernel global mutex. */
|
||||
struct mtx Giant;
|
||||
|
||||
void
|
||||
mtx_init (mtx *m, const char *name, const void *, int)
|
||||
{
|
||||
m->name = name;
|
||||
m->owner = 0;
|
||||
/* Can't use Windows Mutexes here since Windows Mutexes are only
|
||||
unlockable by the lock owner. */
|
||||
m->h = CreateSemaphore (NULL, 1, 1, NULL);
|
||||
if (!m->h)
|
||||
panic ("couldn't allocate %s mutex, %E\n", name);
|
||||
}
|
||||
|
||||
void
|
||||
_mtx_lock (mtx *m, DWORD winpid, const char *file, int line)
|
||||
{
|
||||
_log (file, line, LOG_DEBUG, "Try locking mutex %s", m->name);
|
||||
if (WaitForSingleObject (m->h, INFINITE) != WAIT_OBJECT_0)
|
||||
_panic (file, line, "wait for %s in %d failed, %E", m->name, winpid);
|
||||
m->owner = winpid;
|
||||
_log (file, line, LOG_DEBUG, "Locked mutex %s", m->name);
|
||||
}
|
||||
|
||||
int
|
||||
mtx_owned (mtx *m)
|
||||
{
|
||||
return m->owner > 0;
|
||||
}
|
||||
|
||||
void
|
||||
_mtx_assert(mtx *m, int what, const char *file, int line)
|
||||
{
|
||||
switch (what)
|
||||
{
|
||||
case MA_OWNED:
|
||||
if (!mtx_owned (m))
|
||||
_panic(file, line, "Mutex %s not owned", m->name);
|
||||
break;
|
||||
case MA_NOTOWNED:
|
||||
if (mtx_owned (m))
|
||||
_panic(file, line, "Mutex %s is owned", m->name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_mtx_unlock (mtx *m, const char *file, int line)
|
||||
{
|
||||
m->owner = 0;
|
||||
/* Cautiously check if mtx_destroy has been called (shutdown).
|
||||
In that case, m->h is NULL. */
|
||||
if (m->h && !ReleaseSemaphore (m->h, 1, NULL))
|
||||
{
|
||||
/* Check if the semaphore was already on it's max value. In this case,
|
||||
ReleaseSemaphore returns FALSE with an error code which *sic* depends
|
||||
on the OS. */
|
||||
if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_PARAMETER)
|
||||
|| (wincap.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS))
|
||||
_panic (file, line, "release of mutex %s failed, %E", m->name);
|
||||
}
|
||||
_log (file, line, LOG_DEBUG, "Unlocked mutex %s", m->name);
|
||||
}
|
||||
|
||||
void
|
||||
mtx_destroy (mtx *m)
|
||||
{
|
||||
HANDLE tmp = m->h;
|
||||
m->h = NULL;
|
||||
if (tmp)
|
||||
CloseHandle (tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions for msleep/wakeup.
|
||||
*/
|
||||
static char *
|
||||
msleep_event_name (void *ident, char *name)
|
||||
{
|
||||
if (wincap.has_terminal_services ())
|
||||
__small_sprintf (name, "Global\\cygserver.msleep.evt.%08x", ident);
|
||||
else
|
||||
__small_sprintf (name, "cygserver.msleep.evt.%08x", ident);
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Original description from BSD code:
|
||||
*
|
||||
* General sleep call. Suspends the current process until a wakeup is
|
||||
* performed on the specified identifier. The process will then be made
|
||||
* runnable with the specified priority. Sleeps at most timo/hz seconds
|
||||
* (0 means no timeout). If pri includes PCATCH flag, signals are checked
|
||||
* before and after sleeping, else signals are not checked. Returns 0 if
|
||||
* awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
|
||||
* signal needs to be delivered, ERESTART is returned if the current system
|
||||
* call should be restarted if possible, and EINTR is returned if the system
|
||||
* call should be interrupted by the signal (return EINTR).
|
||||
*
|
||||
* The mutex argument is exited before the caller is suspended, and
|
||||
* entered before msleep returns. If priority includes the PDROP
|
||||
* flag the mutex is not entered before returning.
|
||||
*/
|
||||
static HANDLE msleep_glob_evt;
|
||||
|
||||
void
|
||||
msleep_init (void)
|
||||
{
|
||||
msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
if (!msleep_glob_evt)
|
||||
panic ("CreateEvent in msleep_init failed: %E");
|
||||
}
|
||||
|
||||
static int
|
||||
win_priority (int priority)
|
||||
{
|
||||
int p = (int)((p) & PRIO_MASK) - PZERO;
|
||||
/* Generating a valid priority value is a bit tricky. The only valid
|
||||
values on 9x and NT4 are -15, -2, -1, 0, 1, 2, 15. */
|
||||
switch (p)
|
||||
{
|
||||
case -15: case -14: case -13: case -12: case -11:
|
||||
return THREAD_PRIORITY_IDLE;
|
||||
case -10: case -9: case -8: case -7: case -6:
|
||||
return THREAD_PRIORITY_LOWEST;
|
||||
case -5: case -4: case -3: case -2: case -1:
|
||||
return THREAD_PRIORITY_BELOW_NORMAL;
|
||||
case 0:
|
||||
return THREAD_PRIORITY_NORMAL;
|
||||
case 1: case 2: case 3: case 4: case 5:
|
||||
return THREAD_PRIORITY_ABOVE_NORMAL;
|
||||
case 6: case 7: case 8: case 9: case 10:
|
||||
return THREAD_PRIORITY_HIGHEST;
|
||||
case 11: case 12: case 13: case 14: case 15:
|
||||
return THREAD_PRIORITY_TIME_CRITICAL;
|
||||
}
|
||||
return THREAD_PRIORITY_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the thread priority, returns the old priority.
|
||||
*/
|
||||
static int
|
||||
set_priority (int priority)
|
||||
{
|
||||
int old_prio = GetThreadPriority (GetCurrentThread ());
|
||||
if (!SetThreadPriority (GetCurrentThread (), win_priority(priority)))
|
||||
log (LOG_WARNING,
|
||||
"Warning: Setting thread priority to %d failed with error %lu\n",
|
||||
win_priority(priority), GetLastError ());
|
||||
return old_prio;
|
||||
}
|
||||
|
||||
int
|
||||
_msleep (void *ident, struct mtx *mtx, int priority,
|
||||
const char *wmesg, int timo, struct thread *td)
|
||||
{
|
||||
int ret = -1;
|
||||
char name[64];
|
||||
msleep_event_name (ident, name);
|
||||
HANDLE evt = OpenEvent (EVENT_ALL_ACCESS, FALSE, name);
|
||||
if (!evt)
|
||||
evt = CreateEvent (NULL, TRUE, FALSE, name);
|
||||
if (!evt)
|
||||
panic ("CreateEvent in msleep (%s) failed: %E", wmesg);
|
||||
if (mtx)
|
||||
mtx_unlock (mtx);
|
||||
int old_priority = set_priority (priority);
|
||||
/* PCATCH can't be handled here. */
|
||||
HANDLE obj[3] = { evt, td->client->handle (), msleep_glob_evt };
|
||||
switch (WaitForMultipleObjects (3, obj, FALSE, timo ?: INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0: /* wakeup() has been called. */
|
||||
ret = 0;
|
||||
break;
|
||||
case WAIT_OBJECT_0 + 2: /* Shutdown event (triggered by wakeup_all). */
|
||||
priority |= PDROP;
|
||||
/*FALLTHRU*/
|
||||
case WAIT_OBJECT_0 + 1: /* The dependent process has exited. */
|
||||
ret = EIDRM;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
ret = EWOULDBLOCK;
|
||||
break;
|
||||
default:
|
||||
panic ("wait in msleep (%s) failed, %E", wmesg);
|
||||
break;
|
||||
}
|
||||
set_priority (old_priority);
|
||||
if (!(priority & PDROP) && mtx)
|
||||
mtx_lock (mtx);
|
||||
CloseHandle (evt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make all threads sleeping on the specified identifier runnable.
|
||||
*/
|
||||
int
|
||||
wakeup (void *ident)
|
||||
{
|
||||
char name[64];
|
||||
msleep_event_name (ident, name);
|
||||
HANDLE evt = OpenEvent (EVENT_MODIFY_STATE, FALSE, name);
|
||||
if (!evt)
|
||||
{
|
||||
/* Another round of different error codes returned by 9x and NT
|
||||
systems. Oh boy... */
|
||||
if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_NAME)
|
||||
|| (wincap.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND))
|
||||
panic ("OpenEvent (%s) in wakeup failed: %E", name);
|
||||
}
|
||||
if (evt)
|
||||
{
|
||||
if (!SetEvent (evt))
|
||||
panic ("SetEvent (%s) in wakeup failed, %E", name);
|
||||
CloseHandle (evt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wakeup all sleeping threads. Only called in the context of cygserver
|
||||
* shutdown.
|
||||
*/
|
||||
void
|
||||
wakeup_all (void)
|
||||
{
|
||||
SetEvent (msleep_glob_evt);
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
|
@ -0,0 +1,51 @@
|
|||
/* bsd_mutex.h: BSD Mutex helper
|
||||
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
#ifndef _BSD_MUTEX_H
|
||||
#define _BSD_MUTEX_H
|
||||
|
||||
#define MTX_DEF 0
|
||||
|
||||
#define MA_OWNED 1
|
||||
#define MA_NOTOWNED 2
|
||||
|
||||
#define PZERO (0x20)
|
||||
#define PRIO_MASK (0x1f)
|
||||
#define PDROP 0x1000
|
||||
#define PCATCH 0x2000
|
||||
#define PLOCK 0x3000
|
||||
|
||||
struct mtx {
|
||||
HANDLE h;
|
||||
const char *name;
|
||||
DWORD owner;
|
||||
};
|
||||
|
||||
/* Some BSD kernel global mutex. */
|
||||
extern struct mtx Giant;
|
||||
|
||||
void mtx_init (mtx *, const char *, const void *, int);
|
||||
void _mtx_lock (mtx *, DWORD winpid, const char *, int);
|
||||
#define mtx_lock(m) _mtx_lock((m), (td->ipcblk->winpid), __FILE__, __LINE__)
|
||||
int mtx_owned (mtx *);
|
||||
void _mtx_assert(mtx *, int, const char *, int);
|
||||
#define mtx_assert(m,w) _mtx_assert((m),(w),__FILE__,__LINE__)
|
||||
void _mtx_unlock (mtx *, const char *, int);
|
||||
#define mtx_unlock(m) _mtx_unlock((m),__FILE__,__LINE__)
|
||||
|
||||
void mtx_destroy (mtx *);
|
||||
|
||||
void msleep_init (void);
|
||||
int _msleep (void *, struct mtx *, int, const char *, int, struct thread *);
|
||||
#define msleep(i,m,p,w,t) _msleep((i),(m),(p),(w),(t),(td))
|
||||
#define tsleep(i,p,w,t) _msleep((i),NULL,(p),(w),(t),(td))
|
||||
int wakeup (void *);
|
||||
void wakeup_all (void);
|
||||
|
||||
#endif /* _BSD_MUTEX_H */
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver_client.cc
|
||||
/* client.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Egor Duda <deo@logos-m.ru>
|
||||
|
||||
|
@ -22,11 +22,12 @@ details. */
|
|||
#include <unistd.h>
|
||||
|
||||
#include "cygerrno.h"
|
||||
#include "cygserver_msg.h"
|
||||
#include "cygserver_sem.h"
|
||||
#include "cygserver_shm.h"
|
||||
#include "safe_memory.h"
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "cygserver_transport.h"
|
||||
#include "transport.h"
|
||||
|
||||
int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
|
||||
|
||||
|
@ -48,6 +49,8 @@ client_request_get_version::client_request_get_version ()
|
|||
* the first numbers match, that is).
|
||||
*/
|
||||
|
||||
#ifdef __INSIDE_CYGWIN__
|
||||
|
||||
bool
|
||||
client_request_get_version::check_version () const
|
||||
{
|
||||
|
@ -71,8 +74,6 @@ client_request_get_version::check_version () const
|
|||
return ok;
|
||||
}
|
||||
|
||||
#ifdef __INSIDE_CYGWIN__
|
||||
|
||||
client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
|
||||
HANDLE nfrom_master,
|
||||
HANDLE nto_master)
|
||||
|
@ -87,15 +88,6 @@ client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
|
|||
"from_master = %lu, to_master = %lu"),
|
||||
req.pid, req.master_pid, req.from_master, req.to_master);
|
||||
}
|
||||
|
||||
#else /* !__INSIDE_CYGWIN__ */
|
||||
|
||||
client_request_attach_tty::client_request_attach_tty ()
|
||||
: client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
|
||||
{
|
||||
// verbose: syscall_printf ("created");
|
||||
}
|
||||
|
||||
#endif /* __INSIDE_CYGWIN__ */
|
||||
|
||||
/*
|
||||
|
@ -230,7 +222,12 @@ client_request::send (transport_layer_base * const conn)
|
|||
// sizeof (_header), msglen ());
|
||||
}
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
|
||||
client_request_attach_tty::client_request_attach_tty ()
|
||||
: client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* client_request::handle_request ()
|
||||
|
@ -277,16 +274,22 @@ client_request::handle_request (transport_layer_base *const conn,
|
|||
switch (header.request_code)
|
||||
{
|
||||
case CYGSERVER_REQUEST_GET_VERSION:
|
||||
req = safe_new0 (client_request_get_version);
|
||||
req = new client_request_get_version;
|
||||
break;
|
||||
case CYGSERVER_REQUEST_SHUTDOWN:
|
||||
req = safe_new0 (client_request_shutdown);
|
||||
req = new client_request_shutdown;
|
||||
break;
|
||||
case CYGSERVER_REQUEST_ATTACH_TTY:
|
||||
req = safe_new0 (client_request_attach_tty);
|
||||
req = new client_request_attach_tty;
|
||||
break;
|
||||
case CYGSERVER_REQUEST_MSG:
|
||||
req = new client_request_msg;
|
||||
break;
|
||||
case CYGSERVER_REQUEST_SEM:
|
||||
req = new client_request_sem;
|
||||
break;
|
||||
case CYGSERVER_REQUEST_SHM:
|
||||
req = safe_new0 (client_request_shm);
|
||||
req = new client_request_shm;
|
||||
break;
|
||||
default:
|
||||
syscall_printf ("unknown request code %d received: request ignored",
|
||||
|
@ -299,74 +302,9 @@ client_request::handle_request (transport_layer_base *const conn,
|
|||
req->msglen (header.msglen);
|
||||
req->handle (conn, cache);
|
||||
|
||||
safe_delete (req);
|
||||
|
||||
#ifndef DEBUGGING
|
||||
printf ("."); // A little noise when we're being quiet.
|
||||
#endif
|
||||
delete req;
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
||||
client_request::client_request (request_code_t const id,
|
||||
void * const buf,
|
||||
size_t const buflen)
|
||||
: _header (id, buflen),
|
||||
_buf (buf),
|
||||
_buflen (buflen)
|
||||
{
|
||||
assert ((!_buf && !_buflen) || (_buf && _buflen));
|
||||
}
|
||||
|
||||
client_request::~client_request ()
|
||||
{}
|
||||
|
||||
int
|
||||
client_request::make_request ()
|
||||
{
|
||||
assert (cygserver_running == CYGSERVER_UNKNOWN \
|
||||
|| cygserver_running == CYGSERVER_OK \
|
||||
|| cygserver_running == CYGSERVER_UNAVAIL);
|
||||
|
||||
if (cygserver_running == CYGSERVER_UNKNOWN)
|
||||
cygserver_init ();
|
||||
|
||||
assert (cygserver_running == CYGSERVER_OK \
|
||||
|| cygserver_running == CYGSERVER_UNAVAIL);
|
||||
|
||||
/* Don't retry every request if the server's not there */
|
||||
if (cygserver_running == CYGSERVER_UNAVAIL)
|
||||
{
|
||||
syscall_printf ("cygserver un-available");
|
||||
error_code (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
transport_layer_base *const transport = create_server_transport ();
|
||||
|
||||
assert (transport);
|
||||
|
||||
if (transport->connect () == -1)
|
||||
{
|
||||
if (errno)
|
||||
error_code (errno);
|
||||
else
|
||||
error_code (ENOSYS);
|
||||
safe_delete (transport);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// verbose: debug_printf ("connected to server %p", transport);
|
||||
|
||||
send (transport);
|
||||
|
||||
safe_delete (transport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
|
||||
/*
|
||||
* client_request::handle ()
|
||||
*
|
||||
|
@ -470,7 +408,84 @@ client_request::handle (transport_layer_base *const conn,
|
|||
// sizeof (_header), msglen ());
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
/* The server side implementation of make_request. Very simple. */
|
||||
int
|
||||
client_request::make_request ()
|
||||
{
|
||||
transport_layer_base *const transport = create_server_transport ();
|
||||
assert (transport);
|
||||
if (transport->connect () == -1)
|
||||
{
|
||||
if (errno)
|
||||
error_code (errno);
|
||||
else
|
||||
error_code (ENOSYS);
|
||||
delete transport;
|
||||
return -1;
|
||||
}
|
||||
send (transport);
|
||||
delete transport;
|
||||
return 0;
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
||||
client_request::client_request (request_code_t const id,
|
||||
void * const buf,
|
||||
size_t const buflen)
|
||||
: _header (id, buflen),
|
||||
_buf (buf),
|
||||
_buflen (buflen)
|
||||
{
|
||||
assert ((!_buf && !_buflen) || (_buf && _buflen));
|
||||
}
|
||||
|
||||
client_request::~client_request ()
|
||||
{}
|
||||
|
||||
#ifdef __INSIDE_CYGWIN__
|
||||
int
|
||||
client_request::make_request ()
|
||||
{
|
||||
assert (cygserver_running == CYGSERVER_UNKNOWN \
|
||||
|| cygserver_running == CYGSERVER_OK \
|
||||
|| cygserver_running == CYGSERVER_UNAVAIL);
|
||||
|
||||
if (cygserver_running == CYGSERVER_UNKNOWN)
|
||||
cygserver_init ();
|
||||
|
||||
assert (cygserver_running == CYGSERVER_OK \
|
||||
|| cygserver_running == CYGSERVER_UNAVAIL);
|
||||
|
||||
/* Don't retry every request if the server's not there */
|
||||
if (cygserver_running == CYGSERVER_UNAVAIL)
|
||||
{
|
||||
syscall_printf ("cygserver un-available");
|
||||
error_code (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
transport_layer_base *const transport = create_server_transport ();
|
||||
|
||||
assert (transport);
|
||||
|
||||
if (transport->connect () == -1)
|
||||
{
|
||||
if (errno)
|
||||
error_code (errno);
|
||||
else
|
||||
error_code (ENOSYS);
|
||||
delete transport;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// verbose: debug_printf ("connected to server %p", transport);
|
||||
|
||||
send (transport);
|
||||
|
||||
delete transport;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
check_cygserver_available ()
|
||||
|
@ -523,3 +538,4 @@ cygserver_init ()
|
|||
if (!check_cygserver_available ())
|
||||
cygserver_running = CYGSERVER_UNAVAIL;
|
||||
}
|
||||
#endif /* __INSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Egor Duda <deo@logos-m.ru>
|
||||
|
||||
|
@ -10,6 +10,7 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -27,100 +28,21 @@ details. */
|
|||
#include "cygwin_version.h"
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "cygserver_process.h"
|
||||
#include "cygserver_transport.h"
|
||||
#include "process.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_msg.h"
|
||||
#include "cygserver_sem.h"
|
||||
|
||||
#define DEF_CONFIG_FILE "" SYSCONFDIR "/cygserver.conf"
|
||||
|
||||
// Version string.
|
||||
static const char version[] = "$Revision$";
|
||||
|
||||
/*
|
||||
* Support function for the XXX_printf () macros in "woutsup.h".
|
||||
* Copied verbatim from "strace.cc".
|
||||
*/
|
||||
static int
|
||||
getfunc (char *in_dst, const char *func)
|
||||
{
|
||||
const char *p;
|
||||
const char *pe;
|
||||
char *dst = in_dst;
|
||||
for (p = func; (pe = strchr (p, '(')); p = pe + 1)
|
||||
if (isalnum ((int)pe[-1]) || pe[-1] == '_')
|
||||
break;
|
||||
else if (isspace ((int)pe[-1]))
|
||||
{
|
||||
pe--;
|
||||
break;
|
||||
}
|
||||
if (!pe)
|
||||
pe = strchr (func, '\0');
|
||||
for (p = pe; p > func; p--)
|
||||
if (p != pe && *p == ' ')
|
||||
{
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
if (*p == '*')
|
||||
p++;
|
||||
while (p < pe)
|
||||
*dst++ = *p++;
|
||||
|
||||
*dst++ = ':';
|
||||
*dst++ = ' ';
|
||||
*dst = '\0';
|
||||
|
||||
return dst - in_dst;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support function for the XXX_printf () macros in "woutsup.h".
|
||||
*/
|
||||
extern "C" void
|
||||
__cygserver__printf (const char *const function, const char *const fmt, ...)
|
||||
{
|
||||
const DWORD lasterror = GetLastError ();
|
||||
const int lasterrno = errno;
|
||||
|
||||
va_list ap;
|
||||
|
||||
char *const buf = (char *) alloca (BUFSIZ);
|
||||
|
||||
assert (buf);
|
||||
|
||||
int len = 0;
|
||||
|
||||
if (function)
|
||||
len += getfunc (buf, function);
|
||||
|
||||
va_start (ap, fmt);
|
||||
len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
len += snprintf (buf + len, BUFSIZ - len, "\n");
|
||||
|
||||
const int actual = (len > BUFSIZ ? BUFSIZ : len);
|
||||
|
||||
write (2, buf, actual);
|
||||
|
||||
errno = lasterrno;
|
||||
SetLastError (lasterror);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUGGING
|
||||
|
||||
int __stdcall
|
||||
__set_errno (const char *func, int ln, int val)
|
||||
{
|
||||
debug_printf ("%s:%d val %d", func, ln, val);
|
||||
return _impure_ptr->_errno = val;
|
||||
}
|
||||
|
||||
#endif /* DEBUGGING */
|
||||
|
||||
GENERIC_MAPPING access_mapping;
|
||||
|
||||
static BOOL
|
||||
static bool
|
||||
setup_privileges ()
|
||||
{
|
||||
BOOL rc, ret_val;
|
||||
|
@ -130,15 +52,14 @@ setup_privileges ()
|
|||
rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
|
||||
if (!rc)
|
||||
{
|
||||
system_printf ("error opening process token (%lu)", GetLastError ());
|
||||
ret_val = FALSE;
|
||||
goto out;
|
||||
debug ("error opening process token (%lu)", GetLastError ());
|
||||
return false;
|
||||
}
|
||||
rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
|
||||
if (!rc)
|
||||
{
|
||||
system_printf ("error getting privilege luid (%lu)", GetLastError ());
|
||||
ret_val = FALSE;
|
||||
debug ("error getting privilege luid (%lu)", GetLastError ());
|
||||
ret_val = false;
|
||||
goto out;
|
||||
}
|
||||
sPrivileges.PrivilegeCount = 1 ;
|
||||
|
@ -146,9 +67,8 @@ setup_privileges ()
|
|||
rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
|
||||
if (!rc)
|
||||
{
|
||||
system_printf ("error adjusting privilege level. (%lu)",
|
||||
GetLastError ());
|
||||
ret_val = FALSE;
|
||||
debug ("error adjusting privilege level. (%lu)", GetLastError ());
|
||||
ret_val = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -157,7 +77,7 @@ setup_privileges ()
|
|||
access_mapping.GenericExecute = 0;
|
||||
access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA;
|
||||
|
||||
ret_val = TRUE;
|
||||
ret_val = true;
|
||||
|
||||
out:
|
||||
CloseHandle (hToken);
|
||||
|
@ -181,7 +101,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
|
|||
0, bInheritHandle,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
system_printf ("error getting handle(%u) to server (%lu)",
|
||||
log (LOG_ERR, "error getting handle(%u) to server (%lu)",
|
||||
(unsigned int)from_handle, GetLastError ());
|
||||
goto out;
|
||||
}
|
||||
|
@ -205,7 +125,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
|
|||
| DACL_SECURITY_INFORMATION),
|
||||
sd, sizeof (sd_buf), &bytes_needed))
|
||||
{
|
||||
system_printf ("error getting handle SD (%lu)", GetLastError ());
|
||||
log (LOG_ERR, "error getting handle SD (%lu)", GetLastError ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -214,14 +134,14 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
|
|||
if (!AccessCheck (sd, from_process_token, access, &access_mapping,
|
||||
&ps, &ps_len, &access, &status))
|
||||
{
|
||||
system_printf ("error checking access rights (%lu)",
|
||||
log (LOG_ERR, "error checking access rights (%lu)",
|
||||
GetLastError ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
system_printf ("access to object denied");
|
||||
log (LOG_ERR, "access to object denied");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -230,11 +150,11 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
|
|||
to_process, to_handle_ptr,
|
||||
access, bInheritHandle, 0))
|
||||
{
|
||||
system_printf ("error getting handle to client (%lu)", GetLastError ());
|
||||
log (LOG_ERR, "error getting handle to client (%lu)", GetLastError ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
// verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr);
|
||||
debug ("Duplicated %p to %p", from_handle, *to_handle_ptr);
|
||||
|
||||
ret_val = 0;
|
||||
|
||||
|
@ -259,7 +179,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
|
||||
if (!wincap.has_security ())
|
||||
{
|
||||
syscall_printf ("operation only supported on systems with security");
|
||||
log (LOG_NOTICE, "operation only supported on systems with security");
|
||||
error_code (EINVAL);
|
||||
msglen (0);
|
||||
return;
|
||||
|
@ -267,7 +187,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
|
||||
if (msglen () != sizeof (req))
|
||||
{
|
||||
syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
|
||||
log (LOG_ERR, "bad request body length: expecting %lu bytes, got %lu",
|
||||
sizeof (req), msglen ());
|
||||
error_code (EINVAL);
|
||||
msglen (0);
|
||||
|
@ -276,54 +196,65 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
|
||||
msglen (0); // Until we fill in some fields.
|
||||
|
||||
// verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld",
|
||||
// req.master_pid, req.from_master, req.to_master,
|
||||
// req.pid);
|
||||
debug ("pid %ld:(%p,%p) -> pid %ld", req.master_pid, req.from_master,
|
||||
req.to_master, req.pid);
|
||||
|
||||
// verbose: debug_printf ("opening process %ld", req.master_pid);
|
||||
debug ("opening process %ld", req.master_pid);
|
||||
|
||||
const HANDLE from_process_handle =
|
||||
OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
|
||||
|
||||
if (!from_process_handle)
|
||||
{
|
||||
system_printf ("error opening `from' process, error = %lu",
|
||||
log (LOG_ERR, "error opening `from' process, error = %lu",
|
||||
GetLastError ());
|
||||
error_code (EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
// verbose: debug_printf ("opening process %ld", req.pid);
|
||||
debug ("opening process %ld", req.pid);
|
||||
|
||||
const HANDLE to_process_handle =
|
||||
OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
|
||||
|
||||
if (!to_process_handle)
|
||||
{
|
||||
system_printf ("error opening `to' process, error = %lu",
|
||||
log (LOG_ERR, "error opening `to' process, error = %lu",
|
||||
GetLastError ());
|
||||
CloseHandle (from_process_handle);
|
||||
error_code (EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
// verbose: debug_printf ("Impersonating client");
|
||||
conn->impersonate_client ();
|
||||
debug ("Impersonating client");
|
||||
if (!conn->impersonate_client ())
|
||||
{
|
||||
CloseHandle (from_process_handle);
|
||||
CloseHandle (to_process_handle);
|
||||
error_code (EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE token_handle = NULL;
|
||||
|
||||
// verbose: debug_printf ("about to open thread token");
|
||||
debug ("about to open thread token");
|
||||
const DWORD rc = OpenThreadToken (GetCurrentThread (),
|
||||
TOKEN_QUERY,
|
||||
TRUE,
|
||||
&token_handle);
|
||||
|
||||
// verbose: debug_printf ("opened thread token, rc=%lu", rc);
|
||||
conn->revert_to_self ();
|
||||
debug ("opened thread token, rc=%lu", rc);
|
||||
if (!conn->revert_to_self ())
|
||||
{
|
||||
CloseHandle (from_process_handle);
|
||||
CloseHandle (to_process_handle);
|
||||
error_code (EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
system_printf ("error opening thread token, error = %lu",
|
||||
log (LOG_ERR, "error opening thread token, error = %lu",
|
||||
GetLastError ());
|
||||
CloseHandle (from_process_handle);
|
||||
CloseHandle (to_process_handle);
|
||||
|
@ -348,7 +279,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
from_master,
|
||||
&req.from_master, TRUE) != 0)
|
||||
{
|
||||
system_printf ("error duplicating from_master handle, error = %lu",
|
||||
log (LOG_ERR, "error duplicating from_master handle, error = %lu",
|
||||
GetLastError ());
|
||||
error_code (EACCES);
|
||||
}
|
||||
|
@ -360,7 +291,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
to_master,
|
||||
&req.to_master, TRUE) != 0)
|
||||
{
|
||||
system_printf ("error duplicating to_master handle, error = %lu",
|
||||
log (LOG_ERR, "error duplicating to_master handle, error = %lu",
|
||||
GetLastError ());
|
||||
error_code (EACCES);
|
||||
}
|
||||
|
@ -369,7 +300,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
|
|||
CloseHandle (to_process_handle);
|
||||
CloseHandle (token_handle);
|
||||
|
||||
debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)",
|
||||
debug ("%lu(%lu, %lu) -> %lu(%lu,%lu)",
|
||||
req.master_pid, from_master, to_master,
|
||||
req.pid, req.from_master, req.to_master);
|
||||
|
||||
|
@ -382,7 +313,7 @@ client_request_get_version::serve (transport_layer_base *, process_cache *)
|
|||
assert (!error_code ());
|
||||
|
||||
if (msglen ())
|
||||
syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
|
||||
log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
|
||||
|
||||
msglen (sizeof (version));
|
||||
|
||||
|
@ -401,7 +332,7 @@ public:
|
|||
|
||||
virtual ~server_request ()
|
||||
{
|
||||
safe_delete (_conn);
|
||||
delete _conn;
|
||||
}
|
||||
|
||||
virtual void process ()
|
||||
|
@ -455,8 +386,8 @@ server_submission_loop::request_loop ()
|
|||
*/
|
||||
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
|
||||
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
|
||||
debug_printf ("failed to raise accept thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
debug ("failed to raise accept thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
|
||||
while (_running)
|
||||
{
|
||||
|
@ -464,7 +395,7 @@ server_submission_loop::request_loop ()
|
|||
transport_layer_base *const conn = _transport->accept (&recoverable);
|
||||
if (!conn && !recoverable)
|
||||
{
|
||||
system_printf ("fatal error on IPC transport: closing down");
|
||||
log (LOG_ERR, "fatal error on IPC transport: closing down");
|
||||
return;
|
||||
}
|
||||
// EINTR probably implies a shutdown request; so back off for a
|
||||
|
@ -474,26 +405,25 @@ server_submission_loop::request_loop ()
|
|||
if (!conn && errno == EINTR)
|
||||
{
|
||||
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
|
||||
debug_printf ("failed to reset thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
debug ("failed to reset thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
|
||||
Sleep (0);
|
||||
if (!SetThreadPriority (GetCurrentThread (),
|
||||
THREAD_PRIORITY_HIGHEST + 1))
|
||||
if (!SetThreadPriority (GetCurrentThread (),
|
||||
THREAD_PRIORITY_HIGHEST))
|
||||
debug_printf ("failed to raise thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
debug ("failed to raise thread priority, error = %lu",
|
||||
GetLastError ());
|
||||
}
|
||||
if (conn)
|
||||
_queue->add (safe_new (server_request, conn, _cache));
|
||||
_queue->add (new server_request (conn, _cache));
|
||||
}
|
||||
}
|
||||
|
||||
client_request_shutdown::client_request_shutdown ()
|
||||
: client_request (CYGSERVER_REQUEST_SHUTDOWN)
|
||||
{
|
||||
// verbose: syscall_printf ("created");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -502,7 +432,7 @@ client_request_shutdown::serve (transport_layer_base *, process_cache *)
|
|||
assert (!error_code ());
|
||||
|
||||
if (msglen ())
|
||||
syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
|
||||
log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
|
||||
|
||||
/* FIXME: link upwards, and then this becomes a trivial method call to
|
||||
* only shutdown _this queue_
|
||||
|
@ -530,12 +460,33 @@ handle_signal (const int signum)
|
|||
static void
|
||||
print_usage (const char *const pgm)
|
||||
{
|
||||
printf ("Usage: %s [OPTIONS]\n", pgm);
|
||||
printf (" -c, --cleanup-threads number of cleanup threads to use\n");
|
||||
printf (" -h, --help output usage information and exit\n");
|
||||
printf (" -r, --request-threads number of request threads to use\n");
|
||||
printf (" -s, --shutdown shutdown the daemon\n");
|
||||
printf (" -v, --version output version information and exit\n");
|
||||
log (LOG_NOTICE, "Usage: %s [OPTIONS]\n"
|
||||
"Configuration option:\n"
|
||||
" -f, --config-file <file> Use <file> as config file. Default is\n"
|
||||
"\n"
|
||||
"Performance options:\n"
|
||||
" -c, --cleanup-threads <num> Number of cleanup threads to use.\n"
|
||||
" -r, --request-threads <num> Number of request threads to use.\n"
|
||||
"\n"
|
||||
"Logging options:\n"
|
||||
" -d, --debug Log debug messages to stderr.\n"
|
||||
" -e, --stderr Log to stderr (default if stderr is a tty).\n"
|
||||
" -E, --no-stderr Don't log to stderr (see -y, -Y options).\n"
|
||||
" " DEF_CONFIG_FILE "\n"
|
||||
" -l, --log-level <level> Verbosity of logging (1..7). Default: 6\n"
|
||||
" -y, --syslog Log to syslog (default if stderr is no tty).\n"
|
||||
" -Y, --no-syslog Don't log to syslog (See -e, -E options).\n"
|
||||
"\n"
|
||||
"Support options:\n"
|
||||
" -m, --no-sharedmem Don't start XSI Shared Memory support.\n"
|
||||
" -q, --no-msgqueues Don't start XSI Message Queue support.\n"
|
||||
" -s, --no-semaphores Don't start XSI Semaphore support.\n"
|
||||
"\n"
|
||||
"Miscellaneous:\n"
|
||||
" -S, --shutdown Shutdown the daemon.\n"
|
||||
" -h, --help Output usage information and exit.\n"
|
||||
" -v, --version Output version information and exit."
|
||||
, pgm);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -543,7 +494,7 @@ print_usage (const char *const pgm)
|
|||
*/
|
||||
|
||||
static void
|
||||
print_version (const char *const pgm)
|
||||
print_version ()
|
||||
{
|
||||
char *vn = NULL;
|
||||
|
||||
|
@ -578,10 +529,12 @@ print_version (const char *const pgm)
|
|||
cygwin_version.mount_registry,
|
||||
cygwin_version.dll_build_date);
|
||||
|
||||
printf ("%s (cygwin) %s\n", pgm, vn);
|
||||
printf ("API version %s\n", buf);
|
||||
printf ("Copyright 2001, 2002 Red Hat, Inc.\n");
|
||||
printf ("Compiled on %s\n", __DATE__);
|
||||
log (LOG_INFO, "(cygwin) %s\n"
|
||||
"API version %s\n"
|
||||
"Copyright 2001, 2002, 2003 Red Hat, Inc.\n"
|
||||
"Compiled on %s\n"
|
||||
"Default configuration file is %s",
|
||||
vn, buf, __DATE__, DEF_CONFIG_FILE);
|
||||
|
||||
free (vn);
|
||||
}
|
||||
|
@ -595,79 +548,127 @@ main (const int argc, char *argv[])
|
|||
{
|
||||
const struct option longopts[] = {
|
||||
{"cleanup-threads", required_argument, NULL, 'c'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{"stderr", no_argument, NULL, 'e'},
|
||||
{"no-stderr", no_argument, NULL, 'E'},
|
||||
{"config-file", required_argument, NULL, 'f'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"log-level", required_argument, NULL, 'l'},
|
||||
{"no-sharedmem", no_argument, NULL, 'm'},
|
||||
{"no-msgqueues", no_argument, NULL, 'q'},
|
||||
{"request-threads", required_argument, NULL, 'r'},
|
||||
{"shutdown", no_argument, NULL, 's'},
|
||||
{"no-semaphores", no_argument, NULL, 's'},
|
||||
{"shutdown", no_argument, NULL, 'S'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"syslog", no_argument, NULL, 'y'},
|
||||
{"no-syslog", no_argument, NULL, 'Y'},
|
||||
{0, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
const char opts[] = "c:hr:sv";
|
||||
const char opts[] = "c:deEf:hl:mqr:sSvyY";
|
||||
|
||||
int cleanup_threads = 2;
|
||||
int request_threads = 10;
|
||||
long cleanup_threads = 0;
|
||||
long request_threads = 0;
|
||||
bool shutdown = false;
|
||||
const char *config_file = DEF_CONFIG_FILE;
|
||||
bool force_config_file = false;
|
||||
tun_bool_t option_log_stderr = TUN_UNDEF;
|
||||
tun_bool_t option_log_syslog = TUN_UNDEF;
|
||||
|
||||
const char *pgm = NULL;
|
||||
char *c = NULL;
|
||||
|
||||
if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/')))
|
||||
pgm = *argv;
|
||||
/* Check if we have a terminal. If so, default to stderr logging,
|
||||
otherwise default to syslog logging. This must be done early
|
||||
to allow default logging already in option processing state. */
|
||||
openlog ("cygserver", LOG_PID, LOG_KERN);
|
||||
if (isatty (2))
|
||||
log_stderr = TUN_TRUE;
|
||||
else
|
||||
pgm++;
|
||||
|
||||
wincap.init ();
|
||||
if (wincap.has_security ())
|
||||
setup_privileges ();
|
||||
log_syslog = TUN_TRUE;
|
||||
|
||||
int opt;
|
||||
|
||||
opterr = 0;
|
||||
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
cleanup_threads = atoi (optarg);
|
||||
if (cleanup_threads <= 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: number of cleanup threads must be positive\n",
|
||||
pgm);
|
||||
exit (1);
|
||||
}
|
||||
c = NULL;
|
||||
cleanup_threads = strtol (optarg, &c, 10);
|
||||
if (cleanup_threads <= 0 || cleanup_threads > 16 || (c && *c))
|
||||
panic ("Number of cleanup threads must be between 1 and 16");
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
log_debug = TUN_TRUE;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
option_log_stderr = TUN_TRUE;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
option_log_stderr = TUN_FALSE;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
config_file = optarg;
|
||||
force_config_file = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage (pgm);
|
||||
print_usage (getprogname ());
|
||||
return 0;
|
||||
|
||||
case 'l':
|
||||
c = NULL;
|
||||
log_level = strtoul (optarg, &c, 10);
|
||||
if (!log_level || log_level > 7 || (c && *c))
|
||||
panic ("Log level must be between 1 and 7");
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
support_sharedmem = TUN_FALSE;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
support_msgqueues = TUN_FALSE;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
request_threads = atoi (optarg);
|
||||
if (request_threads <= 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: number of request threads must be positive\n",
|
||||
pgm);
|
||||
exit (1);
|
||||
}
|
||||
c = NULL;
|
||||
request_threads = strtol (optarg, &c, 10);
|
||||
if (request_threads <= 0 || request_threads > 64 || (c && *c))
|
||||
panic ("Number of request threads must be between 1 and 64");
|
||||
break;
|
||||
|
||||
case 's':
|
||||
support_semaphores = TUN_FALSE;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
shutdown = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
print_version (pgm);
|
||||
print_version ();
|
||||
return 0;
|
||||
|
||||
case 'y':
|
||||
option_log_syslog = TUN_TRUE;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
option_log_syslog = TUN_FALSE;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
fprintf (stderr, "Try `%s --help' for more information.\n", pgm);
|
||||
exit (1);
|
||||
panic ("unknown option -- %c\n"
|
||||
"Try `%s --help' for more information.", optopt, getprogname ());
|
||||
}
|
||||
|
||||
if (optind != argc)
|
||||
{
|
||||
fprintf (stderr, "%s: too many arguments\n", pgm);
|
||||
exit (1);
|
||||
}
|
||||
panic ("Too many arguments");
|
||||
|
||||
if (shutdown)
|
||||
{
|
||||
|
@ -679,71 +680,76 @@ main (const int argc, char *argv[])
|
|||
client_request_shutdown req;
|
||||
|
||||
if (req.make_request () == -1 || req.error_code ())
|
||||
{
|
||||
fprintf (stderr, "%s: shutdown request failed: %s\n",
|
||||
pgm, strerror (req.error_code ()));
|
||||
exit (1);
|
||||
}
|
||||
panic("Shutdown request failed: %s", strerror (req.error_code ()));
|
||||
|
||||
// FIXME: It would be nice to wait here for the daemon to exit.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SIGHANDLE(SIG) \
|
||||
do \
|
||||
{ \
|
||||
struct sigaction act; \
|
||||
\
|
||||
act.sa_handler = &handle_signal; \
|
||||
act.sa_mask = 0; \
|
||||
act.sa_flags = 0; \
|
||||
\
|
||||
if (sigaction (SIG, &act, NULL) == -1) \
|
||||
{ \
|
||||
system_printf ("failed to install handler for " #SIG ": %s", \
|
||||
strerror (errno)); \
|
||||
exit (1); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
SIGHANDLE (SIGHUP);
|
||||
SIGHANDLE (SIGINT);
|
||||
SIGHANDLE (SIGTERM);
|
||||
|
||||
print_version (pgm);
|
||||
setbuf (stdout, NULL);
|
||||
printf ("daemon starting up");
|
||||
tunable_param_init (config_file, force_config_file);
|
||||
|
||||
loginit (option_log_stderr, option_log_syslog);
|
||||
|
||||
log (LOG_INFO, "daemon starting up");
|
||||
|
||||
if (!cleanup_threads)
|
||||
TUNABLE_INT_FETCH ("kern.srv.cleanup_threads", &cleanup_threads);
|
||||
if (!cleanup_threads)
|
||||
cleanup_threads = 2;
|
||||
|
||||
if (!request_threads)
|
||||
TUNABLE_INT_FETCH ("kern.srv.request_threads", &request_threads);
|
||||
if (!request_threads)
|
||||
request_threads = 10;
|
||||
|
||||
if (support_sharedmem == TUN_UNDEF)
|
||||
TUNABLE_BOOL_FETCH ("kern.srv.sharedmem", &support_sharedmem);
|
||||
if (support_sharedmem == TUN_UNDEF)
|
||||
support_sharedmem = TUN_TRUE;
|
||||
|
||||
if (support_msgqueues == TUN_UNDEF)
|
||||
TUNABLE_BOOL_FETCH ("kern.srv.msgqueues", &support_msgqueues);
|
||||
if (support_msgqueues == TUN_UNDEF)
|
||||
support_msgqueues = TUN_TRUE;
|
||||
|
||||
if (support_semaphores == TUN_UNDEF)
|
||||
TUNABLE_BOOL_FETCH ("kern.srv.semaphores", &support_semaphores);
|
||||
if (support_semaphores == TUN_UNDEF)
|
||||
support_semaphores = TUN_TRUE;
|
||||
|
||||
wincap.init ();
|
||||
if (wincap.has_security () && !setup_privileges ())
|
||||
panic ("Setting process privileges failed.");
|
||||
|
||||
/*XXXXX*/
|
||||
threaded_queue request_queue (request_threads);
|
||||
printf (".");
|
||||
|
||||
transport_layer_base *const transport = create_server_transport ();
|
||||
assert (transport);
|
||||
printf (".");
|
||||
|
||||
process_cache cache (cleanup_threads);
|
||||
printf (".");
|
||||
|
||||
server_submission_loop submission_loop (&request_queue, transport, &cache);
|
||||
printf (".");
|
||||
|
||||
request_queue.add_submission_loop (&submission_loop);
|
||||
printf (".");
|
||||
|
||||
if (transport->listen () == -1)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
printf (".");
|
||||
|
||||
ipcinit ();
|
||||
|
||||
cache.start ();
|
||||
printf (".");
|
||||
|
||||
request_queue.start ();
|
||||
printf (".");
|
||||
|
||||
printf ("complete\n");
|
||||
log (LOG_NOTICE, "Initialization complete. Waiting for requests.");
|
||||
|
||||
/* TODO: wait on multiple objects - the thread handle for each
|
||||
* request loop + all the process handles. This should be done by
|
||||
|
@ -758,16 +764,25 @@ main (const int argc, char *argv[])
|
|||
-- if signal event then retrigger it
|
||||
*/
|
||||
while (!shutdown_server && request_queue.running () && cache.running ())
|
||||
pause ();
|
||||
{
|
||||
pause ();
|
||||
if (ipcunload ())
|
||||
{
|
||||
shutdown_server = false;
|
||||
log (LOG_WARNING, "Shutdown request received but ignored. "
|
||||
"Dependent processes still running.");
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\nShutdown request received - new requests will be denied\n");
|
||||
log (LOG_INFO, "Shutdown request received - new requests will be denied");
|
||||
request_queue.stop ();
|
||||
printf ("All pending requests processed\n");
|
||||
safe_delete (transport);
|
||||
printf ("No longer accepting requests - cygwin will operate in daemonless mode\n");
|
||||
log (LOG_INFO, "All pending requests processed");
|
||||
delete transport;
|
||||
log (LOG_INFO, "No longer accepting requests - cygwin will operate in daemonless mode");
|
||||
cache.stop ();
|
||||
printf ("All outstanding process-cache activities completed\n");
|
||||
printf ("daemon shutdown\n");
|
||||
log (LOG_INFO, "All outstanding process-cache activities completed");
|
||||
log (LOG_NOTICE, "Shutdown finished.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# cygserver.conf, Copyright(C) 2003 Red Hat Inc.
|
||||
#
|
||||
# Contains configurable parameters for the cygserver.
|
||||
#
|
||||
# The format of this file is easy. Lines beginning with a hash `#' are
|
||||
# comments and ignored. Lines consisting of only whitespaces are ignored.
|
||||
# Any other line is a setting for cygserver.
|
||||
# A setting consists of a name/value pair, separated by whitespace.
|
||||
# Each line must only consist of one name/value pair.
|
||||
# Lines must not be longer than 1023 characters.
|
||||
#
|
||||
# Some settings can be overridden by a command line switch. If so, it's
|
||||
# mentioned below.
|
||||
#
|
||||
# Settings which are commented out will use the default values. These are
|
||||
# mentioned below, too.
|
||||
|
||||
# kern.srv.cleanup_threads: No. of cygserver threads used for cleanup tasks.
|
||||
# Default: 2, Min: 1, Max: 16, command line option -c, --cleanup-threads
|
||||
#kern.srv.cleanup_threads 2
|
||||
|
||||
# kern.srv.request_threads: No. of cygserver threads used to serve
|
||||
# application requests.
|
||||
# Default: 10, Min: 1, Max: 64, command line option -r, --request-threads
|
||||
#kern.srv.request_threads 10
|
||||
|
||||
# kern.srv.msgqueues: Determines whether XSI Message Queue support should be
|
||||
# started, "yes" (or "true", "y", "t", "1") or "no" (or "false", "n", "f", "0").
|
||||
# These values are valid for all binary type options.
|
||||
# Default is "yes". Command line option -q, --no-msgqueues
|
||||
#kern.srv.msgqueues yes
|
||||
|
||||
# kern.srv.semaphores: Determines whether XSI Semaphore support should be
|
||||
# started. Default is "yes". Command line option -s, --no-semaphores
|
||||
#kern.srv.semaphores yes
|
||||
|
||||
# kern.srv.sharedmem: Determines whether XSI Shared Memory support should be
|
||||
# started. Default is "yes". Command line option -m, --no-sharedmem
|
||||
#kern.srv.sharedmem yes
|
||||
|
||||
# LOGGING
|
||||
|
||||
# kern.log.syslog: Determines whether logging should go to the syslog,
|
||||
# Default is "yes", if stderr is no tty, "no" otherwise.
|
||||
# Command line option -y, --syslog or -Y, --no-syslog.
|
||||
#kern.log.syslog no
|
||||
|
||||
# kern.log.stderr: Determines whether logging should go to stderr,
|
||||
# Default is "yes", if stderr is a tty, "no" otherwise.
|
||||
# Command line option -e, --stderr or -E, --no-stderr.
|
||||
#kern.log.stderr no
|
||||
|
||||
# kern.log.level: Logging level. Valid values are 1 to 7 with a bigger
|
||||
# value emitting more logging output. Default level is 6.
|
||||
# Command line option -l, --log-level.
|
||||
#kern.log.level 6
|
||||
|
||||
# kern.log.debug: Determines whether debug output should be printed to stderr.
|
||||
# Default is "no". Command line option -d, --debug
|
||||
#kern.log.debug no
|
||||
|
||||
# XSI message queue parameters.
|
||||
#
|
||||
# Each message is broken up and stored in segments that are msgssz bytes
|
||||
# long. For efficiency reasons, this should be a power of two. Also,
|
||||
# it doesn't make sense if it is less than 8 or greater than about 256.
|
||||
|
||||
# kern.ipc.msgseg: Maximum no. of message queue segments hold concurrently.
|
||||
# Default: 2048, Min: 256, Max: 32767
|
||||
#kern.ipc.msgseg 2048
|
||||
|
||||
# kern.ipc.msgssz: Size of segment in bytes. Must be a power of 2 value.
|
||||
# Default: 8, Min: 8, Max: 1024
|
||||
#kern.ipc.msgssz 8
|
||||
|
||||
# kern.ipc.msgmni: Maximum no. of message queue identifiers hold concurrently.
|
||||
# Default: 40, Min: 1, Max: 1024
|
||||
#kern.ipc.msgmni 40
|
||||
|
||||
# XSI semaphore parameters
|
||||
|
||||
# kern.ipc.semmni: Maximum no. of semaphore identifiers hold concurrently.
|
||||
# Default: 10, Min: 1, Max: 1024
|
||||
#kern.ipc.semmni 10
|
||||
|
||||
# kern.ipc.semmns: Maximum no. of semaphores hold concurrently.
|
||||
# Default: 60, Min: 1, Max: 1024
|
||||
#kern.ipc.semmns 60
|
||||
|
||||
# kern.ipc.semmnu: Total no. of undo structures hold by server.
|
||||
# Default: 30, Min: 1, Max: 1024
|
||||
#kern.ipc.semmnu 30
|
||||
|
||||
# kern.ipc.semmsl: Maximum no. of semaphores per semaphore id.
|
||||
# Default: 60, Min: 1, Max: 1024
|
||||
#kern.ipc.semmsl 60
|
||||
|
||||
# kern.ipc.semopm: Maximum no. of operations per semop call.
|
||||
# Default: 100, Min: 1, Max: 1024
|
||||
#kern.ipc.semopm 100
|
||||
|
||||
# kern.ipc.semume: Maximum no. of undo entries per process.
|
||||
# Default: 10, Min: 1, Max: 1024
|
||||
#kern.ipc.semume 10
|
||||
|
||||
# kern.ipc.semvmx: Maximum value of a semaphore.
|
||||
# Default: 32767, Min: 1, Max: 32767
|
||||
#kern.ipc.semvmx 32767
|
||||
|
||||
# kern.ipc.semaem: Maximum value to adjust on process exit.
|
||||
# Default: 16384, Min: 1, Max: 32767
|
||||
#kern.ipc.semaem 16384
|
||||
|
||||
# XSI shared memory parameters
|
||||
|
||||
# kern.ipc.shmmaxpgs: Maximum pages available for XSI shared memory.
|
||||
# Default: 8192, Min: 1, Max: 32767
|
||||
#kern.ipc.shmmaxpgs 8192
|
||||
|
||||
# kern.ipc.shmmni: Maximum number of shared memory segments, system wide.
|
||||
# Default: 192, Min: 1, Max: 32767
|
||||
#kern.ipc.shmmni 192
|
||||
|
||||
# kern.ipc.shmseg: Maximum number of shared memory segments per process.
|
||||
# Default: 128, Min: 1, Max: 32767
|
||||
#kern.ipc.shmseg 128
|
|
@ -1,8 +1,6 @@
|
|||
/* msg.cc: Single unix specification IPC interface for Cygwin.
|
||||
|
||||
Copyright 2002 Red Hat, Inc.
|
||||
|
||||
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -10,38 +8,103 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#include "winsup.h"
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cygwin/msg.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "process.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "cygerrno.h"
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_msg.h"
|
||||
|
||||
extern "C" int
|
||||
msgctl (int msqid, int cmd, struct msqid_ds *buf)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
client_request_msg::client_request_msg ()
|
||||
: client_request (CYGSERVER_REQUEST_MSG,
|
||||
&_parameters, sizeof (_parameters))
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
msgget (key_t key, int msgflg)
|
||||
void
|
||||
client_request_msg::serve (transport_layer_base *const conn,
|
||||
process_cache *const cache)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" ssize_t
|
||||
msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
if (msglen () != sizeof (_parameters.in))
|
||||
{
|
||||
syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
|
||||
sizeof (_parameters), msglen ());
|
||||
error_code (EINVAL);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (support_msgqueues == TUN_FALSE)
|
||||
{
|
||||
syscall_printf ("Message queue support not started");
|
||||
error_code (ENOSYS);
|
||||
if (_parameters.in.msgop == MSGOP_msgrcv)
|
||||
_parameters.out.rcv = -1;
|
||||
else
|
||||
_parameters.out.ret = -1;
|
||||
msglen (sizeof (_parameters.out));
|
||||
return;
|
||||
}
|
||||
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
|
||||
_parameters.in.ipcblk.winpid);
|
||||
if (!client)
|
||||
{
|
||||
error_code (EAGAIN);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!conn->impersonate_client ())
|
||||
{
|
||||
client->release ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!adjust_identity_info (&_parameters.in.ipcblk))
|
||||
{
|
||||
conn->revert_to_self ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
/* Early revert_to_self since IPC code runs in kernel mode. */
|
||||
conn->revert_to_self ();
|
||||
thread td = { client, &_parameters.in.ipcblk, {-1, -1} };
|
||||
int res;
|
||||
msgop_t msgop = _parameters.in.msgop; /* Get's overwritten otherwise. */
|
||||
switch (msgop)
|
||||
{
|
||||
case MSGOP_msgctl:
|
||||
res = msgctl (&td, &_parameters.in.ctlargs);
|
||||
break;
|
||||
case MSGOP_msgget:
|
||||
res = msgget (&td, &_parameters.in.getargs);
|
||||
break;
|
||||
case MSGOP_msgrcv:
|
||||
res = msgrcv (&td, &_parameters.in.rcvargs);
|
||||
break;
|
||||
case MSGOP_msgsnd:
|
||||
res = msgsnd (&td, &_parameters.in.sndargs);
|
||||
break;
|
||||
}
|
||||
/* Allocated by the call to adjust_identity_info(). */
|
||||
if (_parameters.in.ipcblk.gidlist)
|
||||
free (_parameters.in.ipcblk.gidlist);
|
||||
client->release ();
|
||||
error_code (res);
|
||||
if (msgop == MSGOP_msgrcv)
|
||||
_parameters.out.rcv = td.td_retval[0];
|
||||
else
|
||||
_parameters.out.ret = td.td_retval[0];
|
||||
msglen (sizeof (_parameters.out));
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* cygserver_process.cc
|
||||
/* process.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
|
||||
|
@ -19,7 +19,7 @@ details. */
|
|||
|
||||
#include "cygerrno.h"
|
||||
|
||||
#include "cygserver_process.h"
|
||||
#include "process.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -29,7 +29,7 @@ details. */
|
|||
|
||||
process_cleanup::~process_cleanup ()
|
||||
{
|
||||
safe_delete (_process);
|
||||
delete _process;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -139,7 +139,7 @@ process::remove (const cleanup_routine *const entry)
|
|||
else
|
||||
_routines_head = ptr->_next;
|
||||
|
||||
safe_delete (ptr);
|
||||
delete ptr;
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ process::cleanup ()
|
|||
cleanup_routine *const ptr = entry;
|
||||
entry = entry->_next;
|
||||
ptr->cleanup (this);
|
||||
safe_delete (ptr);
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,11 +250,11 @@ process_cache::process (const pid_t cygpid, const DWORD winpid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
entry = safe_new (class process, cygpid, winpid);
|
||||
entry = new class process (cygpid, winpid);
|
||||
if (!entry->is_active ())
|
||||
{
|
||||
LeaveCriticalSection (&_cache_write_access);
|
||||
safe_delete (entry);
|
||||
delete entry;
|
||||
set_errno (ESRCH);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ process_cache::check_and_remove_process (const size_t index)
|
|||
LeaveCriticalSection (&_cache_write_access);
|
||||
|
||||
/* Schedule any cleanup tasks for this process. */
|
||||
_queue.add (safe_new (process_cleanup, process));
|
||||
_queue.add (new process_cleanup (process));
|
||||
}
|
||||
|
||||
class process *
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* cygserver_process.h
|
||||
/* process.h
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
|
||||
|
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifndef _CYGSERVER_PROCESS_
|
||||
#define _CYGSERVER_PROCESS_
|
||||
#ifndef _PROCESS_H
|
||||
#define _PROCESS_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -161,4 +161,4 @@ private:
|
|||
class process *find (DWORD winpid, class process **previous = NULL);
|
||||
};
|
||||
|
||||
#endif /* _CYGSERVER_PROCESS_ */
|
||||
#endif /* _PROCESS_H */
|
|
@ -1,8 +1,6 @@
|
|||
/* sem.cc: Single unix specification IPC interface for Cygwin.
|
||||
|
||||
Copyright 2002 Red Hat, Inc.
|
||||
|
||||
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -10,31 +8,94 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#include "winsup.h"
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cygwin/sem.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "process.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "cygerrno.h"
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_sem.h"
|
||||
|
||||
extern "C" int
|
||||
semctl (int semid, int semnum, int cmd, ...)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
client_request_sem::client_request_sem ()
|
||||
: client_request (CYGSERVER_REQUEST_SEM,
|
||||
&_parameters, sizeof (_parameters))
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
semget (key_t key, int nsems, int semflg)
|
||||
void
|
||||
client_request_sem::serve (transport_layer_base *const conn,
|
||||
process_cache *const cache)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
semop (int semid, struct sembuf *sops, size_t nsops)
|
||||
{
|
||||
set_errno (ENOSYS);
|
||||
return -1;
|
||||
if (msglen () != sizeof (_parameters.in))
|
||||
{
|
||||
syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
|
||||
sizeof (_parameters), msglen ());
|
||||
error_code (EINVAL);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (support_semaphores == TUN_FALSE)
|
||||
{
|
||||
syscall_printf ("Semaphore support not started");
|
||||
error_code (ENOSYS);
|
||||
_parameters.out.ret = -1;
|
||||
msglen (sizeof (_parameters.out));
|
||||
return;
|
||||
}
|
||||
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
|
||||
_parameters.in.ipcblk.winpid);
|
||||
if (!client)
|
||||
{
|
||||
error_code (EAGAIN);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!conn->impersonate_client ())
|
||||
{
|
||||
client->release ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!adjust_identity_info (&_parameters.in.ipcblk))
|
||||
{
|
||||
client->release ();
|
||||
conn->revert_to_self ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
/* Early revert_to_self since IPC code runs in kernel mode. */
|
||||
conn->revert_to_self ();
|
||||
thread td = { client, &_parameters.in.ipcblk, {-1, -1} };
|
||||
int res;
|
||||
switch (_parameters.in.semop)
|
||||
{
|
||||
case SEMOP_semctl:
|
||||
res = semctl (&td, &_parameters.in.ctlargs);
|
||||
break;
|
||||
case SEMOP_semget:
|
||||
res = semget (&td, &_parameters.in.getargs);
|
||||
break;
|
||||
case SEMOP_semop:
|
||||
res = semop (&td, &_parameters.in.opargs);
|
||||
break;
|
||||
}
|
||||
/* Allocated by the call to adjust_identity_info(). */
|
||||
if (_parameters.in.ipcblk.gidlist)
|
||||
free (_parameters.in.ipcblk.gidlist);
|
||||
client->release ();
|
||||
error_code (res);
|
||||
_parameters.out.ret = td.td_retval[0];
|
||||
msglen (sizeof (_parameters.out));
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin.
|
||||
/* shm.cc: Single unix specification IPC interface for Cygwin.
|
||||
|
||||
Copyright 2002 Red Hat, Inc.
|
||||
|
||||
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
|
||||
Based on code by Robert Collins <robert.collins@hotmail.com>.
|
||||
Copyright 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -11,824 +8,33 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "process.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "cygserver_ipc.h"
|
||||
#include "cygserver_shm.h"
|
||||
#include "security.h"
|
||||
|
||||
#include "cygserver.h"
|
||||
#include "cygserver_process.h"
|
||||
#include "cygserver_transport.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* class server_shmmgr
|
||||
*
|
||||
* A singleton class.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#define shmmgr (server_shmmgr::instance ())
|
||||
|
||||
class server_shmmgr
|
||||
{
|
||||
private:
|
||||
class attach_t
|
||||
{
|
||||
public:
|
||||
class process *const _client;
|
||||
unsigned int _refcnt;
|
||||
|
||||
attach_t *_next;
|
||||
|
||||
attach_t (class process *const client)
|
||||
: _client (client),
|
||||
_refcnt (0),
|
||||
_next (NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
class segment_t
|
||||
{
|
||||
private:
|
||||
// Bits for the _flg field.
|
||||
enum { IS_DELETED = 0x01 };
|
||||
|
||||
public:
|
||||
const int _intid;
|
||||
const int _shmid;
|
||||
struct shmid_ds _ds;
|
||||
|
||||
segment_t *_next;
|
||||
|
||||
segment_t (const key_t key, const int intid, const HANDLE hFileMap);
|
||||
~segment_t ();
|
||||
|
||||
bool is_deleted () const
|
||||
{
|
||||
return _flg & IS_DELETED;
|
||||
}
|
||||
|
||||
bool is_pending_delete () const
|
||||
{
|
||||
return !_ds.shm_nattch && is_deleted ();
|
||||
}
|
||||
|
||||
void mark_deleted ()
|
||||
{
|
||||
assert (!is_deleted ());
|
||||
|
||||
_flg |= IS_DELETED;
|
||||
}
|
||||
|
||||
int attach (class process *, HANDLE & hFileMap);
|
||||
int detach (class process *);
|
||||
|
||||
private:
|
||||
static long _sequence;
|
||||
|
||||
int _flg;
|
||||
const HANDLE _hFileMap;
|
||||
attach_t *_attach_head; // A list sorted by winpid;
|
||||
|
||||
attach_t *find (const class process *, attach_t **previous = NULL);
|
||||
};
|
||||
|
||||
class cleanup_t : public cleanup_routine
|
||||
{
|
||||
public:
|
||||
cleanup_t (const segment_t *const segptr)
|
||||
: cleanup_routine (reinterpret_cast<void *> (segptr->_shmid))
|
||||
{
|
||||
assert (key ());
|
||||
}
|
||||
|
||||
int shmid () const { return reinterpret_cast<int> (key ()); }
|
||||
|
||||
virtual void cleanup (class process *const client)
|
||||
{
|
||||
const int res = shmmgr.shmdt (shmid (), client);
|
||||
|
||||
if (res != 0)
|
||||
debug_printf ("process cleanup failed [shmid = %d]: %s",
|
||||
shmid (), strerror (-res));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static server_shmmgr & instance ();
|
||||
|
||||
int shmat (HANDLE & hFileMap,
|
||||
int shmid, int shmflg, class process *);
|
||||
int shmctl (int & out_shmid, struct shmid_ds & out_ds,
|
||||
struct shminfo & out_shminfo, struct shm_info & out_shm_info,
|
||||
const int shmid, int cmd, const struct shmid_ds &,
|
||||
class process *);
|
||||
int shmdt (int shmid, class process *);
|
||||
int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t,
|
||||
class process *);
|
||||
|
||||
private:
|
||||
static server_shmmgr *_instance;
|
||||
static pthread_once_t _instance_once;
|
||||
|
||||
static void initialise_instance ();
|
||||
|
||||
CRITICAL_SECTION _segments_lock;
|
||||
segment_t *_segments_head; // A list sorted by int_id.
|
||||
|
||||
int _shm_ids; // Number of shm segments (for ipcs(8)).
|
||||
int _shm_tot; // Total bytes of shm segments (for ipcs(8)).
|
||||
int _shm_atts; // Number of attached segments (for ipcs(8)).
|
||||
int _intid_max; // Highest intid yet allocated (for ipcs(8)).
|
||||
|
||||
server_shmmgr ();
|
||||
~server_shmmgr ();
|
||||
|
||||
// Undefined (as this class is a singleton):
|
||||
server_shmmgr (const server_shmmgr &);
|
||||
server_shmmgr & operator= (const server_shmmgr &);
|
||||
|
||||
segment_t *find_by_key (key_t);
|
||||
segment_t *find (int intid, segment_t **previous = NULL);
|
||||
|
||||
int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
|
||||
|
||||
segment_t *new_segment (key_t, size_t, HANDLE);
|
||||
void delete_segment (segment_t *);
|
||||
};
|
||||
|
||||
/* static */ long server_shmmgr::segment_t::_sequence = 0;
|
||||
|
||||
/* static */ server_shmmgr *server_shmmgr::_instance = NULL;
|
||||
/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::segment_t ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t::segment_t (const key_t key,
|
||||
const int intid,
|
||||
const HANDLE hFileMap)
|
||||
: _intid (intid),
|
||||
_shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)),
|
||||
_next (NULL),
|
||||
_flg (0),
|
||||
_hFileMap (hFileMap),
|
||||
_attach_head (NULL)
|
||||
{
|
||||
assert (0 <= _intid && _intid < SHMMNI);
|
||||
|
||||
memset (&_ds, '\0', sizeof (_ds));
|
||||
_ds.shm_perm.key = key;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::~segment_t ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t::~segment_t ()
|
||||
{
|
||||
assert (!_attach_head);
|
||||
|
||||
if (!CloseHandle (_hFileMap))
|
||||
syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::attach ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::segment_t::attach (class process *const client,
|
||||
HANDLE & hFileMap)
|
||||
{
|
||||
assert (client);
|
||||
|
||||
if (!DuplicateHandle (GetCurrentProcess (),
|
||||
_hFileMap,
|
||||
client->handle (),
|
||||
&hFileMap,
|
||||
0,
|
||||
FALSE, // bInheritHandle
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
syscall_printf (("failed to duplicate handle for client "
|
||||
"[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"),
|
||||
_ds.shm_perm.key, _shmid, _hFileMap);
|
||||
|
||||
return -EACCES; // FIXME: Case analysis?
|
||||
}
|
||||
|
||||
_ds.shm_lpid = client->cygpid ();
|
||||
_ds.shm_nattch += 1;
|
||||
_ds.shm_atime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
attach_t *previous = NULL;
|
||||
attach_t *attptr = find (client, &previous);
|
||||
|
||||
if (!attptr)
|
||||
{
|
||||
attptr = safe_new (attach_t, client);
|
||||
|
||||
if (previous)
|
||||
{
|
||||
attptr->_next = previous->_next;
|
||||
previous->_next = attptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
attptr->_next = _attach_head;
|
||||
_attach_head = attptr;
|
||||
}
|
||||
}
|
||||
|
||||
attptr->_refcnt += 1;
|
||||
|
||||
cleanup_t *const cleanup = safe_new (cleanup_t, this);
|
||||
|
||||
// FIXME: ::add should only fail if the process object is already
|
||||
// cleaning up; but it can't be doing that since this thread has it
|
||||
// locked.
|
||||
|
||||
const bool result = client->add (cleanup);
|
||||
|
||||
assert (result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::detach ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::segment_t::detach (class process *const client)
|
||||
{
|
||||
attach_t *previous = NULL;
|
||||
attach_t *const attptr = find (client, &previous);
|
||||
|
||||
if (!attptr)
|
||||
return -EINVAL;
|
||||
|
||||
if (client->is_active ())
|
||||
{
|
||||
const cleanup_t key (this);
|
||||
|
||||
if (!client->remove (&key))
|
||||
syscall_printf (("failed to remove cleanup routine for %d(%lu) "
|
||||
"[shmid = %d]"),
|
||||
client->cygpid (), client->winpid (),
|
||||
_shmid);
|
||||
}
|
||||
|
||||
attptr->_refcnt -= 1;
|
||||
|
||||
if (!attptr->_refcnt)
|
||||
{
|
||||
assert (previous ? previous->_next == attptr : _attach_head == attptr);
|
||||
|
||||
if (previous)
|
||||
previous->_next = attptr->_next;
|
||||
else
|
||||
_attach_head = attptr->_next;
|
||||
|
||||
safe_delete (attptr);
|
||||
}
|
||||
|
||||
assert (_ds.shm_nattch > 0);
|
||||
|
||||
_ds.shm_lpid = client->cygpid ();
|
||||
_ds.shm_nattch -= 1;
|
||||
_ds.shm_dtime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::segment_t::find ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::attach_t *
|
||||
server_shmmgr::segment_t::find (const class process *const client,
|
||||
attach_t **previous)
|
||||
{
|
||||
if (previous)
|
||||
*previous = NULL;
|
||||
|
||||
// Nb. The _attach_head list is sorted by winpid.
|
||||
|
||||
for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next)
|
||||
if (attptr->_client == client)
|
||||
return attptr;
|
||||
else if (attptr->_client->winpid () > client->winpid ())
|
||||
return NULL;
|
||||
else if (previous)
|
||||
*previous = attptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::instance ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* static */ server_shmmgr &
|
||||
server_shmmgr::instance ()
|
||||
{
|
||||
pthread_once (&_instance_once, &initialise_instance);
|
||||
|
||||
assert (_instance);
|
||||
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmat ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmat (HANDLE & hFileMap,
|
||||
const int shmid, const int shmflg,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
|
||||
shmid, shmflg, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->attach (client, hFileMap);
|
||||
|
||||
if (!result)
|
||||
_shm_atts += 1;
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
-result, shmid, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
hFileMap, shmid, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmctl ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmctl (int & out_shmid,
|
||||
struct shmid_ds & out_ds,
|
||||
struct shminfo & out_shminfo,
|
||||
struct shm_info & out_shm_info,
|
||||
const int shmid, const int cmd,
|
||||
const struct shmid_ds & ds,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)",
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case IPC_STAT:
|
||||
case SHM_STAT: // Uses intids rather than shmids.
|
||||
case IPC_SET:
|
||||
case IPC_RMID:
|
||||
{
|
||||
int intid;
|
||||
|
||||
if (cmd == SHM_STAT)
|
||||
intid = shmid;
|
||||
else
|
||||
intid = ipc_ext2int (shmid, IPC_SHMOP);
|
||||
|
||||
segment_t *const segptr = find (intid);
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
switch (cmd)
|
||||
{
|
||||
case IPC_STAT:
|
||||
out_ds = segptr->_ds;
|
||||
break;
|
||||
|
||||
case IPC_SET:
|
||||
segptr->_ds.shm_perm.uid = ds.shm_perm.uid;
|
||||
segptr->_ds.shm_perm.gid = ds.shm_perm.gid;
|
||||
segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777;
|
||||
segptr->_ds.shm_lpid = client->cygpid ();
|
||||
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
|
||||
break;
|
||||
|
||||
case IPC_RMID:
|
||||
if (segptr->is_deleted ())
|
||||
result = -EIDRM;
|
||||
else
|
||||
{
|
||||
segptr->mark_deleted ();
|
||||
if (segptr->is_pending_delete ())
|
||||
delete_segment (segptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SHM_STAT: // ipcs(8) i'face.
|
||||
out_ds = segptr->_ds;
|
||||
out_shmid = segptr->_shmid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_INFO:
|
||||
out_shminfo.shmmax = SHMMAX;
|
||||
out_shminfo.shmmin = SHMMIN;
|
||||
out_shminfo.shmmni = SHMMNI;
|
||||
out_shminfo.shmseg = SHMSEG;
|
||||
out_shminfo.shmall = SHMALL;
|
||||
break;
|
||||
|
||||
case SHM_INFO: // ipcs(8) i'face.
|
||||
out_shmid = _intid_max;
|
||||
out_shm_info.shm_ids = _shm_ids;
|
||||
out_shm_info.shm_tot = _shm_tot;
|
||||
out_shm_info.shm_atts = _shm_atts;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = "
|
||||
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
|
||||
-result,
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("%d = "
|
||||
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
|
||||
((cmd == SHM_STAT || cmd == SHM_INFO)
|
||||
? out_shmid
|
||||
: result),
|
||||
shmid, cmd, client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmdt ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmdt (const int shmid, class process *const client)
|
||||
{
|
||||
syscall_printf ("shmdt (shmid = %d) for %d(%lu)",
|
||||
shmid, client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
|
||||
|
||||
if (!segptr)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->detach (client);
|
||||
|
||||
if (!result)
|
||||
_shm_atts -= 1;
|
||||
|
||||
if (!result && segptr->is_pending_delete ())
|
||||
delete_segment (segptr);
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)",
|
||||
-result, shmid, client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)",
|
||||
result, shmid, client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::shmget ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::shmget (int & out_shmid,
|
||||
const key_t key, const size_t size, const int shmflg,
|
||||
const uid_t uid, const gid_t gid,
|
||||
class process *const client)
|
||||
{
|
||||
syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
int result = 0;
|
||||
EnterCriticalSection (&_segments_lock);
|
||||
|
||||
if (key == IPC_PRIVATE)
|
||||
result = new_segment (key, size, shmflg,
|
||||
client->cygpid (), uid, gid);
|
||||
else
|
||||
{
|
||||
segment_t *const segptr = find_by_key (key);
|
||||
|
||||
if (!segptr)
|
||||
if (shmflg & IPC_CREAT)
|
||||
result = new_segment (key, size, shmflg,
|
||||
client->cygpid (), uid, gid);
|
||||
else
|
||||
result = -ENOENT;
|
||||
else if (segptr->is_deleted ())
|
||||
result = -EIDRM;
|
||||
else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
|
||||
result = -EEXIST;
|
||||
else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777)
|
||||
result = -EACCES;
|
||||
else if (size && segptr->_ds.shm_segsz < size)
|
||||
result = -EINVAL;
|
||||
else
|
||||
result = segptr->_shmid;
|
||||
}
|
||||
|
||||
LeaveCriticalSection (&_segments_lock);
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
out_shmid = result;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
syscall_printf (("-1 [%d] = "
|
||||
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
-result,
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
else
|
||||
syscall_printf (("%d = "
|
||||
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
|
||||
"for %d(%lu)"),
|
||||
out_shmid,
|
||||
key, size, shmflg,
|
||||
client->cygpid (), client->winpid ());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::initialise_instance ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* static */ void
|
||||
server_shmmgr::initialise_instance ()
|
||||
{
|
||||
assert (!_instance);
|
||||
|
||||
_instance = safe_new0 (server_shmmgr);
|
||||
|
||||
assert (_instance);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::server_shmmgr ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::server_shmmgr ()
|
||||
: _segments_head (NULL),
|
||||
_shm_ids (0),
|
||||
_shm_tot (0),
|
||||
_shm_atts (0),
|
||||
_intid_max (0)
|
||||
{
|
||||
InitializeCriticalSection (&_segments_lock);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::~server_shmmgr ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::~server_shmmgr ()
|
||||
{
|
||||
DeleteCriticalSection (&_segments_lock);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::find_by_key ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::find_by_key (const key_t key)
|
||||
{
|
||||
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
|
||||
if (segptr->_ds.shm_perm.key == key)
|
||||
return segptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::find ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::find (const int intid, segment_t **previous)
|
||||
{
|
||||
if (previous)
|
||||
*previous = NULL;
|
||||
|
||||
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
|
||||
if (segptr->_intid == intid)
|
||||
return segptr;
|
||||
else if (segptr->_intid > intid) // The list is sorted by intid.
|
||||
return NULL;
|
||||
else if (previous)
|
||||
*previous = segptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::new_segment ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
int
|
||||
server_shmmgr::new_segment (const key_t key,
|
||||
const size_t size,
|
||||
const int shmflg,
|
||||
const pid_t cygpid,
|
||||
const uid_t uid,
|
||||
const gid_t gid)
|
||||
{
|
||||
if (size < SHMMIN || size > SHMMAX)
|
||||
return -EINVAL;
|
||||
|
||||
const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE,
|
||||
NULL, PAGE_READWRITE,
|
||||
0, size,
|
||||
NULL);
|
||||
|
||||
if (!hFileMap)
|
||||
{
|
||||
syscall_printf ("failed to create file mapping [size = %lu]: %E", size);
|
||||
return -ENOMEM; // FIXME
|
||||
}
|
||||
|
||||
segment_t *const segptr = new_segment (key, size, hFileMap);
|
||||
|
||||
if (!segptr)
|
||||
{
|
||||
(void) CloseHandle (hFileMap);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid;
|
||||
segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid;
|
||||
segptr->_ds.shm_perm.mode = shmflg & 0777;
|
||||
segptr->_ds.shm_segsz = size;
|
||||
segptr->_ds.shm_cpid = cygpid;
|
||||
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
|
||||
|
||||
return segptr->_shmid;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::new_segment ()
|
||||
*
|
||||
* Allocate a new segment for the given key and file map with the
|
||||
* lowest available intid and insert into the segment map.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
server_shmmgr::segment_t *
|
||||
server_shmmgr::new_segment (const key_t key, const size_t size,
|
||||
const HANDLE hFileMap)
|
||||
{
|
||||
// FIXME: Overflow risk.
|
||||
if (_shm_tot + size > SHMALL)
|
||||
return NULL;
|
||||
|
||||
int intid = 0; // Next expected intid value.
|
||||
segment_t *previous = NULL; // Insert pointer.
|
||||
|
||||
// Find first unallocated intid.
|
||||
for (segment_t *segptr = _segments_head;
|
||||
segptr && segptr->_intid == intid;
|
||||
segptr = segptr->_next, intid++)
|
||||
{
|
||||
previous = segptr;
|
||||
}
|
||||
|
||||
/* By the time this condition is reached (given the default value of
|
||||
* SHMMNI), the linear searches should all replaced by something
|
||||
* just a *little* cleverer . . .
|
||||
*/
|
||||
if (intid >= SHMMNI)
|
||||
return NULL;
|
||||
|
||||
segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap);
|
||||
|
||||
assert (segptr);
|
||||
|
||||
if (previous)
|
||||
{
|
||||
segptr->_next = previous->_next;
|
||||
previous->_next = segptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
segptr->_next = _segments_head;
|
||||
_segments_head = segptr;
|
||||
}
|
||||
|
||||
_shm_ids += 1;
|
||||
_shm_tot += size;
|
||||
if (intid > _intid_max)
|
||||
_intid_max = intid;
|
||||
|
||||
return segptr;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* server_shmmgr::delete_segment ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
server_shmmgr::delete_segment (segment_t *const segptr)
|
||||
{
|
||||
assert (segptr);
|
||||
assert (segptr->is_pending_delete ());
|
||||
|
||||
segment_t *previous = NULL;
|
||||
|
||||
const segment_t *const tmp = find (segptr->_intid, &previous);
|
||||
|
||||
assert (tmp == segptr);
|
||||
assert (previous ? previous->_next == segptr : _segments_head == segptr);
|
||||
|
||||
if (previous)
|
||||
previous->_next = segptr->_next;
|
||||
else
|
||||
_segments_head = segptr->_next;
|
||||
|
||||
assert (_shm_ids > 0);
|
||||
_shm_ids -= 1;
|
||||
_shm_tot -= segptr->_ds.shm_segsz;
|
||||
|
||||
safe_delete (segptr);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* client_request_shm::client_request_shm ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
client_request_shm::client_request_shm ()
|
||||
: client_request (CYGSERVER_REQUEST_SHM,
|
||||
&_parameters, sizeof (_parameters))
|
||||
{
|
||||
// verbose: syscall_printf ("created");
|
||||
{
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*
|
||||
* client_request_shm::serve ()
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
client_request_shm::serve (transport_layer_base *const conn,
|
||||
process_cache *const cache)
|
||||
process_cache *const cache)
|
||||
{
|
||||
assert (conn);
|
||||
|
||||
assert (!error_code ());
|
||||
|
||||
if (msglen () != sizeof (_parameters.in))
|
||||
{
|
||||
syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
|
||||
|
@ -837,60 +43,76 @@ client_request_shm::serve (transport_layer_base *const conn,
|
|||
msglen (0);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Get a return code out of this and don't continue on error.
|
||||
conn->impersonate_client ();
|
||||
|
||||
class process *const client = cache->process (_parameters.in.cygpid,
|
||||
_parameters.in.winpid);
|
||||
|
||||
if (support_sharedmem == TUN_FALSE)
|
||||
{
|
||||
syscall_printf ("Shared memory support not started");
|
||||
error_code (ENOSYS);
|
||||
if (_parameters.in.shmop == SHMOP_shmat)
|
||||
_parameters.out.ptr = (vm_offset_t)0;
|
||||
else
|
||||
_parameters.out.ret = -1;
|
||||
msglen (sizeof (_parameters.out));
|
||||
return;
|
||||
}
|
||||
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
|
||||
_parameters.in.ipcblk.winpid);
|
||||
if (!client)
|
||||
{
|
||||
error_code (EAGAIN);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
|
||||
int result = -EINVAL;
|
||||
|
||||
switch (_parameters.in.shmop)
|
||||
if (!conn->impersonate_client ())
|
||||
{
|
||||
case SHMOP_shmget:
|
||||
result = shmmgr.shmget (_parameters.out.shmid,
|
||||
_parameters.in.key, _parameters.in.size,
|
||||
_parameters.in.shmflg,
|
||||
_parameters.in.uid, _parameters.in.gid,
|
||||
client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmat:
|
||||
result = shmmgr.shmat (_parameters.out.hFileMap,
|
||||
_parameters.in.shmid, _parameters.in.shmflg,
|
||||
client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmdt:
|
||||
result = shmmgr.shmdt (_parameters.in.shmid, client);
|
||||
break;
|
||||
|
||||
case SHMOP_shmctl:
|
||||
result = shmmgr.shmctl (_parameters.out.shmid,
|
||||
_parameters.out.ds, _parameters.out.shminfo,
|
||||
_parameters.out.shm_info,
|
||||
_parameters.in.shmid, _parameters.in.cmd,
|
||||
_parameters.in.ds,
|
||||
client);
|
||||
break;
|
||||
}
|
||||
|
||||
client->release ();
|
||||
conn->revert_to_self ();
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
error_code (-result);
|
||||
client->release ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
if (!adjust_identity_info (&_parameters.in.ipcblk))
|
||||
{
|
||||
client->release ();
|
||||
conn->revert_to_self ();
|
||||
error_code (EACCES);
|
||||
msglen (0);
|
||||
return;
|
||||
}
|
||||
/* Early revert_to_self since IPC code runs in kernel mode. */
|
||||
conn->revert_to_self ();
|
||||
thread td = { client, &_parameters.in.ipcblk, {0, 0} };
|
||||
int res;
|
||||
shmop_t shmop = _parameters.in.shmop; /* Get's overwritten otherwise. */
|
||||
switch (shmop)
|
||||
{
|
||||
case SHMOP_shmat:
|
||||
ipc_p_vmspace (td.ipcblk);
|
||||
res = shmat (&td, &_parameters.in.atargs);
|
||||
break;
|
||||
case SHMOP_shmctl:
|
||||
res = shmctl (&td, &_parameters.in.ctlargs);
|
||||
break;
|
||||
case SHMOP_shmdt:
|
||||
ipc_p_vmspace (td.ipcblk);
|
||||
res = shmdt (&td, &_parameters.in.dtargs);
|
||||
break;
|
||||
case SHMOP_shmget:
|
||||
res = shmget (&td, &_parameters.in.getargs);
|
||||
break;
|
||||
case SHMOP_shmfork:
|
||||
res = cygwin_shmfork_myhook (&td, &_parameters.in.forkargs);
|
||||
break;
|
||||
}
|
||||
/* Allocated by the call to adjust_identity_info(). */
|
||||
if (_parameters.in.ipcblk.gidlist)
|
||||
free (_parameters.in.ipcblk.gidlist);
|
||||
client->release ();
|
||||
error_code (res);
|
||||
if (shmop == SHMOP_shmat)
|
||||
_parameters.out.ptr = td.td_retval[0];
|
||||
else
|
||||
msglen (sizeof (_parameters.out));
|
||||
_parameters.out.ret = td.td_retval[0];
|
||||
if (shmop == SHMOP_shmget)
|
||||
_parameters.out.obj = td.td_retval[1];
|
||||
msglen (sizeof (_parameters.out));
|
||||
}
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
/* threaded_queue.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Robert Collins <rbtcollins@hotmail.com>
|
||||
|
||||
|
@ -10,6 +10,7 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifdef __OUTSIDE_CYGWIN__
|
||||
#include "woutsup.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -73,7 +74,7 @@ threaded_queue::~threaded_queue ()
|
|||
{
|
||||
queue_request *const ptr = reqptr;
|
||||
reqptr = reqptr->_next;
|
||||
safe_delete (ptr);
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
DeleteCriticalSection (&_queue_lock);
|
||||
|
@ -267,7 +268,7 @@ threaded_queue::worker_loop ()
|
|||
|
||||
assert (reqptr);
|
||||
reqptr->process ();
|
||||
safe_delete (reqptr);
|
||||
delete reqptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,3 +407,4 @@ queue_submission_loop::start_routine (const LPVOID lpParam)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
#endif /* __OUTSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver_transport.cc
|
||||
/* transport.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Robert Collins <rbtcollins@hotmail.com>
|
||||
|
||||
|
@ -19,31 +19,33 @@ details. */
|
|||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "safe_memory.h"
|
||||
|
||||
#include "cygserver_transport.h"
|
||||
#include "cygserver_transport_pipes.h"
|
||||
#include "cygserver_transport_sockets.h"
|
||||
#include "transport.h"
|
||||
#include "transport_pipes.h"
|
||||
#include "transport_sockets.h"
|
||||
|
||||
/* The factory */
|
||||
transport_layer_base *
|
||||
create_server_transport ()
|
||||
{
|
||||
if (wincap.is_winnt ())
|
||||
return safe_new0 (transport_layer_pipes);
|
||||
return new transport_layer_pipes;
|
||||
else
|
||||
return safe_new0 (transport_layer_sockets);
|
||||
return new transport_layer_sockets;
|
||||
}
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
|
||||
void
|
||||
bool
|
||||
transport_layer_base::impersonate_client ()
|
||||
{}
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
transport_layer_base::revert_to_self ()
|
||||
{}
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver_transport.h
|
||||
/* transport.h
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Robert Collins <rbtcollins@hotmail.com>
|
||||
|
||||
|
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifndef _CYGSERVER_TRANSPORT_
|
||||
#define _CYGSERVER_TRANSPORT_
|
||||
#ifndef _TRANSPORT_H
|
||||
#define _TRANSPORT_H
|
||||
|
||||
class transport_layer_base *create_server_transport ();
|
||||
|
||||
|
@ -29,11 +29,11 @@ public:
|
|||
virtual int connect () = 0;
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
virtual void impersonate_client ();
|
||||
virtual void revert_to_self ();
|
||||
virtual bool impersonate_client ();
|
||||
virtual bool revert_to_self ();
|
||||
#endif
|
||||
|
||||
virtual ~transport_layer_base ();
|
||||
};
|
||||
|
||||
#endif /* _CYGSERVER_TRANSPORT_ */
|
||||
#endif /* _TRANSPORT_H */
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver_transport_pipes.cc
|
||||
/* transport_pipes.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Robert Collins <rbtcollins@hotmail.com>
|
||||
|
||||
|
@ -25,11 +25,14 @@ details. */
|
|||
#include <unistd.h>
|
||||
|
||||
#include "cygerrno.h"
|
||||
#include "cygserver_transport.h"
|
||||
#include "cygserver_transport_pipes.h"
|
||||
#include "transport.h"
|
||||
#include "transport_pipes.h"
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
#include "cygserver.h"
|
||||
#include "cygserver_ipc.h"
|
||||
#else
|
||||
#include "security.h"
|
||||
#endif
|
||||
|
||||
enum
|
||||
|
@ -64,7 +67,6 @@ transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
|
|||
assert (_hPipe);
|
||||
assert (_hPipe != INVALID_HANDLE_VALUE);
|
||||
|
||||
init_security ();
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
@ -75,22 +77,6 @@ transport_layer_pipes::transport_layer_pipes ()
|
|||
_is_accepted_endpoint (false),
|
||||
_is_listening_endpoint (false)
|
||||
{
|
||||
init_security ();
|
||||
}
|
||||
|
||||
void
|
||||
transport_layer_pipes::init_security ()
|
||||
{
|
||||
assert (wincap.has_security ());
|
||||
|
||||
/* FIXME: pthread_once or equivalent needed */
|
||||
|
||||
InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE);
|
||||
|
||||
_sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
|
||||
_sec_all_nih.lpSecurityDescriptor = &_sd;
|
||||
_sec_all_nih.bInheritHandle = FALSE;
|
||||
}
|
||||
|
||||
transport_layer_pipes::~transport_layer_pipes ()
|
||||
|
@ -138,7 +124,7 @@ transport_layer_pipes::accept (bool *const recoverable)
|
|||
(PIPE_TYPE_BYTE | PIPE_WAIT),
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
0, 0, 1000,
|
||||
&_sec_all_nih);
|
||||
&sec_all_nih);
|
||||
|
||||
const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
|
||||
&& pipe_instance == 0
|
||||
|
@ -175,7 +161,7 @@ transport_layer_pipes::accept (bool *const recoverable)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return safe_new (transport_layer_pipes, accept_pipe);
|
||||
return new transport_layer_pipes (accept_pipe);
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
@ -281,7 +267,7 @@ transport_layer_pipes::connect ()
|
|||
_hPipe = CreateFile (_pipe_name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&_sec_all_nih,
|
||||
&sec_all_nih,
|
||||
OPEN_EXISTING,
|
||||
SECURITY_IMPERSONATION,
|
||||
NULL);
|
||||
|
@ -331,32 +317,33 @@ transport_layer_pipes::connect ()
|
|||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
|
||||
void
|
||||
bool
|
||||
transport_layer_pipes::impersonate_client ()
|
||||
{
|
||||
assert (_hPipe);
|
||||
assert (_hPipe != INVALID_HANDLE_VALUE);
|
||||
assert (_is_accepted_endpoint);
|
||||
|
||||
// verbose: debug_printf ("impersonating pipe %p", _hPipe);
|
||||
if (_hPipe)
|
||||
if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
|
||||
{
|
||||
assert (_hPipe != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (!ImpersonateNamedPipeClient (_hPipe))
|
||||
debug_printf ("Failed to Impersonate the client, (%lu)",
|
||||
GetLastError ());
|
||||
debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
|
||||
return false;
|
||||
}
|
||||
// verbose: debug_printf ("I am who you are");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
transport_layer_pipes::revert_to_self ()
|
||||
{
|
||||
assert (_is_accepted_endpoint);
|
||||
|
||||
RevertToSelf ();
|
||||
// verbose: debug_printf ("I am who I yam");
|
||||
if (!RevertToSelf ())
|
||||
{
|
||||
debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* cygserver_transport_pipes.h
|
||||
/* transport_pipes.h
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
Copyright 2001, 2002, 2003 Red Hat Inc.
|
||||
|
||||
Written by Robert Collins <rbtcollins@hotmail.com>
|
||||
|
||||
|
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifndef _CYGSERVER_TRANSPORT_PIPES_
|
||||
#define _CYGSERVER_TRANSPORT_PIPES_
|
||||
#ifndef _TRANSPORT_PIPES_H
|
||||
#define _TRANSPORT_PIPES_H
|
||||
|
||||
/* Named pipes based transport, for security on NT */
|
||||
class transport_layer_pipes : public transport_layer_base
|
||||
|
@ -28,20 +28,14 @@ public:
|
|||
virtual int connect ();
|
||||
|
||||
#ifndef __INSIDE_CYGWIN__
|
||||
virtual void impersonate_client ();
|
||||
virtual void revert_to_self ();
|
||||
virtual bool impersonate_client ();
|
||||
virtual bool revert_to_self ();
|
||||
#endif
|
||||
|
||||
transport_layer_pipes ();
|
||||
virtual ~transport_layer_pipes ();
|
||||
|
||||
private:
|
||||
/* for pipe based communications */
|
||||
void init_security ();
|
||||
|
||||
//FIXME: allow inited, sd, all_nih_.. to be static members
|
||||
SECURITY_DESCRIPTOR _sd;
|
||||
SECURITY_ATTRIBUTES _sec_all_nih;
|
||||
const char *const _pipe_name;
|
||||
HANDLE _hPipe;
|
||||
const bool _is_accepted_endpoint;
|
||||
|
@ -50,4 +44,4 @@ private:
|
|||
transport_layer_pipes (HANDLE hPipe);
|
||||
};
|
||||
|
||||
#endif /* _CYGSERVER_TRANSPORT_PIPES_ */
|
||||
#endif /* _TRANSPORT_PIPES_H */
|
|
@ -1,4 +1,4 @@
|
|||
/* cygserver_transport_sockets.cc
|
||||
/* transport_sockets.cc
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
|
||||
|
@ -26,8 +26,8 @@ details. */
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cygserver_transport.h"
|
||||
#include "cygserver_transport_sockets.h"
|
||||
#include "transport.h"
|
||||
#include "transport_sockets.h"
|
||||
|
||||
/* to allow this to link into cygwin and the .dll, a little magic is needed. */
|
||||
#ifndef __OUTSIDE_CYGWIN__
|
||||
|
@ -219,7 +219,7 @@ transport_layer_sockets::accept (bool *const recoverable)
|
|||
|
||||
debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd);
|
||||
|
||||
return safe_new (transport_layer_sockets, accept_fd);
|
||||
return new transport_layer_sockets (accept_fd);
|
||||
}
|
||||
|
||||
#endif /* !__INSIDE_CYGWIN__ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* cygserver_transport_sockets.h
|
||||
/* transport_sockets.h
|
||||
|
||||
Copyright 2001, 2002 Red Hat Inc.
|
||||
|
||||
|
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
|
|||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#ifndef _CYGSERVER_TRANSPORT_SOCKETS_
|
||||
#define _CYGSERVER_TRANSPORT_SOCKETS_
|
||||
#ifndef _TRANSPORT_SOCKETS_H
|
||||
#define _TRANSPORT_SOCKETS_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
@ -43,4 +43,4 @@ private:
|
|||
transport_layer_sockets (int fd);
|
||||
};
|
||||
|
||||
#endif /* _CYGSERVER_TRANSPORT_SOCKETS_ */
|
||||
#endif /* _TRANSPORT_SOCKETS_H */
|
|
@ -1,6 +1,6 @@
|
|||
/* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver).
|
||||
|
||||
Copyright 2002 Red Hat, Inc.
|
||||
Copyright 2002, 2003 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -42,67 +42,32 @@ details. */
|
|||
|
||||
#include "wincap.h"
|
||||
|
||||
#include "bsd_helper.h"
|
||||
#include "bsd_log.h"
|
||||
#include "bsd_mutex.h"
|
||||
|
||||
/* The one function we use from winuser.h most of the time */
|
||||
extern "C" DWORD WINAPI GetLastError (void);
|
||||
|
||||
extern int cygserver_running;
|
||||
|
||||
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
|
||||
#define NEW_MACRO_VARARGS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A reproduction of the <sys/strace.h> macros. This allows code that
|
||||
* runs both inside and outside the Cygwin DLL to use the same macros
|
||||
* for logging messages.
|
||||
*/
|
||||
|
||||
extern "C" void __cygserver__printf (const char *, const char *, ...);
|
||||
|
||||
#ifdef NEW_MACRO_VARARGS
|
||||
|
||||
#define system_printf(...) \
|
||||
do \
|
||||
{ \
|
||||
__cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__); \
|
||||
#define SIGHANDLE(SIG) \
|
||||
do \
|
||||
{ \
|
||||
struct sigaction act; \
|
||||
\
|
||||
act.sa_handler = &handle_signal; \
|
||||
act.sa_mask = 0; \
|
||||
act.sa_flags = 0; \
|
||||
\
|
||||
if (sigaction (SIG, &act, NULL) == -1) \
|
||||
{ \
|
||||
panic ("failed to install handler for " #SIG ": %s", \
|
||||
strerror (errno)); \
|
||||
exit (1); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define __noop_printf(...) do {;} while (false)
|
||||
|
||||
#else /* !NEW_MACRO_VARARGS */
|
||||
|
||||
#define system_printf(args...) \
|
||||
do \
|
||||
{ \
|
||||
__cygserver__printf (__PRETTY_FUNCTION__, ## args); \
|
||||
} while (false)
|
||||
|
||||
#define __noop_printf(args...) do {;} while (false)
|
||||
|
||||
#endif /* !NEW_MACRO_VARARGS */
|
||||
|
||||
#ifdef DEBUGGING
|
||||
#define debug_printf system_printf
|
||||
#define paranoid_printf system_printf
|
||||
#define select_printf system_printf
|
||||
#define sigproc_printf system_printf
|
||||
#define syscall_printf system_printf
|
||||
#define termios_printf system_printf
|
||||
#define wm_printf system_printf
|
||||
#define minimal_printf system_printf
|
||||
#define malloc_printf system_printf
|
||||
#define thread_printf system_printf
|
||||
#else
|
||||
#define debug_printf __noop_printf
|
||||
#define paranoid_printf __noop_printf
|
||||
#define select_printf __noop_printf
|
||||
#define sigproc_printf __noop_printf
|
||||
#define syscall_printf __noop_printf
|
||||
#define termios_printf __noop_printf
|
||||
#define wm_printf __noop_printf
|
||||
#define minimal_printf __noop_printf
|
||||
#define malloc_printf __noop_printf
|
||||
#define thread_printf __noop_printf
|
||||
#endif
|
||||
|
||||
#include "safe_memory.h"
|
||||
#define debug_printf(f,...) debug((f),##__VA_ARGS__)
|
||||
#define syscall_printf(f,...) log(LOG_ERR,(f),##__VA_ARGS__)
|
||||
#define system_printf(f,...) log(LOG_ERR,(f),##__VA_ARGS__)
|
||||
|
|
Loading…
Reference in New Issue