diff options
author | Robert Collins <rbtcollins@hotmail.com> | 2002-02-28 14:30:38 +0000 |
---|---|---|
committer | Robert Collins <rbtcollins@hotmail.com> | 2002-02-28 14:30:38 +0000 |
commit | f449bfef408685a2e4c0fc40c601c584fbc7bc82 (patch) | |
tree | 90167807132514f02fd751fbbae71e3b09c2fa65 /winsup/cygserver/shm.cc | |
parent | 062401c9b4bf8a203d7e694194307d84e351fce0 (diff) | |
download | cygnal-f449bfef408685a2e4c0fc40c601c584fbc7bc82.tar.gz cygnal-f449bfef408685a2e4c0fc40c601c584fbc7bc82.tar.bz2 cygnal-f449bfef408685a2e4c0fc40c601c584fbc7bc82.zip |
2002-02-28 Robert Collins <rbtcollins@hotmail.com>
* Merged cygwin_daemon into head minus the new shm and ipc exports.
2002-02-28 Robert Collins <rbtcollins@hotmail.com>
* fhandler_tty.cc (fhandler_tty_slave::open): More debugging.
(fhandler_tty_slave::read): Fix printf type for the handle.
* tty.cc (tty::common_init): Add a FIXME for security.
2002-01-29 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in (OBJS): Remove duplicate localtime.o.
2002-01-17 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (check_and_dup_handle): Consolidate the two variants for
simplicity.
Add Some basic debug output.
(client_request_attach_tty::serve): Use the new debug_printf for clarity.
Mark the duplicated handles as inheritable - fixup_after_fork() doesn't reopen
tty's.
2002-01-16 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (transport): Correct scope.
(client_request_attach_tty::serve): Add more debug information.
Fix erroneous use of transport instead of conn.
* cygserver_transport_pipes.cc (transport_layer_pipes::close): More debug.
(transport_layer_pipes::read): Ditto.
(transport_layer_pipes::write): Ditto.
(transport_layer_pipes::impersonate_client): Ditto.
Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (server_request::process): Rename client_request_shm_get to
client_request_shm.
* cygserver_process.cc (process_cache::add): Rename to add_task.
Use process_cleanup instead of process_request.
(process_cache::remove_process): New method.
(process::process): Initialize new members.
(process::~process): New member.
(process::cleanup): New method.
(process::add_cleanup_routine): New method.
(process_request::process): Rename to process_cleanup.
Call the process object's cleanup method and then delete it.
(process_process_param::request_loop): Remove the signalling process.
* cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm.
(client_request_shm_get::serve): Handle attach request counting.
* cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm.
(class shm_cleanup): New class.
* shm.cc: Globally rename client_request_shm_get to client_request_shm.
(client_request_shm::client_request_shm): New constructor for attach requests.
(shmat): Use it.
* include/cygwin/cygserver_process.h (class process_request): Rename to
process_cleanup.
(class cleanup_routine): New class.
(class process): New members and methods to allow calling back when the process
terminates.
Thu Oct 4 14:12:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (request_loop): Make static.
(main): Use new cache constructor syntax.
Start cache worker threads.
Cleanup the cache at shutdown.
* cygserver_process.cc: Run indent.
(process_cache::process_cache): Add a trigger to use when adding a process.
(process_cache::process): Move process_entry to process.
Insert at the end of the list.
Trigger the request loop when new process's inserted.
(process_cache::process_requests): Do it.
(process_cache::add): New method.
(process_cache::handle_snapshot): New method.
(process::process): Merge in the process_entry fields.
(process::handle): Make a stub function.
(process::exit_code): New method.
(process_request::process): New method.
(process_process_param::request_loop): New method.
* cygserver_shm.cc: New header dependency - threaded_queue.h.
* threaded_queue.cc (threaded_queue::cleanup): Clearer messages.
(queue_process_param::stop): Short spinlock on interruptible threads.
* threaded_queue.h (class threaded_queue): New constructor.
* include/cygwin/cygserver_process.h (process_request): New class.
(process_entry): Remove.
(process): Merge in process_entry.
(process_cache): Inherit from threaded_queue.
Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (class server_process_param): Use new constructor syntax.
* cygserver_process.cc (process_cache::~process_cache): New function.
* threaded_queue.cc: Define condition debug_printf.
Run indent.
(threaded_queue::cleanup): Move queue_process_param guts to a method.
(threaded_queue::process_requests): Ditto.
(queue_process_param::queue_process_param): New method.
(queue_process_param::~queue_process_param): Ditto.
(queue_process_param::start): Ditto.
(queue_process_param::stop): Ditto.
* threaded_queue.h (class queue_process_param): Add support for
interruptible request loops.
* cygwin/include/cygwin/cygserver_process.h (class process_cache): Add
destructor.
Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver_client.cc: New flag allow_daemon to disable the daemon completely.
(cygserver_request): Check it.
(cygserver_init): Ditto.
* environ.cc (parse_thing): Add (no)daemon option.
Tue Oct 2 23:00:00 2001 Robert Collins <rbtcollins@hotmail.com>
* shm.cc: Update to handle include changes from HEAD.
Tue Oct 2 16:06:00 2001 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in: Remove cygserver_shm.o from cygwin1.dll.
Rename cygserver_shm_outside.o to cygserver_shm.o.
* cygserver.cc (server_request::process): Use the new client_request
constructor.
* cygserver_client.cc: Remove the #ifdef's stubs for the server method
within cygwin.
(client_request_attach_tty::client_request_attach_tty): Use the new
client_request constructor.
(client_request_shutdown::client_request_shutdown): Ditto.
(client_request::client_request): Ditto.
* cygserver_shm.cc (client_request_shm_get::serve): Remove the
#ifdef'd stub for in-cygwin builds.
(client_request_shm_get::client_request_shm_get): Use the new
client_request constructor, and remove the in-cygwin variants.
* cygserver_shm.h (class client_request_shm_get): #ifndef test the
serve method - it's only used in cygserver.
* shm.cc (client_request_shm_get::client_request_shm_get): New function.
* include/cygwin/cygserver.h (request_header): New constructor.
(class client_request): Use it.
New constructor accepting the header size.
#ifndef test the server method - it's only used within cygserver.
(client_request_get_version): #ifdef test the server method.
(client_request_shutdown): Ditto.
(client_request_attach_tty): Ditto.
Tue Oct 2 9:57:00 2001 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in: add threaded_queue.o to cygserver.exe.
* cygserver.cc: Include threaded_queue.h
(class server_request): Inherit from queue_request.
(class server_process_param): Inherit from queue_process_param.
(class server_request_queue): Inherit from threaded_queue.
(request_loop): Adjust for new types.
(server_request_queue::process_requests): Remove guts to
threaded_queue::process_requests.
(server_request::server_request): Adjust for new types.
(worker_function): Delete.
(server_request_queue::create_workers): Delete.
(server_request_queue::cleanup): Delete.
(server_request_queue::add): Move guts to threaded_queue::add.
* threaded_queue.cc: New file.
* threaded_queue.h: New file.
Mon Oct 1 12:38:00 2001 Robert Collins <rbtcollins@hotmail.com>
* cygserver.cc (client_request::serve): New function.
* cygserver_process.cc: Inlude <pthread.h> for pthread_once.
(process_cache::process_cache): Initialise a crtiical section for write access.
(process_cache::process): Use the critical section. Also add missing entries to
the cache.
(do_process_init): New function to initalise class process static variables.
(process::process): Ensure that the process access critical section is
initialised.
(process::handle): Close the handle of old process's when they have terminated
and we are returning the handle for a process with the same pid.
* cygserver_shm.cc: Run indent.
Include cygserver_process.h to allow process cache functionality.
(client_request_shm_get::serve): New parameter for process cache support.
Use the process cache, not OpenProcess to get a handle to the originating process.
Fix a handle leak with token_handle.
* cygserver_shm.h (class client_request_shm_get): Update ::serve for process
cache support.
* cygserver_transport_pipes.cc: Redefine debug_printf to be conditional on DEBUG.
* include/cygwin/cygserver.h: Do not implement client_request::serve in the
header.
* include/cygwin/cygserver_process.h (class process_cache): Add a write access
critical section to prevent races when requests from a multithreaded
application arrive.
Sun Sep 30 23:41:00 2001 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in: Add cygserver_process.o to cygserver.exe.
* cygserver.cc: Include signal.h and cygwin_version.h.
Define debug_printf as a macro.
Define DEBUG to a value.
(client_request_attach_tty::serve): Add beginning of process cache support.
Change from #ifdef DEBUG to work with new DEBUG style.
(client_request_get_version::serve): Add beginning of process cache support.
(class server_request): New prototype for support of process cache.
(class queue_process_param): New class to allow request loop threading.
(class server_request_queue): Add beginning of process cache support.
Allow request loop threading.
(request_loop): Thread function for request loops.
(server_request_queue::process_requests): Initiator for threaded request loops.
(client_request_shutdown::serve): Add beginning of process cache support.
(server_request::server_request): Ditto.
(server_request::process): Use debug_printf. Add beginning of process cache
support.
(server_request_queue::cleanup): Kill off any request loop threads.
(server_request_queue::add): Add beginning of process cache support.
(handle_signal): Trigger a shutdown.
(main): Print out some useful info at startup - version, date time.
Add process cache support.
Spawn a separate thread for the transport request loop, thus allowing concurrent
support for multiple transports.
* cygserver_client.cc (client_request_get_version::serve): Add process cache
support.
(client_request_attach_tty::serve): Add process cache support.
(client_request_shutdown::serve): Add process cache support.
* cygsserver_process.cc: New file with the process cache support.
* cygserver_shm.cc: Redefine debug_printf to allow conditional output.
* cygwin.din: Export shmdt().
* shm.cc: Run indent.
Update FIXME's.
(shmdt): New function.
* include/cygwin/cygserver.h (class client_request): Add process cache support.
(class client_request_get_version): Ditto.
(class client_request_shutdown): Ditto.
(class client_request_attach_tty): Ditto.
* include/cygwin/cygserver_process.h: New header for process cache support.
Sun Sep 30 8:52:00 2001 Robert Collins <rbtcollins@hotmail.com>
* include/cygwin/cygserver_transport.h: Add copyright header.
* include/cygwin/cygserver_transport_pipes.h: Ditto.
* include/cygwin/cygserver_transport_sockets.h: Ditto.
Sat Sep 29 20:40:00 2001 Robert Collins <rbtcollins@hotmail.com>
* Makefile.in: Add cygserver_transport_sockets.o to DLL_OFILES.
Add cygserver_transport_sockets_outside.o to cygserver.exe.
* cygserver.cc: Include new include files.
* cygserver_client.cc: Ditto.
* cygserver_shm.h: No need to include <sys/socket.h> now.
* cygerver_transport.cc: Include new include files.
(transport_layer_base::transport_layer_base): Strip back to a stub.
(transport_layer_base::listen): Ditto.
(transport_layer_base::accept): Ditto.
(transport_layer_base::close): Ditto.
(transport_layer_base::read): Ditto.
(transport_layer_base::write): Ditto.
(transport_layer_base::connect): Ditto.
* cygserver_transport_pipes.cc: Include new header
"cygwin/cygserver_transport_pipes.h".
* cygserver_transport_sockets.cc: New file.
* dcrt0.cc: No need to include <sys/socket.h> now.
* fhandler_tty.cc: Ditto.
* tty.cc: Ditto.
* include/cygwin/cygserver_transport.h: Strip the base class to a stub.
Remove the cygserver_transport_pipes class.
* include/cygwin/cygserver_transport_pipes.h: New file.
* include/cygwin/cygserver_transport_sockets.h: New file.
Tue Sep 25 16:22:00 2001 Robert Collins <rbtcollins@hotmail.com>
* autoload.cc: Add dynamic load statement for 'ImpersonateNamedPipeClient'.
* Makefile.in: Add new object files, and build instructions for cygserver.exe.
* cygwin.din: Export ftok, shmat, shmctl and shmget.
* dcrt0.cc: Additional includes for cygserver support.
(dll_crt0_1): Initialise the cygserver client.
* fhandler.h (fhandler_tty): New method cygserver_attach_tty.
* fhandler_tty.cc: Additional includes for cygserver support.
(fhandler_tty_slave::open): Attempt to use the cygserver when obtaining
handles from the parent process. On failure or 9x use the current method.
(fhandler_tty_slave::cygserver_attach_tty): New function.
* fork.cc (fork_child): Fixup shm memory mapped areas.
* pinfo.h: Declare fixup_shms_after_fork().
* security.h: Declare alloc_sd().
* tty.cc: Additonal includes to support cygserver.
(tty::common_init): Don't allow others to open us if the cygserver is running.
* winsup.h: Declare cygserver_running.
* cygserver.cc: New file.
* cygserver_client.cc: New file.
* cygserver_shm.cc: New file.
* cygserver_shm.h: New file.
* cygserver_transport.cc: New file.
* cygserver_transport_pipes.cc: New file.
* ipc.cc: New file.
* shm.cc: New file.
* include/cygwin/cygserver.h: New file.
* include/cygwin/cygserver_transport.h: New file.
* include/sys/ipc.h: New file.
* include/sys/shm.h: New file.
2002-02-28 Robert Collins <rbtcollins@hotmail.com>
* thread.cc (semaphore::TryWait): Set errno as required by posix 1003.1.
(__sem_wait): Ditto.
(__sem_trywait): Ditto.
Diffstat (limited to 'winsup/cygserver/shm.cc')
-rw-r--r-- | winsup/cygserver/shm.cc | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/winsup/cygserver/shm.cc b/winsup/cygserver/shm.cc new file mode 100644 index 000000000..c29938bb9 --- /dev/null +++ b/winsup/cygserver/shm.cc @@ -0,0 +1,552 @@ +/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin + + Copyright 2001 Red Hat, Inc. + + Originally written by Robert Collins <robert.collins@hotmail.com> + + 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__ +#undef __INSIDE_CYGWIN__ +#else +#include "winsup.h" +#endif + +#ifndef __INSIDE_CYGWIN__ +#define DEBUG 0 +#define system_printf printf +#define debug_printf if (DEBUG) printf +#define api_fatal printf +#include <stdio.h> +#include <windows.h> +#endif + +#include <sys/stat.h> +#include <errno.h> +#include "cygerrno.h" +#include <unistd.h> +#include "security.h" +//#include "fhandler.h" +//#include "dtable.h" +//#include "cygheap.h" +#include <stdio.h> +//#include "thread.h" +#ifndef __INSIDE_CYGWIN__ +#define __INSIDE_CYGWIN__ +#include <sys/shm.h> +#undef __INSIDE_CYGWIN__ +#else +#include <sys/shm.h> +#endif +//#include "perprocess.h" +#include <threaded_queue.h> +#include <cygwin/cygserver_process.h> +#include "cygserver_shm.h" + +// FIXME IS THIS CORRECT +/* Implementation notes: We use two shared memory regions per key: + * One for the control structure, and one for the shared memory. + * While this has a higher overhead tham a single shared area, + * It allows more flexability. As the entire code is transparent to the user + * We can merge these in the future should it be needed. + * Also, IPC_PRIVATE keys create unique mappings each time. The shm_ids just + * keep monotonically incrementing - system wide. + */ +size_t +getsystemallocgranularity () +{ + SYSTEM_INFO sysinfo; + static size_t buffer_offset = 0; + if (buffer_offset) + return buffer_offset; + GetSystemInfo (&sysinfo); + buffer_offset = sysinfo.dwAllocationGranularity; + return buffer_offset; +} + + +client_request_shm::client_request_shm ():client_request (CYGSERVER_REQUEST_SHM_GET, sizeof (parameters)) +{ + buffer = (char *) ¶meters; +} + +/* FIXME: If building on a 64-bit compiler, the address->int typecast will fail. + * Solution: manually calculate the next id value + */ + +#if 0 +extern "C" void * +shmat (int shmid, const void *shmaddr, int parameters.in.shmflg) +{ + class shmid_ds *shm = (class shmid_ds *) shmid; //FIXME: verifyable object test + + if (shmaddr) + { + //FIXME: requested base address ?! + set_errno (EINVAL); + return (void *) -1; + } + + void *rv = MapViewOfFile (shm->attachmap, + + + (parameters.in.shmflg & SHM_RDONLY) ? + FILE_MAP_READ : FILE_MAP_WRITE, 0, + 0, 0); + + if (!rv) + { + //FIXME: translate GetLastError() + set_errno (EACCES); + return (void *) -1; + } + +/* FIXME: this needs to be globally protected to prevent a mismatch betwen + * attach count and attachees list + */ + + InterlockedIncrement (&shm->shm_nattch); + _shmattach *attachnode = new _shmattach; + + attachnode->data = rv; + attachnode->next = + (_shmattach *) InterlockedExchangePointer ((LONG *) & shm->attachhead, + (long int) attachnode); + return rv; +} +#endif + +/* FIXME: evaluate getuid() and getgid() against the requested mode. Then + * choose PAGE_READWRITE | PAGE_READONLY and FILE_MAP_WRITE | FILE_MAP_READ + * appropriately + */ + +/* Test result from openbsd: shm ids are persistent cross process if a handle is left + * open. This could lead to resource starvation: we're not copying that behaviour + * unless we have to. (It will involve acygwin1.dll gloal shared list :[ ). + */ +/* FIXME: shmid should be a verifyable object + */ + +/* FIXME: on NT we should check everything against the SD. On 95 we just emulate. + */ + +extern GENERIC_MAPPING access_mapping; + +extern int +check_and_dup_handle (HANDLE from_process, HANDLE to_process, + HANDLE from_process_token, + DWORD access, + HANDLE from_handle, + HANDLE * to_handle_ptr, BOOL bInheritHandle); + +//FIXME: where should this live +static shmnode *shm_head = NULL; +/* must be long for InterlockedIncrement */ +static long new_id = 0; +static long new_private_key = 0; + +void +client_request_shm::serve (transport_layer_base * conn, + process_cache * cache) +{ +// DWORD sd_size = 4096; +// char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) parameters.in.sd_buf; +// /* create a sd for our open requests based on shmflag & 0x01ff */ +// psd = alloc_sd (getuid (), getgid (), cygheap->user.logsrv (), +// parameters.in.shmflg & 0x01ff, psd, &sd_size); + + HANDLE from_process_handle = NULL; + HANDLE token_handle = NULL; + DWORD rc; + + from_process_handle = cache->process (parameters.in.pid)->handle (); + /* possible TODO: reduce the access on the handle before we use it */ + /* Note that unless we do this, we don't need to call CloseHandle - it's kept open + * by the process cache until the process terminates. + * We may need a refcount on the cache however... + */ + if (!from_process_handle) + { + debug_printf ("error opening process (%lu)\n", GetLastError ()); + header.error_code = EACCES; + return; + } + + conn->impersonate_client (); + + rc = OpenThreadToken (GetCurrentThread (), + TOKEN_QUERY, TRUE, &token_handle); + + conn->revert_to_self (); + + if (!rc) + { + debug_printf ("error opening thread token (%lu)\n", GetLastError ()); + header.error_code = EACCES; + CloseHandle (from_process_handle); + return; + } + + + /* we trust the clients request - we will be doing it as them, and + * the worst they can do is open their own permissions + */ + + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof (sa); + sa.lpSecurityDescriptor = psd; + sa.bInheritHandle = TRUE; /* the memory structures inherit ok */ + + char *shmname = NULL, *shmaname = NULL; + char stringbuf[29], stringbuf1[29]; + + /* TODO: make this code block a function! */ + if (parameters.in.type == SHM_REATTACH) + { + /* just find and fill out the existing shm_id */ + shmnode *tempnode = shm_head; + while (tempnode) + { + if (tempnode->shm_id == parameters.in.shm_id) + { + parameters.out.shm_id = tempnode->shm_id; + parameters.out.key = tempnode->key; + if (check_and_dup_handle + (GetCurrentProcess (), from_process_handle, token_handle, + DUPLICATE_SAME_ACCESS, tempnode->filemap, + ¶meters.out.filemap, TRUE) != 0) + { + debug_printf ("error duplicating filemap handle (%lu)\n", + GetLastError ()); + header.error_code = EACCES; + } + if (check_and_dup_handle + (GetCurrentProcess (), from_process_handle, token_handle, + DUPLICATE_SAME_ACCESS, tempnode->attachmap, + ¶meters.out.attachmap, TRUE) != 0) + { + debug_printf ("error duplicating attachmap handle (%lu)\n", + GetLastError ()); + header.error_code = EACCES; + } + CloseHandle (token_handle); + return; + } + tempnode = tempnode->next; + } + header.error_code = EINVAL; + CloseHandle (token_handle); + return; + } + + /* someone attached */ + /* someone can send shm_id's they don't have and currently we will increment those + * attach counts. If someone wants to fix that, please go ahead. + * The problem is that shm_get has nothing to do with the ability to attach. Attach + * requires a permission check, which we get the OS to do in MapViewOfFile. + */ + if (parameters.in.type == SHM_ATTACH) + { + shmnode *tempnode = shm_head; + while (tempnode) + { + if (tempnode->shm_id == parameters.in.shm_id) + { + InterlockedIncrement (&tempnode->shmds->shm_nattch); + header.error_code = 0; + CloseHandle (token_handle); + return; + } + tempnode = tempnode->next; + } + header.error_code = EINVAL; + CloseHandle (token_handle); + return; + } + + /* it's a original request from the users */ + + /* FIXME: enter the checking for existing keys mutex. This mutex _must_ be system wide + * to prevent races on shmget. + */ + + if (parameters.in.key == IPC_PRIVATE) + { + /* create the mapping name (CYGWINSHMKPRIVATE_0x01234567 */ + /* The K refers to Key, the actual mapped area has D */ + long private_key = (int) InterlockedIncrement (&new_private_key); + snprintf (stringbuf, 29, "CYGWINSHMKPRIVATE_0x%0x", private_key); + shmname = stringbuf; + snprintf (stringbuf1, 29, "CYGWINSHMDPRIVATE_0x%0x", private_key); + shmaname = stringbuf1; + } + else + { + /* create the mapping name (CYGWINSHMK0x0123456789abcdef */ + /* The K refers to Key, the actual mapped area has D */ + + snprintf (stringbuf, 29, "CYGWINSHMK0x%0qx", parameters.in.key); + shmname = stringbuf; + snprintf (stringbuf1, 29, "CYGWINSHMD0x%0qx", parameters.in.key); + shmaname = stringbuf1; + debug_printf ("system id strings are \n%s\n%s\n", shmname, shmaname); + debug_printf ("key input value is 0x%0qx\n", parameters.in.key); + } + + /* attempt to open the key */ + + /* get an existing key */ + /* On unix the same shmid identifier is returned on multiple calls to shm_get + * with the same key and size. Different modes is a ?. + */ + + + + /* walk the list of known keys and return the id if found. remember, we are + * authoritative... + */ + + shmnode *tempnode = shm_head; + while (tempnode) + { + if (tempnode->key == parameters.in.key + && parameters.in.key != IPC_PRIVATE) + { + // FIXME: free the mutex + if (parameters.in.size + && tempnode->shmds->shm_segsz < parameters.in.size) + { + header.error_code = EINVAL; + CloseHandle (token_handle); + return; + } + /* FIXME: can the same process call this twice without error ? test + * on unix + */ + if ((parameters.in.shmflg & IPC_CREAT) + && (parameters.in.shmflg & IPC_EXCL)) + { + header.error_code = EEXIST; + debug_printf + ("attempt to exclusively create already created shm_area with key 0x%0qx\n", + parameters.in.key); + // FIXME: free the mutex + CloseHandle (token_handle); + return; + } + // FIXME: do we need to other tests of the requested mode with the + // tempnode->shm_id mode ? testcase on unix needed. + // FIXME how do we do the security test? or + // do we wait for shmat to bother with that? + /* One possibly solution: impersonate the client, and then test we can + * reopen the area. In fact we'll probably have to do that to get + * handles back to them, alternatively just tell them the id, and then + * let them attempt the open. + */ + parameters.out.shm_id = tempnode->shm_id; + if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, + token_handle, + DUPLICATE_SAME_ACCESS, + tempnode->filemap, + ¶meters.out.filemap, TRUE) != 0) + { + printf ("error duplicating filemap handle (%lu)\n", + GetLastError ()); + header.error_code = EACCES; +/*mutex*/ + CloseHandle (token_handle); + return; + } + if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, + token_handle, + DUPLICATE_SAME_ACCESS, + tempnode->attachmap, + ¶meters.out.attachmap, TRUE) != 0) + { + printf ("error duplicating attachmap handle (%lu)\n", + GetLastError ()); + header.error_code = EACCES; +/*mutex*/ + CloseHandle (token_handle); + return; + } + + CloseHandle (token_handle); + return; + } + tempnode = tempnode->next; + } + /* couldn't find a currently open shm area. */ + + /* create one */ + /* do this as the client */ + conn->impersonate_client (); + /* This may need sh_none... it's only a control structure */ + HANDLE filemap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile. + &sa, + PAGE_READWRITE, // protection + 0x00000000, + getsystemallocgranularity (), + shmname // object name + ); + int lasterr = GetLastError (); + conn->revert_to_self (); + + if (filemap == NULL) + { + /* We failed to open the filemapping ? */ + system_printf ("failed to open file mapping: %lu\n", GetLastError ()); + // free the mutex + // we can assume that it exists, and that it was an access problem. + header.error_code = EACCES; + CloseHandle (token_handle); + return; + } + + /* successfully opened the control region mapping */ + /* did we create it ? */ + int oldmapping = lasterr == ERROR_ALREADY_EXISTS; + if (oldmapping) + { + /* should never happen - we are the global daemon! */ +#if 0 + if ((parameters.in.shmflg & IPC_CREAT) + && (parameters.in.shmflg & IPC_EXCL)) +#endif + { + /* FIXME free mutex */ + CloseHandle (filemap); + header.error_code = EEXIST; + CloseHandle (token_handle); + return; + } + } + + /* we created a new mapping */ + if (parameters.in.key != IPC_PRIVATE && + (parameters.in.shmflg & IPC_CREAT) == 0) + { + CloseHandle (filemap); + /* FIXME free mutex */ + header.error_code = ENOENT; + CloseHandle (token_handle); + return; + } + + conn->impersonate_client (); + void *mapptr = MapViewOfFile (filemap, FILE_MAP_WRITE, 0, 0, 0); + conn->revert_to_self (); + + if (!mapptr) + { + CloseHandle (filemap); + //FIXME: close filemap and free the mutex + /* we couldn't access the mapped area with the requested permissions */ + header.error_code = EACCES; + CloseHandle (token_handle); + return; + } + + conn->impersonate_client (); + /* Now get the user data */ + HANDLE attachmap = CreateFileMapping (INVALID_HANDLE_VALUE, // system pagefile + &sa, + PAGE_READWRITE, // protection (FIXME) + 0x00000000, + parameters.in.size + + parameters.in.size % + getsystemallocgranularity (), + shmaname // object name + ); + conn->revert_to_self (); + + if (attachmap == NULL) + { + system_printf ("failed to get shm attachmap\n"); + header.error_code = ENOMEM; + UnmapViewOfFile (mapptr); + CloseHandle (filemap); + /* FIXME exit the mutex */ + CloseHandle (token_handle); + return; + } + + shmid_ds *shmtemp = new shmid_ds; + if (!shmtemp) + { + system_printf ("failed to malloc shm node\n"); + header.error_code = ENOMEM; + UnmapViewOfFile (mapptr); + CloseHandle (filemap); + CloseHandle (attachmap); + /* FIXME exit mutex */ + CloseHandle (token_handle); + return; + } + + /* fill out the node data */ + shmtemp->shm_perm.cuid = getuid (); + shmtemp->shm_perm.uid = shmtemp->shm_perm.cuid; + shmtemp->shm_perm.cgid = getgid (); + shmtemp->shm_perm.gid = shmtemp->shm_perm.cgid; + shmtemp->shm_perm.mode = parameters.in.shmflg & 0x01ff; + shmtemp->shm_lpid = 0; + shmtemp->shm_nattch = 0; + shmtemp->shm_atime = 0; + shmtemp->shm_dtime = 0; + shmtemp->shm_ctime = time (NULL); + shmtemp->shm_segsz = parameters.in.size; + *(shmid_ds *) mapptr = *shmtemp; + shmtemp->mapptr = mapptr; + + /* no need for InterlockedExchange here, we're serialised by the global mutex */ + tempnode = new shmnode; + tempnode->shmds = shmtemp; + tempnode->shm_id = (int) InterlockedIncrement (&new_id); + tempnode->key = parameters.in.key; + tempnode->filemap = filemap; + tempnode->attachmap = attachmap; + tempnode->next = shm_head; + shm_head = tempnode; + + /* we now have the area in the daemon list, opened. + + FIXME: leave the system wide shm mutex */ + + parameters.out.shm_id = tempnode->shm_id; + if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, + token_handle, + DUPLICATE_SAME_ACCESS, + tempnode->filemap, ¶meters.out.filemap, + TRUE) != 0) + { + printf ("error duplicating filemap handle (%lu)\n", GetLastError ()); + header.error_code = EACCES; + CloseHandle (token_handle); +/* mutex et al */ + return; + } + if (check_and_dup_handle (GetCurrentProcess (), from_process_handle, + token_handle, + DUPLICATE_SAME_ACCESS, + tempnode->attachmap, ¶meters.out.attachmap, + TRUE) != 0) + { + printf ("error duplicating attachmap handle (%lu)\n", GetLastError ()); + header.error_code = EACCES; + CloseHandle (from_process_handle); + CloseHandle (token_handle); +/* more cleanup... yay! */ + return; + } + CloseHandle (token_handle); + return; +} |