diff options
author | Corinna Vinschen <vinschen@redhat.com> | 2006-07-06 13:40:58 +0000 |
---|---|---|
committer | Corinna Vinschen <vinschen@redhat.com> | 2006-07-06 13:40:58 +0000 |
commit | 9ee064b4bd06b7be50fbc976c46172f83557f084 (patch) | |
tree | 60d4c70ba6f61b9046396c77a4fdc51466cb0b5f | |
parent | 69a7b5f79888513741e65a54216d7756474b76c2 (diff) | |
download | gdb-9ee064b4bd06b7be50fbc976c46172f83557f084.tar.gz |
* autoload.cc (DsGetDcNameA): Define.
(NetGetAnyDCName): Define.
* security.cc: Include dsgetdc.h.
(DsGetDcNameA): Declare.
(DS_FORCE_REDISCOVERY): Define.
(get_logon_server): Add bool parameter to control rediscovery of DC.
Use DsGetDcNameA function if supported, NetGetDCName/NetGetAnyDCName
otherwise.
(get_server_groups): Rediscover DC if get_user_groups fails and
try again.
(get_reg_security): Use correct error code macro when testing
RegGetKeySecurity return value.
* security.h (get_logon_server): Remove default vaue from wserver
parameter. Add rediscovery parameter.
* uinfo.cc (cygheap_user::env_logsrv): Accomodate rediscovery parameter
in call to get_logon_server.
-rw-r--r-- | winsup/cygwin/ChangeLog | 2168 | ||||
-rw-r--r-- | winsup/cygwin/autoload.cc | 572 | ||||
-rw-r--r-- | winsup/cygwin/security.cc | 1893 | ||||
-rw-r--r-- | winsup/cygwin/security.h | 402 | ||||
-rw-r--r-- | winsup/cygwin/uinfo.cc | 572 |
5 files changed, 5607 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog new file mode 100644 index 00000000000..9ab0c2cb1b7 --- /dev/null +++ b/winsup/cygwin/ChangeLog @@ -0,0 +1,2168 @@ +2006-07-06 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (DsGetDcNameA): Define. + (NetGetAnyDCName): Define. + * security.cc: Include dsgetdc.h. + (DsGetDcNameA): Declare. + (DS_FORCE_REDISCOVERY): Define. + (get_logon_server): Add bool parameter to control rediscovery of DC. + Use DsGetDcNameA function if supported, NetGetDCName/NetGetAnyDCName + otherwise. + (get_server_groups): Rediscover DC if get_user_groups fails and + try again. + (get_reg_security): Use correct error code macro when testing + RegGetKeySecurity return value. + * security.h (get_logon_server): Remove default vaue from wserver + parameter. Add rediscovery parameter. + * uinfo.cc (cygheap_user::env_logsrv): Accomodate rediscovery parameter + in call to get_logon_server. + +2006-07-05 Christopher Faylor <cgf@timesys.com> + + * sortdin: Ignore all leading underscores when deriving a sort key. + * cygwin.din: Resort. + +2006-07-05 Christopher Faylor <cgf@timesys.com> + + * sortdin: New program. + * cygwin.din: Sort. + +2006-07-05 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (fhandler_socket::wait): Reset default timeout to 10ms. + +2006-07-05 Corinna Vinschen <corinna@vinschen.de> + + * path.cc (path_conv::check): Ignore has_ea setting, it's always unset + at this point anyway. + (get_symlink_ea): Remove. + (set_symlink_ea): Remove. + (symlink_worker): Drop writing symlink into NTFS extended attributes. + (symlink_info::check): Drop reading symlinks from NTFS extended + attributes. + +2006-07-04 Christopher Faylor <cgf@timesys.com> + + * libc/rexec.cc (cygwin_rexec): Obvious (?) fix to correct a gcc + warning - set port to zero first thing in the function. + +2006-07-04 Corinna Vinschen <corinna@vinschen.de> + + * signal.cc (signal): Set sa_mask to sig. + +2006-07-04 Corinna Vinschen <corinna@vinschen.de> + + * Makefile.in (DLL_OFILES): Add rexec.o. + * autoload.cc (inet_network): Drop definition. + (rexec): Ditto. + * net.cc (rexec): Drop extern declaration. + (inet_network): Ditto. + (cygwin_inet_network): Implement using inet_addr. + (cygwin_rexec): Remove. + * libc/rexec.cc: New file. + +2006-07-04 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_socket.cc (fhandler_socket::listen): Allow listening on + unbound INET socket. + +2006-07-04 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (fhandler_socket::wait): Set default timeout to INFINITE. + +2006-07-03 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (NtQueryEaFile): Define. + (NtSetEaFile): Define. + * fhandler.cc (fhandler_base::open): Use appropriate open flags + in query case when allow_ntea is set. + * ntdll.h (struct _FILE_GET_EA_INFORMATION): Define. + (struct _FILE_FULL_EA_INFORMATION): Define. + (NtQueryEaFile): Declare. + (NtSetEaFile): Declare. + * ntea.cc (read_ea): Rename from NTReadEA and rewrite using + NtQueryEaFile. + (write_ea): Rename from NTWriteEA and rewrite using NtSetEaFile. + * path.cc (get_symlink_ea): Make static. Add handle parameter to + accomodate new read_ea call. + (set_symlink_ea): Make static. Add handle parameter to accomodate new + write_ea call. + (symlink_worker): Call set_symlink_ea while file is still open. + (symlink_info::check): Call get_symlink_ea after file has been opened. + * security.cc (get_file_attribute): Accomodate new read_ea call. + (set_file_attribute): Accomodate new write_ea call. + * security.h (read_ea): Change declaration accordingly. + (write_ea): Ditto. + +2006-07-03 Kazuhiro Fujieda <fujieda@jaist.ac.jp> + + * fhandler.h (class dev_console): Add `metabit' indicating the + current meta key mode. + * fhandler_console.cc (fhandler_console::read): Set the top bit of + the character if metabit is true. + * fhandler_console.cc (fhandler_console::ioctl): Implement + KDGKBMETA and KDSKBMETA commands. + * fhandler_tty.cc (process_ioctl): Support KDSKBMETA. + (fhandler_tty_slave::ioctl): Send KDGKBMETA and KDSKBMETA to the + master. + * include/cygwin/kd.h: New file for the meta key mode. + * include/sys/kd.h: New file. + +2006-07-03 Eric Blake <ebb9@byu.net> + + * include/stdint.h (UINT8_C, UINT16_C): Unsigned types smaller + than int promote to signed int. + +2006-07-03 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (cygwin_sendto): Define appropriate parameters using + socklen_t type according to SUSv3. + (cygwin_recvfrom): Ditto. + (cygwin_setsockopt): Ditto. + (cygwin_getsockopt): Ditto. + (cygwin_connect): Ditto. + (cygwin_accept): Ditto. + (cygwin_bind): Ditto. + (cygwin_getsockname): Ditto. + (cygwin_getpeername): Ditto. + (cygwin_recv): Ditto. + (cygwin_send): Ditto. + * include/cygwin/socket.h (socklen_t): Typedef and define. + * include/sys/socket.h: Declare socket functions using socklen_t type. + +2006-07-02 Christopher Faylor <cgf@timesys.com> + + * include/cygwin/version.h: Bump DLL minor version number to 21. + +2006-06-30 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (cygwin_sendto): Allow zero-sized packets. + (cygwin_sendmsg): Ditto. + +2006-06-26 Corinna Vinschen <corinna@vinschen.de> + + Revert patches from 2005-10-22 and 2006-06-14 to use event driven + accept and connect back to using select: + * fhandler.h (class fhandler_socket): Remove accept_mtx. + * fhandler_socket.cc (fhandler_socket::fhandler_socket): Drop + initializing accept_mtx. + (fhandler_socket::accept): Drop event handling. + (fhandler_socket.cc (fhandler_socket::connect): Ditto. + (fhandler_socket::dup): Drop accept_mtx handling. + (fhandler_socket::listen): Ditto. + (fhandler_socket::prepare): Ditto. + (fhandler_socket::release): Ditto. + (fhandler_socket::close): Ditto. + * net.cc (cygwin_accept): Revert to calling cygwin_select to + implement interuptible accept. + (cygwin_connect): Ditto for connect. + +2006-06-22 Christopher Faylor <cgf@timesys.com> + + * fhandler_fifo.cc (fhandler_fifo::open): Release process lock and grab + a system-wide mutex to prevent a deadlock and a race. + * sync.h (lock_process): Make fhandler_fifo a friend. + + * smallprint.c (__small_vsprintf): Cosmetic change. + +2006-06-15 Corinna Vinschen <corinna@vinschen.de> + + * cygwin.din: Export __srget_r, __swbuf_r. + * include/cygwin/version.h: Bump API minor number to 156. + +2006-06-14 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (class fhandler_socket): Add private mutex handle + accept_mtx. + * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize + accept_mtx to NULL. + (fhandler_socket::dup): Duplicate accept_mtx, if available. + (fhandler_socket::listen): Create accept_mtx before trying to listen. + (fhandler_socket::prepare): Wait for accept_mtx if available to + serialize accepts on the same socket. + (fhandler_socket::release): Release accept_mtx. + (fhandler_socket::close): Close accept_mtx on successful closesocket. + +2006-06-12 Christopher Faylor <cgf@timesys.com> + + * fhandler_tty.cc (fhandler_pty_master::close): Always close + from_master/to_master since we always have copies of these handles. + +2006-06-12 Corinna Vinschen <corinna@vinschen.de> + + * include/sys/wait.h: Move definition of wait constants from here... + * include/cygwin/wait.h: ...to here. New file. + * include/cygwin/stdlib.h: Include cygwin/wait.h to conform with SUSv3. + +2006-06-12 Pierre Humblet Pierre.Humblet@ieee.org + + * heap.cc (heap_init): Only commit if allocsize is not zero. + +2006-06-12 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (fdsock): Disable raising buffer sizes. Add comment to + explain why. + +2006-06-04 Christopher Faylor <cgf@timesys.com> + + * ioctl.cc (ioctl): Accommodate change in reported pty master device + number. + * select.cc (peek_pipe): Ditto. + +2006-06-04 Christopher Faylor <cgf@timesys.com> + + * cygtls.h (CYGTLS_PADSIZE): Reset to a size that XP SP1 seems to like. + * tlsoffsets.h: Regenerate. + +2006-06-03 Christopher Faylor <cgf@timesys.com> + + * cygthread.cc (cygthread::terminate_thread): In debugging output, use + name of thread being terminated rather than thread doing the + terminating. + + * fhandler.h (fhandler_pty_master::slave): Delete. + (fhandler_pty_master::get_unit): Ditto. + (fhandler_pty_master::setup): Change argument declaration to + accommodate new usage. + * fhandler_tty.cc (fhandler_tty_master::init): Remove obsolete slave + assignment. Pass argument to setup indicating that this is a tty. + (fhandler_tty_slave::open): Use dev() method rather than referencing + pc.dev directly. + (fhandler_pty_master::open): Don't create archetype based on ptym + device number. Set device number to use DEV_TTYM_MAJOR and tty number. + Pass argument to setup indicating that this is a pty. + (fhandler_pty_master::setup): Change single argument to a flag + indicating whether we're creating a pty and use appropriately. + Calculate 't' variable here rather than in caller. + + * fhandler_dsp.cc (fhandler_dev_dsp::open): Use dev() method rather + than referencing pc.dev directly. + +2006-06-03 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Call tty_list::init_session here. + (dll_crt0_1): Reflect renaming from tty_init to tty::init_session. + (do_exit): Reflect moving of tty_terminate into tty_list. + * exceptions.cc (events_init): Move tty_mutex stuff elsewhere. + * fhandler_console.cc (set_console_title): Use lock_ttys class. + * fhandler_termios.cc (fhandler_termios::bg_check): Make debug output + more accurate. + * fhandler_tty.cc (fhandler_tty_slave::open): Reflect move of + attach_tty into tty_list class. Don't attempt to grab master end of + pty if master doesn't exist. + (fhandler_pty_master::open): Reflect move of allocate_tty into tty_list + class. Use lock_ttys::release to release mutex. Improve debugging + output. + (fhandler_pty_master::setup): Remove if 0'ed block. Fix argument to + SetNamedPipeHandleState. + * pinfo.cc (_pinfo::set_ctty): Lock ttys before setting sid/pgid. + Improve debugging. Add temporary debugging. + * tty.cc (tty_list::init_session): New function. + (tty::init_session): Rename from tty_init. Reflect move of attach_tty + to tty_list class. + (tty::create_master): Rename from create_tty_master. + (tty_list::attach): Rename from attach_tty. Reflect renaming of + connect_tty to connect. Ditto for allocate_tty. + (tty_terminate): Delete. + (tty_list::terminate): Subsume tty_terminate. Use lock_ttys rather + than manipulating mutex directly. + (tty_list::allocate): Rename from allocate_tty. Use lock_ttys rather + than manipulating mutex directly. Don't set sid here since linux + apparently doesn't do this. Reflect move of create_tty_master into + tty. + (lock_ttys::lock_ttys): Define new constructor. + (lock_ttys::release): New function. + * tty.h (tty::exists): Return false immediately if !master_pid. + (tty::set_master_closed): Define new function. + (tty::create_master): Ditto. + (tty::init_session): Ditto. + (tty_list::mutex): New field. + (tty_list::allocate): Define new function. + (tty_list::connect): Ditto. + (tty_list::attach): Ditto. + (tty_list::init_session): Ditto. + (lock_ttys): New class. + (tty_init): Delete declaration. + (tty_terminate): Ditto. + (attach_tty): Ditto. + (create_tty_master): Ditto. + +2006-06-03 Christopher Faylor <cgf@timesys.com> + + * Makefile.in (libdl.a): New library. + +2006-06-03 Christopher Faylor <cgf@timesys.com> + + * fhandler_tty.cc (fhandler_pty_master::close): Don't close handles if + we don't own them. + (fhandler_pty_master::setup): Make sure that original handle is closed + when changing inheritance. + (fhandler_pty_master::fixup_after_fork): Set from_master/to_master to + arch value always. + (fhandler_pty_master::fixup_after_exec): Clear from_master/to_master + when close_on_exec. + +2006-06-03 Christopher Faylor <cgf@timesys.com> + + * cygheap.cc (init_cygheap::close_ctty): Remove obsolete code. + * dcrt0.cc (child_info_spawn::handle_spawn): Signal ready after we've + run fixup_after_exec. + * dtable.cc (dtable::fixup_after_exec): Add debugging output. + * fhandler_tty.cc (fhandler_pty_master::doecho): Use class version of + to_master. + (fhandler_tty_common::close): Remove obsolete code. + (fhandler_tty_slave::fixup_after_exec): Don't close, since this is done + in dtable's fixup_after_exec. (revisit later?) + (fhandler_pty_master::fixup_after_exec): Ditto. + +2006-06-02 Christopher Faylor <cgf@timesys.com> + + * cygtls.h (CYGTLS_PADSIZE): Bump up or suffer a regrettable collision + with the call chain. + * tlsoffsets.h: Regenerate. + + * dcrt0.cc (break_here): Define unconditionally for use elsewhere. + Call DebugBreak, if appropriate. + (initial_env): Rely on break_here() to call DebugBreak. + * exceptions.cc (try_to_debug): Ditto. + +2006-06-02 Christopher Faylor <cgf@timesys.com> + + * fhandler.cc (fhandler_base::fixup_after_exec): Declare here. + * fhandler.h (fhandler_base::fixup_after_exec): Make non-inline. + (fhandler_termios::fixup_after_fork): Delete declaration. + (fhandler_termios::fixup_after_exec): Ditto. + (fhandler_tty_common::inuse): Remove. + (fhandler_tty_common::dup): Delete declaration. + (fhandler_tty_common::fixup_after_fork): Ditto. + (fhandler_tty_slave::fixup_after_exec): Declare new function. + (fhandler_pty_master::dwProcessId): New variable. + (fhandler_pty_master::from_master): Ditto. + (fhandler_pty_master::to_master): Ditto. + (fhandler_pty_master::setup): New function. + (fhandler_pty_master::fixup_after_fork): Ditto. + (fhandler_pty_master::fixup_after_exec): Ditto. + * fhandler_termios.cc (fhandler_termios::fixup_after_exec): Delete + definition. + (fhandler_termios::fixup_after_fork): Ditto. + * fhandler_tty.cc (fhandler_tty_master::init): Use fhandler_pty_master + setup function rather than obsolete tty::common_init. Delete obsolete + inuse setting. + (fhandler_tty_slave::fhandler_tty_slave): Set inuse to NULL here. + (fhandler_tty_slave::open): Change debugging output for clarity. Check + for different things when doing a sanity check on the tty. Reflect the + fact that master_pid now is the cygwin pid rather than the windows pid. + Use "arch" rather than "archetype" for consistency. + (fhandler_tty_slave::close): Close inuse here. + (fhandler_tty_slave::dup): Remove old if 0'ed code. + (fhandler_pty_master::dup): New function. Handles pty master + archetype. + (fhandler_pty_master::fhandler_pty_master): Zero pty_master specific + fields. + (fhandler_pty_master::open): Implement using archetypes, similar to + slave. Use fhandler_pty_master setup function rather than obsolete + tty::common_init. Don't set inuse. + (fhandler_tty_common::close): Don't deal with inuse. Delete old if + 0'ed code. + (fhandler_pty_master::close): Implement using archetypes. Close + from_master and to_master. + (fhandler_tty_common::set_close_on_exec): Just set close_on_exec flag + here since everything uses archetypes now. + (fhandler_tty_common::fixup_after_fork): Delete definition. + (fhandler_tty_slave::fixup_after_exec): Define new function. + (fhandler_pty_master::setup): New function, derived from + tty::common_init. + (fhandler_pty_master::fixup_after_fork): New function. + (shared_info.h): Reset SHARED_INFO_CB to reflect new tty size. + * tty.cc (tty_list::terminate): Close individual handles from + tty_master. + (tty::master_alive): Delete. + (tty::make_pipes): Ditto. + (tty::common_init): Ditto. + * tty.h (tty::from_slave): Delete. + (tty::to_slave): Ditto. + (tty::common_init): Delete declaration. + (tty::make_pipes): Ditto. + (tty::master_pid): Define as pid_t since it is now a cygwin pid. + +2006-06-01 Christopher Faylor <cgf@timesys.com> + + * cygheap.cc (cygheap_fixup_in_child): Don't close parent handle here. + Let the caller do that. + * dcrt0.cc (child_info_spawn::handle_spawn): Close parent handle here + to allow fixup_after_exec functions to use it. + + * cygtls.cc (_cygtls::call2): Avoid calling exit thread if called with + *crt0_1 functions. + * cygtls.h (_cygtls::isinitialized): Check that we actually have a tls + before seeing if it is initialized. + * gendef (_sigfe_maybe): Ditto. + * dcrt0.cc (dll_crt0_1): Remove static, use just one argument. + * dll_init.cc (dllcrt0_info): New structure. + (dll_dllcrt0): Change into a front-end to renamed dll_dllcrt0_1 so that + we'll always be assured of having something like a tls. + (dll_dllcrt0_1): New function, basically renamed from from dll_dllcrt0. + Unconditionally call _my_tls.init_exception_handler now that we are + assured of having a tls. Change variable name from "linking" to "linked". + * winsup.h (dll_crt0_1): Declare. + (dll_dllcrt0_1): Ditto. + +2006-05-30 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::call2): Don't call ExitThread on the main thread. + +2006-05-29 Christopher Faylor <cgf@timesys.com> + + * winf.h (MAXCYGWINCMDLEN): Set down size to 30000 or suffer fork + errors. + +2006-05-28 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (child_info::proc_retry): Mask all of the bits we're + interested in, which includes bits above and below 0xc0000000. + +2006-05-27 Christopher Faylor <cgf@timesys.com> + + * dll_init.cc (dll_dllcrt0): Previous change didn't work very well with + fork. Semi-revert it but change name of variable to something that + makes better sense. + +2006-05-27 Christopher Faylor <cgf@timesys.com> + + * thread.cc (verifyable_object_isvalid): Check for NULL specifically. + +2006-05-27 Christopher Faylor <cgf@timesys.com> + + * dll_init.cc (dll_dllcrt0): Call _my_tls.init_exception_handler if + we've finished initializing (Thanks to Gary Zablackis for noticing this + problem). Just use cygwin_finished_initializing rather than defining a + separate variable. + +2006-05-25 Christopher Faylor <cgf@timesys.com> + + * debug.h (ModifyHandle): Define new macro. + (modify_handle): Declare new function. + * debug.cc (modify_handle): Define new function. + * fhandler.h (fhandler_base::fork_fixup): Change return value from void + to bool. + * fhandler.cc (fhandler_base::fork_fixup): Return true if fork fixup has + been done. + * pipe.cc (fhandler_pipe::set_close_on_exec): Set inheritance of + protected handle via ModifyHandle if DEBUGGING. + (fhandler_pipe::fixup_after_fork): Protect guard handle if fork fixup + has been done. + +2006-05-24 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::call): Call call2 using _my_tls. + (_cygtls::init_exception_handler): Always replace existing exception + handler with cygwin exception handler. + * cygtls.h (_cygtls::call2): Remove static designation. + * dcrto.cc (dll_crt0_1): Define in a way that allows calling via + _cygtls::call. + (_initialize_main_tls): Delete. + (_dll_crt0): Call dll_crt0_1 via cygtls::call. Set _main_tls here. + * external.cc (cygwin_internal): Implement CW_CYGTLS_PADSIZE. + * include/sys/cygwin.h (CW_CYGTLS_PADSIZE): Define. + * tlsoffsets.h: Regenerate. + +2006-05-24 Christopher Faylor <cgf@timesys.com> + + * configure.in: Update to newer autoconf. + (thanks to Steve Ellcey) + * configure: Regenerate. + * aclocal.m4: New file. + +2006-05-23 Lev Bishop <lev.bishop+cygwin@gmail.com> + + * fhandler.cc (readv): Remove nonsensical assert. + +2006-05-23 Christopher Faylor <cgf@timesys.com> + + * select.cc (start_thread_socket): Delay setting thread local exitsock + until we know it's correct. Return correct value on error. + +2006-05-23 Lev Bishop <lev.bishop+cygwin@gmail.com> + Christopher Faylor <cgf@timesys.com> + + * select.cc (start_thread_socket): Clean up exitsock in case of error. + Use si->exitcode consistently. + +2006-05-21 Christopher Faylor <cgf@timesys.com> + + * child_info.h (_CI_SAW_CTRL_C): New enum. + (CURR_CHILD_INFO_MAGIC): Reset. + (saw_ctrl_c): New function. + (set_saw_ctrl_c): Ditto. + * sigproc.cc (child_info::proc_retry): Return EXITCODE_OK if we get + STATUS_CONTROL_C_EXIT and we actually saw a CTRL-C. + * spawn.cc (dwExeced): Delete. + (chExeced): New variable. + (spawn_guts): Set chExeced; + * exceptions.cc (dwExeced): Delete declaration. + (chExeced): Declare. + (ctrl_c_handler): Detect if we're an exec stub process and set a flag, + if so. + + * fhandler_tty.cc (fhandler_tty_common::__release_output_mutex): Add + extra DEBUGGING test. + + * pinfo.cc: Fix comment. + +2006-05-21 Christopher Faylor <cgf@timesys.com> + + * fhandle.h (fhandler_pipe::create_guard): Revert change which + eliminated SECURITY_ATTRIBUTES argument. + * pipe.cc (fhandler_pipe::open): Duplicate guard from other process and + protect it appropriately. Eliminate unneeded writepipe_exists + temporary variable. Set inheritance appropriately. + (fhandler_pipe::set_close_on_exec): Revert change which eliminated + handling guard inheritance. + (fhandler_pipe::fixup_after_fork): Ditto. Use correct name of entity + being checked by fork_fixup. + (fhandler_pipe::fixup_after_exec): Don't bother with guard here. + (fhandler_pipe::dup): Cosmetic changes and revert creation of + writepipe_exists as noninheritable. + (fhandler_pipe::create): Revert change which eliminated + SECURITY_ATTRIBUTES argument. Revert change which always made + writepipe_exists noninheritable. + +2006-05-21 Christopher Faylor <cgf@timesys.com> + + * debug.cc (add_handle): Print handle value when collision detected. + * dtable.cc (dtable::stdio_init): Cosmetic change. + * fhandler.h (fhandler_base::create_read_state): Protect handle. + (fhandler_pipe::create_guard): Ditto. Always mark the handle as + inheritable. + (fhandler_pipe::is_slow): Return boolean value rather than numeric 1. + * pipe.cc (fhandler_pipe::fhandler_pipe): Always flag that we need fork + fixup. + (fhandler_pipe::open): Don't pass security attributes to create_guard. + (fhandler_pipe::set_close_on_exec): Don't handle guard here. + (fhandler_pipe::close): Accommodate now-protected guard handle. + (fhandler_pipe::fixup_in_child): Don't protect read_state here. + (fhandler_pipe::fixup_after_exec): Close guard handle if close_on_exec. + (fhandler_pipe::fixup_after_fork): Don't bother with guard here. + (fhandler_pipe::dup): Don't set res to non-error prematurely. Use + boolean values where appropriate. Protect guard and read_state. + (fhandler_pipe::create): Don't call need_fork_fixup since it is now the + default. Don't protect read_state or guard. + + * pipe.cc (fhandler_base::ready_for_read): Use bool values for "avail". + + * spawn.cc (spawn_guts): Set cygheap->pid_handle as inheritable when + protecting. + +2006-05-15 Lev Bishop <lev.bishop+cygwin@gmail.com> + Christopher Faylor <cgf@timesys.com> + + * select.cc (fhandler_pipe::ready_for_read): Actually get the guard + mutex for blocking reads. + +2006-05-20 Christopher Faylor <cgf@timesys.com> + + * fhandler_tty.cc (fhandler_tty::close): Remove problematic hExeced guard. + +2006-05-20 Christopher Faylor <cgf@timesys.com> + + * fhandler_tty.cc (fhandler_tty_slave::open): Reinstate call to + need_invisible on first pty open. + +2006-05-18 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (fhandler_console::need_invisible): Allocate an + invisible window station when ctty != TTY_CONSOLE. + +2006-05-16 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::remove): Don't test for initialization since + this function will always be called when _my_tls is initialized. + * init.cc (dll_entry): Don't attempt to remove tls info if _my_tls is + obviously not even available. + +2006-05-15 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (no_signals_available): Detect hwait_sig == + INVALID_HANDLE_VALUE. + (wait_sig): Set hwait_sig to INVALID_HANDLE_VALUE on __SIGEXIT. + +2006-05-15 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::init_thread): Zero entire _my_tls structure and + no more. + * cygtls.h (_my_tls::padding): Delete. + (CYGTLS_PADSIZE): Redefine concept of padding to mean padding at the + end of the stack. + * dcrt0.cc (initialize_main_tls): Change return to void. + * gentls_offsets: Treat const specially, too. Keep going after a '}' + is found. Change negative offset calculation to use CYGTLS_PADSIZE. + * init.cc (_my_oldfunc): New variable. + (threadfunc_fe): Use stored tls value for oldfunc rather than blindly + writing to the stack. + (munge_threadfunc): Set oldfunc in tls. + (dll_entry): Initialize tls allocation. + * tlsoffsets.h: Regenerate. + +2006-05-13 Christopher Faylor <cgf@timesys.com> + + * ntdll.h (STATUS_INVALID_INFO_CLASS): Conditionalize. + +2006-05-10 Brian Dessent <brian@dessent.net> + + * Makefile.in (clean): Also delete *.dbg. + +2006-05-08 Christian Franke <Christian.Franke@t-online.de> + + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Fix typo which + caused test for ".." to be skipped. + +2006-05-02 Christopher Faylor <cgf@timesys.com> + + * external.cc (cygwin_internal): Set errno on failure. + +2006-04-27 Corinna Vinschen <corinna@vinschen.de> + + * pipe.cc (DEFAULT_PIPEBUFSIZE): Raise to 64K. + +2006-04-26 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (fhandler_base): Change fstat_helper prototype + to take file size and inode number as 64 bit values. + * fhandler_disk_file.cc (FS_IS_SAMBA): Move to path.cc + (FS_IS_SAMBA_WITH_QUOTA): Ditto. + (path_conv::hasgood_inode): Delete. + (path_conv::is_samba): Delete. + (path_conv::isgood_inode): Centralized function to recognize + a good inode number. + (fhandler_base::fstat_by_handle): Constify fvi_size and fai_size. + Accomodate argument change in fstat_helper. + (fhandler_base::fstat_by_name): Ditto. + (fhandler_base::fstat_helper): Accomodate argument change. Call + path_conv::isgood_inode to recognize good inodes. + (fhandler_disk_file::opendir): Explain Samba weirdness here. + Call path_conv::fs_is_samba instead of path_conv::is_samba. + (fhandler_disk_file::readdir): Add STATUS_INVALID_INFO_CLASS + as valid return code from NtQueryDirectoryFile to indicate that + FileIdBothDirectoryInformation is not supported. + Call path_conv::isgood_inode to recognize good inodes. + * ntdll.h (STATUS_INVALID_INFO_CLASS): Define. + * path.cc (fs_info::update): Rework file system recognition + and set appropriate flags. + * path.h (struct fs_info): Add is_ntfs, is_samba and is_nfs flags. + Constify pure read accessors. + +2006-04-24 Christopher Faylor <cgf@timesys.com> + + * environ.cc (getearly): Force correct dereference order when + inspecting environ table. + +2006-04-24 Corinna Vinschen <corinna@vinschen.de> + + * select.cc (thread_pipe): Raise sleep time only every 8th iteration. + (thread_mailslot): Ditto. + +2006-04-23 Corinna Vinschen <corinna@vinschen.de> + Christopher Faylor <cgf@timesys.com> + + * select.cc (thread_pipe): Raise sleep time dynamically to speed up + select on pipes when copying lots of data. + (thread_mailslot): Ditto for mailslots. + +2006-04-22 Christopher Faylor <cgf@timesys.com> + + * signal.cc (abort): On second thought, just set incyg once. + +2006-04-22 Christopher Faylor <cgf@timesys.com> + + * signal.cc (abort): Set incyg manually to help get a reliable gdb + stack trace. + * cygwin.din (abort): Make NOSIGFE. + +2006-04-21 Pierre Humblet Pierre.Humblet@ieee.org + Christopher Faylor <cgf@timesys.com> + + * environ.cc (getearly): Use GetEnvironmentVariable and cmalloc instead + of GetEnvironmentStrings. + (environ_init): Revert rawenv stuff. + +2006-04-21 Christopher Faylor <cgf@timesys.com> + + * environ.cc (rawenv): Make this variable a file-scope static. + (getearly): Rename 's' variable to 'len' since 's' is used fairly + consistently throughout cygwin as a string variable. Remove rawenv + declaration. Perform other minor cleanups. + (environ_init): Remove rawenv declaration. Only set rawenv to + GetEnvironmentStrings() if it has not already been set. Properly free + rawenv in all cases. + +2006-04-21 Christopher Faylor <cgf@timesys.com> + + * tty.h (tty::hwnd): Move to tty_min. + (tty::gethwnd): Ditto. + (tty::sethwnd): Ditto. + (tty_min::hwnd): Receive variable from tty class. + (tty_min::gethwnd): Receive function from tty classs. + (tty_min::sethwnd): Ditto. + * dtable.cc (dtable::stdio_init): Only call init_console_handler when + we actually own the console. + * fhandler_console.cc (fhandler_console::get_tty_stuff): Set tty's hwnd + to non-zero value. + * fhandler_termios.cc (fhandler_termios::tcsetpgrp): Semi-reinstate + handling of console when pgrp is set. + +2006-04-21 Pierre Humblet <Pierre.Humblet@ieee.org> + Corinna Vinschen <corinna@vinschen.de> + + * environ.cc (getearly): New function. + (findenv_func): New function pointer, predefined to getearly. + (getenv): Call findenv function over the findenv_func pointer. + (environ_init): Change findenv_func pointer to my_findenv after Cygwin + environment is initialized. + +2006-04-21 Lars Munch <lars@segv.dk> + + * include/asm/byteorder.h (__ntohl): Fix the missing uint32_t. + +2006-04-21 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_socket.cc (fhandler_socket::wait): Reorder setting + WSAError to avoid spurious errors with WSAError set to 0. + +2006-04-21 Corinna Vinschen <corinna@vinschen.de> + + * include/asm/byteorder.h: Include stdint.h. Per standard, change + datatypes in ntohX and htonX functions to uintXX_t types. + +2006-04-18 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (ctrl_c_handler): Only exit TRUE on CTRL_LOGOFF_EVENT + when we have actually handled the event. + +2006-04-17 Eric Blake <ebb9@byu.net> + + * mktemp.cc (_gettemp): Open temp files in binary mode. + +2006-04-14 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Use UINT32_MAX + instead of UINT_MAX. + +2006-04-14 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (path_conv::hasgood_inode): Make inline. + Drop remote fs handling entirely since unreliable inode numbers + are now recognized differently. + (path_conv::is_samba): Make inline. + (fhandler_disk_file::opendir): Reformat comment. + (fhandler_base::fstat_helper): Special case remote file systems + returning (unreliable) 32 bit inode numbers. + (fhandler_disk_file::readdir): Ditto. + * fhandler_netdrive.cc (fhandler_netdrive::readdir): Ditto. + +2006-04-13 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (spawn_guts): Move ch.set() call back to where it was + supposed to be. + +2006-04-13 Corinna Vinschen <corinna@vinschen.de> + + * sysconf.cc (sysconf): Add _SC_THREADS, _SC_THREAD_ATTR_STACKSIZE, + _SC_THREAD_PRIORITY_SCHEDULING, _SC_THREAD_PROCESS_SHARED, + _SC_THREAD_SAFE_FUNCTIONS, _SC_TIMERS handling. + +2006-04-12 Corinna Vinschen <corinna@vinschen.de> + Christopher Faylor <cgf@timesys.com> + + * spawn.cc (spawn_guts): Revert patch which treated derived cygwin + programs differently from those which are mounted with -X. Pass extra + argument to linebuf::fromargv. + * winf.h (MAXCYGWINCMDLEN): New define. + (linebuf::finish): Add a new argument denoting when command line + overflow is ok. + (linebuf::fromargv): Ditto. + * winf.cc (linebuf::finish): Implement above change. + (linebuf::fromargv): Ditto. + +2006-04-11 Christopher Faylor <cgf@timesys.com> + + * Makefile.in (DLL_OFILES): Add winf.o. + * spawn.cc: Move command line handling stuff into winf.cc. + * winf.h: New file. + * winf.cc: New file. + +2006-04-05 Christopher Faylor <cgf@timesys.com> + + * fhandler_socket.cc: Move iptypes.h include after winsock2 since it + now relies on it. + * net.cc: Ditto. + +2006-04-05 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Move user_data->{resourcelocks,threadinterface} + initialization here from dll_crt0_1. + (dll_crt0_1): See above. + +2006-04-04 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (fdsock): Raise default SO_RCVBUF/SO_SNDBUF buffer sizes to + the same values as on Linux. + +2006-04-03 Christopher Faylor <cgf@timesys.com> + + * child_info.h (CURR_CHILD_INFO_MAGIC): Update. + (child_info_fork::alloc_stack): Move into this class. + (child_info_fork::alloc_stack_hard_way): Ditto. + * dcrt0.cc (child_info_fork::alloc_stack): Ditto. + (child_info_fork::alloc_stack_hard_way): Ditto. + (_dll_crt0): Reference alloc_stack via fork_info. + +2006-04-03 Corinna Vinschen <corinna@vinschen.de> + + * spawn.cc (linebuf::finish): Drop argument. Don't check command line + length. + (spawn_guts): Remove wascygexec. Check real_path.iscygexec instead. + Accommodate change to linebuf::finish. + +2006-04-03 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (sm): Delete. + (alloc_stack_hard_way): Figure out where the stack lives here rather + than relying on previously filled out information which has been + invalid since 1.5.19. + +2006-03-31 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (FS_IS_SAMBA_WITH_QUOTA): New define. + (path_conv::hasgood_inode): Recognize Samba with quota support + compiled in. + (path_conv::is_samba): Ditto. Fix comment to include Samba version + numbers for later reference. + +2006-03-30 Corinna Vinschen <corinna@vinschen.de> + + * security.h (sec_user_nih): Make sid1 argument mandatory. + (sec_user): Ditto. + +2006-03-29 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (wait_for_sigthread): Use the current user sid when + setting up the signal pipe rather than relying on (eventually) the + effective sid. + +2006-03-29 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (child_info_fork::handle_fork): Set uid/gid in myself so + that it can be used by subsequent startup functions. + (dll_crt0_0): Issue a warning if DuplicateTokenEx fails and DEBUGGING. + (dll_crt0_1): Move user_data->{resourcelocks,threadinterface} + initialization here from dll_crt0_0. + * fork.cc (frok::child): Tell wait_for_sigthread that this is fork. + (frok::parent): Only initialize start_time once. Tighten time when + we're "deimpersonated". + * sigproc.cc (signal_fixup_after_exec): Rework (futiley) sa_buf stuff. + Add debugging output. + (wait_for_sigthread): Accept an argument which illustrates whether we + are forked or not. + (wait_sig): Avoid using myself pointer. + * winsup.h ((wait_for_sigthread): Reflect change to argument. + +2006-03-26 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (spawn_guts): Close handles if we know that we will not be + seeing a sync event from the child. + +2006-03-26 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (wait_sig): Move myself manipulation... + (wait_for_sigthread): ...to here. + +2006-03-24 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_floppy.cc: Include ntdef.h and ntdll.h. + (fhandler_dev_floppy::get_drive_info): Rearrange so that now + NtQueryVolumeInformationFile is called on drives which don't support + IOCTL_DISK_GET_DRIVE_GEOMETRY. + * ntdll.h (struct _FILE_FS_SIZE_INFORMATION): Add. + (enum _FSINFOCLASS): Add missing values. + +2006-03-23 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (fhandler_console::fixup_after_fork_exec): Make + error message more explicit. + * pinfo.cc (_pinfo::commune_request): Don't lock process unless we're + looking for fifos. + +2006-03-23 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (child_info_spawn::handle_spawn): Don't initialize the + console handler here. + * dtable.cc (dtable::stdio_init): Initialize console handler here. + +2006-03-23 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (sigalloc): Don't set SA_RESTART here. + * signal.cc (_SA_NORESTART): New flag. + (sigaction_worker): New function, derived from sigaction. Don't set + internal flags unless called internally. + (sigaction): Use sigaction_worker. + (signal): Honor new _SA_NORESTART flag. + (siginterrupt): Set _SA_NORESTART flag appropriately. Use + sigaction_worker to set flags. + * include/cygwin/signal.h: Define _SA_INTERNAL_MASK here. + +2006-03-22 Corinna Vinschen <corinna@vinschen.de> + + * thread.cc (pthread_mutex::is_good_initializer_or_bad_object): Delete. + (pthread_cond::is_good_initializer_or_bad_object): Delete. + (pthread_rwlock::is_good_initializer_or_bad_object): Delete. + (pthread_cond::init): Remove disabled code. Guard assignment to + object to initialize against access violation. + (pthread_rwlock::init): Ditto. + (pthread_mutex::init): Ditto. + +2006-03-22 Eric Blake <ebb9@byu.net> + + * fhandler.cc (fcntl): Print flags in hex. + +2006-03-22 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Semi-revert 2006-03-14 change which moved + pinfo_init and uinfo_init here. + (dll_crt0_1): Ditto. + (__dll_crt0): Ditto. Don't call update_envptrs here. + (dll_crt0_1): Ditto. Move wait_for_sigthread call here from dll_crt0_0. + * environ.cc (environ_init): Call it here instead. + * sigproc.cc (my_readsig): New static variable. + (wait_for_sigthread): Set up read pipe here since we are assured that + we have the proper privileges when this is called. + (talktome): Eliminate second argument since it is available as a global + now. + (wait_sig): Reflect use of my_readsig. + +2006-03-22 Corinna Vinschen <corinna@vinschen.de> + + * thread.cc (pthread_cond::init): Disable validity test of object + to initialize since test of uninitialized content is unreliable. + (pthread_rwlock::init): Ditto. + (pthread_mutex::init): Ditto. + +2006-03-21 Christopher Faylor <cgf@timesys.com> + + * signal.cc (signal): Don't set SA_RESTART here. + (siginterrupt): White space. + * sigproc.cc (sigalloc): Set SA_RESTART here, on initialization. + +2006-03-21 Christopher Faylor <cgf@timesys.com> + + * child_info.h (child_status): Fix typo which made it impossible to set + iscygwin. + (child_info::isstraced): Booleanize. + (child_info::iscygwin): Ditto. + * sigproc.cc (child_info::child_info): Minor cleanup of flag setting. + * spawn.cc (spawn_guts): Only close_all_files when we know the process + has started successfully. + + * exceptions.cc (init_console_handler): Fix indentation. + +2006-03-20 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Call SetErrorMode earlier. + * pinfo.cc (_pinfo::dup_proc_pipe): Reset wr_proc_pipe on failure. + Return previous pipe handle. + * pinfo.h (_pinfo::dup_proc_pipe): Reflect change to return value. + * spawn.cc (spawn_guts): Restore previous proc pipe on retry or if + process exits before synchronization. + +2006-03-20 Christopher Faylor <cgf@timesys.com> + + * child_info.h (child_status): New enum. + (child_info::flag): Rename from 'straced'. + (child_info::isstraced): New function. + (child_info::iscygwin): Ditto. + (child_info_fork::handle_fork): Reparmize. + (child_info_fork::handle_failure): Ditto. + (child_info_spawn::handle_spawn): New function. + * dcrt0.cc (get_cygwin_startup_info): Use isstraced method. + (child_info_spawn::handle_spawn): Define new function from code + previously in dll_crt0_0. + (dll_crt0_0): Move spawn stuff into handle_spawn. Only call + init_console_handler for fork case. + * sigproc.cc (child_info::child_info): Set flag appropriately. + (child_info::proc_retry): Treat exit code as "funny" if it's a cygwin + process. + * spawn.cc (spawn_guts): Remove commented out flag setting. + +2006-03-19 Christopher Faylor <cgf@timesys.com> + + * pinfo.cc (commune_process): Fix randomly invalid pointer which caused + fifos to work incorrectly. + +2006-03-19 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Oops. We need to bother with setting + init_console_handler in the fork/exec case. + +2006-03-19 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Don't bother with setting init_console_handler + here since it will be set later when we discover if we have a ctty or + not. + * exceptions.cc (init_console_handler): Properly remove NULL handler. + +2006-03-18 Christopher Faylor <cgf@timesys.com> + + * pinfo.h (EXITCODE_OK): Define new constant. + * sigproc.cc (child_info::sync): Return EXITCODE_OK if entering with + exit_code == 0. + (sig_send): Don't complain if sending signals while blocked if the + sender isn't in the main thread. + +2006-03-18 Christopher Faylor <cgf@timesys.com> + + * child_info.h (CURR_CHILD_INFO_MAGIC): Regenerate. + (child_info::retry): Move here from fork subclass. + (child_info::exit_code): New field. + (child_info::retry_count): Max retry count for process start. + (child_info::proc_retry): Declare new function. + (child_info_fork::retry): Move to parent. + (child_info_fork::fork_retry): Ditto. + * dcrt0.cc (child_info::fork_retry): Rename and move. + (child_info_fork::handle_failure): Move. + (dll_crt0_0): Initialize console handler based on whether we have a + controlling tty or not. Avoid nonsensical check for fork where it can + never occur. + * environ.cc (set_proc_retry): Rename from set_fork_retry. Set + retry_count in child_info. + (parse_thing): Reflect above change. + * exceptions.cc (dummy_ctrl_c_handler): Remove unused variable name. + (ctrl_c_handler): Always return TRUE for the annoying + CTRL_LOGOFF_EVENT. + * fhandler_termios.cc (fhandler_termios::tcsetpgrp): Remove call to + init_console_handler. + * fhandler_tty.cc (fhandler_tty_slave::open): Just call + mange_console_count here and let it decide what to do with initializing + console control handling. + * fork.cc (fork_retry): Remove definition. + (frok::parent): Define static errbuf and use in error messages (not + thread safe yet). Close pi.hThread as soon as possible. Protect + pi.hProcess as soon as possible. Don't set retry_count. That happens + automatically in the constructor now. Accommodate name change from + fork_retry to proc_retry. + * init.cc (dll_entry): Turn off ctrl-c handling early until we know how + it is supposed to be handled. + * pinfo.cc (_pinfo::dup_proc_pipe): Remember original proc pipe value + for failure error message. Tweak debug message slightly. + * sigproc.cc (child_info::retry_count): Define. + (child_info::child_info): Initialize retry count. + (child_info::sync): Set exit code if process dies before + synchronization. + (child_info::proc_retry): Rename from child_info_fork::fork_retry. Use + previously derived exit code. Be more defensive about what is + classified as an error exit. + (child_info_fork::handle_failure): Move here from dcrt0.cc. + * spawn.cc (spawn_guts): Maintain error mode when starting new process + to avoid annoying pop ups. Move deimpersonate call within new loop. + Move envblock freeing to end. Loop if process dies prematurely with + bad exit code. + * syscalls.cc (setpgid): Remove hopefully unneeded call to + init_console_handler. + +2006-03-15 Christopher Faylor <cgf@timesys.com> + + * cygheap.cc (init_cygheap::manage_console_count): Turn console control + handler on/off depending on whether we have allocated a console or not. + * dcrt0.cc (child_info_fork::fork_retry): Add more potential retry + statuses. + (dll_crt0_0): Turn on/off console control depending on whether we have + a controlling tty or not. + * exceptions.cc (init_console_handler): Change BOOL to bool. + * fhandler_console.cc (fhandler_console::need_invisible): Cosmetic + change. + * winsup.h (init_console_handler): Reflect argument type change. + + * wincap.h (supports_setconsolectrlhandler_null): Remove duplicate + capability throughout. + * wincap.cc: Ditto. + +2006-03-14 Christopher Faylor <cgf@timesys.com> + + * child_info.h (child_info_fork::fork_retry): Declare new function. + * dcrt0.cc (child_info_fork::fork_retry): Define new function. + * fork.cc (frok::parent): Move retry decision into + child_info_fork::fork_retry and honor what it tells us to do. + * sigproc.cc (sig_send): Unhold signals on __SIGEXIT. + +2006-03-14 Christopher Faylor <cgf@timesys.com> + + * fork.cc (frok::parent): Improve error message. + +2006-03-14 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (main_environ): Initialize to &__cygwin_environment. + (dll_crt0_1): Move resourcelocks, thread interface, pinfo_init, and + uinfo_init... + (dll_crt0_0): ...to here. + (_dll_crt0): Call update_envptrs here after setting main_environ. + * environ.cc (environ_init): Eliminate initted variable. Don't call + update_envptrs here. + * sigproc.cc (wait_sig): Use my_sendsig when calling CreatePipe to + avoid a dereference. + +2006-03-13 Christopher Faylor <cgf@timesys.com> + + * child_info.h (child_info_fork::handle_failure): Declare new function. + (child_info_fork::retry): New field. + * dcrt0.cc (__api_fatal_exit_val): Define. + (child_info_fork::handle_failure): Define new function. + (__api_fatal): Exit using __api_fatal_exit_val value. + * environ.cc (set_fork_retry): Set fork_retry based on CYGWIN + environment variable. + (parse_thing): Add "fork_retry" setting. + * fork.cc (fork_retry): Define. + (frok::parent): Reorganize to allow retry of failed child creation if + child signalled that it was ok to do so. + * heap.cc (heap_init): Signal parent via handle_failure when + VirtualAlloc fails. + * pinfo.h (EXITCODE_RETRY): Declare. + * sigproc.cc (child_info::sync): Properly exit with failure condition + if called for fork and didn't see subproc_ready. + * spawn.cc (spawn_guts): Use windows pid as first argument. + * winsup.h: Remove obsolete NEW_MACRO_VARARGS define. + (__api_fatal_exit_val): Declare. + (set_api_fatal_return): Define. + (in_dllentry): Declare. + * exceptions.cc (inside_kernel): Remove unneeded in_dllentry + declaration. + +2006-03-13 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (dll_crt0_0): Reorganize so that sigproc_init is called a + little later. Add a comment. + * fork.cc (resume_child): Make void. + (frok::parent): Only zero pi when necessary. Explicitly zero si. Set + this_errno when child_copy fails. Accommodate change to resume_child. + * sigproc.cc (sigalloc): Move global_sigs initialization here. + (sigproc_init): Move global_sigs. + (sig_send): Just check for flush signals once. + + * wincap.h: Define supports_setconsolectrlhandler_null throughout. + * wincap.cc: Ditto. + +2006-03-13 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (LoadDLLfuncNt): New define to wrap NT native functions. + Use for NT native functions throughout. + * dtable.cc (handle_to_fn): Treat return value of NtQueryObject as + NTSTATUS value. + +2006-03-12 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::remove): Reset initialized flag right away if we + were previously initialized. + * cygtls.h (_cygtls::initialized): Move nearer to the end to catch + situation when Windows 98 mysteriously changes parts of _my_tls when + thread is detaching. + * gendef (__sigfe_maybe): Simplify slightly. + * tlsoffsets.h: Regenerate. + +2006-03-12 Christopher Faylor <cgf@timesys.com> + + * cygtls.h (CYGTLS_INITIALIZED): Change to a little more unlikely value. + (CYGTLSMAGIC): Delete. + * dcrt0.cc (dll_crt0_0): Call sigproc_init during init startup. + (_dll_crt0): Don't worry about sync_startup. Just wait for sigthread here. + * dll_init.cc (cygwin_detach_dll): Only pick up tls version of retaddr + if we have a valid tls. + * fork.cc (frok::child): Remove sigproc_init initialization since it + happens much earlier now. + * gendef: Recognize SIGFE_MAYBE. + (fefunc): Generate calls to _sigfe_maybe, if appropriate. + (_sigfe_maybe): New function. + * init.cc (search_for): Always initialize search_for, even on fork. + (calibration_thread): Delete. + (calibration_id): Delete. + (prime_threads): Delete. + (munge_threadfunc): Remove calibration_thread special case. Avoid + calling thread function if we haven't yet hit the "search_for" thread. + (dll_entry): Remove prime_threads call. Only call munge_threadfunc + when hwait_sig is active. Ditto. for _my_tls.remove (); + * sigproc.cc (hwait_sig): Make global. + (sigproc_init): Don't bother with sync_startup. + (sig_send): Treat flush as a no-op when signals are held. + (wait_sig): Cause signals to be held after fork. + +2006-03-09 Corinna Vinschen <corinna@vinschen.de> + + * syscalls.cc (rename): Move existance check for oldpath further up + to the start of the function. Avoid another case of a name collision + if oldpath is a shortcut and a file or directory newpath already exists. + +2006-03-09 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (NtClose): Define. + (NtOpenDirectoryObject): Define. + (NtQueryDirectoryObject): Define. + * fhandler_proc.cc: Include ctype.h and wchar.h. + (format_proc_partitions): Revamp loop over existing harddisks by + scanning the NT native \Device object directory and looking for + Harddisk entries. + * ntdll.h: Rearrange system call declarations alphabetically. + (DIRECTORY_QUERY): Define. + (struct _DIRECTORY_BASIC_INFORMATION): Define. + (NtOpenDirectoryObject): Declare. + (NtQueryDirectoryObject): Declare. + +2006-03-08 Christopher Faylor <cgf@timesys.com> + + * cygtls.h (_cygtls::retaddr): New method. + * dll_init.cc (cygwin_detach_dll): Use new tls method to find return + address since this function is now signal guarded. + (update_envptrs): Remove unneeded braces. + * syscalls.cc (statvfs): Coerce full_path to avoid a gcc warning. + +2006-03-08 Corinna Vinschen <corinna@vinschen.de> + + * syscalls.cc (statvfs): Simplify path name expression. + +2006-03-08 Corinna Vinschen <corinna@vinschen.de> + + * syscalls.cc: Include winioctl.h. + (statvfs): Request correct volume size using DeviceIoControl if + quotas are enforced on the file system. + +2006-03-03 Corinna Vinschen <corinna@vinschen.de> + + * dir.cc (opendir): Fix indentation. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Move storing + fhandler in file descriptor table to some point very late in function + to avoid double free'ing. Add comment to explain what happens. + Add label free_mounts and don't forget to delete __DIR_mounts structure + if NtOpenFile fails. + +2006-03-02 Corinna Vinschen <corinna@vinschen.de> + + * syscalls.cc (chroot): Disallow chroot into special directories. + Return EPERM instead. + +2006-03-02 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (__DIR_mounts::check_missing_mount): Check + cygdrive string length for those who have cygdrive mapped to "/". + +2006-03-01 Corinna Vinschen <corinna@vinschen.de> + + * sec_helper.cc (set_cygwin_privileges): Request SE_BACKUP_NAME + privileges. + +2006-03-01 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_proc.cc (fhandler_proc::fstat): Always return fixed link + count of 1 for /proc directory instead of incorrect PROC_LINK_COUNT. + +2006-03-01 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (enum dirent_states): Remove dirent_saw_cygdrive, + dirent_saw_dev and dirent_saw_proc. + (fhandler_cygdrive::open): Declare. + (fhandler_cygdrive::close): Declare. + * fhandler_disk_file.cc (class __DIR_mounts): Move to beginning of file. + (__DIR_mounts::check_mount): New parameter to indicate if inode number + is needed in calling function or not. Add /proc and /cygdrive handling. + (__DIR_mounts::check_missing_mount): Ditto. + (path_conv::ndisk_links): Use __DIR_mounts class to create correct + hardlink count for directories with mount points in them. + (fhandler_disk_file::readdir_helper): Remove /dev, /proc and /cygdrive + handling. + (fhandler_cygdrive::open): New method. + (fhandler_cygdrive::close): New method. + (fhandler_cygdrive::fstat): Always return fixed inode number 2 and + fixed link count of 1. Drop call to set_drives. + (fhandler_cygdrive::opendir): Drop call to get_namehash. + (fhandler_cygdrive::readdir): Handle "." entry to return fixed inode + number 2. + +2006-03-01 Christopher Faylor <cgf@timesys.com> + + * cygwin.din: Fix some erroneous SIGFE/NOSIGFE settings. + +2006-03-01 Christopher Faylor <cgf@timesys.com> + + * cygthread.cc (cygthread::callfunc): Revert below change. Make ev a + manual reset event again. so that it will be reset by WaitFor*Object + as appropriate. + (cygthread::stub): Ditto. + (cygthread::terminate_thread): Reset ev if it was found to have been + set. + +2006-03-01 Christopher Faylor <cgf@timesys.com> + + * analyze_sigfe: New script. + * dllfixdbg: Add copyright. + * gendef: Ditto. + * gendevices: Ditto. + * gentls_offsets: Ditto. + +2006-03-01 Christopher Faylor <cgf@timesys.com> + + * cygthread.cc (cygthread::callfunc): Create ev as an auto-reset event + so that it will be reset by WaitFor*Object as appropriate. + (cygthread::stub): Ditto. + (cygthread::terminate_thread): Remove forced setting of thread + termination. + +2006-03-01 Corinna Vinschen <corinna@vinschen.de> + + * include/sys/dirent.h (struct __DIR): Rename __d_unused to + __d_internal. + * fhandler_disk_file.cc (struct __DIR_cache): Remove useless "typedef". + (d_dirname): Remove useless "struct". + (d_cachepos): Ditto. + (d_cache): Ditto. + (class __DIR_mounts): New class, implementing mount point tracking + for readdir. + (d_mounts): New macro for easy access to __DIR_mounts structure. + (fhandler_disk_file::opendir): Allocate __DIR_mounts structure and + let __d_internal element of dir point to it. + (fhandler_disk_file::readdir_helper): Add mount points in the current + directory, which don't have a real directory backing them. + Don't generate an inode number for /dev. Add comment, why. + (fhandler_disk_file::readdir): Move filling fname to an earlier point. + Check if current entry is a mount point and evaluate correct inode + number for it. + (fhandler_disk_file::readdir_9x): Ditto. + (fhandler_disk_file::rewinddir): Set all mount points in this directory + to "not found" so that they are listed again after calling rewinddir(). + (fhandler_disk_file::closedir): Deallocate __DIR_mounts structure. + * path.cc (mount_info::get_mounts_here): New method to evaluate a list + of mount points in a given parent directory. + * shared_info.h (class mount_info): Declare get_mounts_here. + +2006-02-28 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Use iscygdrive + instead of isspecial. + * path.h (path_conv::iscygdrive): New method. + +2006-02-28 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (_cygtls::interrupt_now): Remove "inside cygwin" check + since some cygwin functions are meant to be interrupted. + +2006-02-28 Corinna Vinschen <corinna@vinschen.de> + + * cygwin.din: Export __isinff, __isinfd, __isnanf, __isnand. + * include/cygwin/version.h: Bump API minor number to 155. + +2006-02-28 Corinna Vinschen <corinna@vinschen.de> + + * dir.cc (readdir_worker): Use slash as path separator when evaluating + namehash for paths below /proc. + * fhandler_netdrive.cc (fhandler_netdrive::readdir): Use expensive + inode number evaluation on share names. + +2006-02-27 Christopher Faylor <cgf@timesys.com> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Only set + d_cachepos under NT or suffer memory corruption. + (fhandler_disk_file::readdir_helper): Avoid else with a return. Just + calculate extension location once when doing symlink checks. + (fhandler_disk_file::readdir): Make debug output more useful. + (fhandler_disk_file::readdir_9x): Ditto. Eliminate redundant variable. + +2006-02-27 Christopher Faylor <cgf@timesys.com> + + * include/sys/termios.h (cfsetispeed): Just define as a function rather + than resorting to a macro. + (cfsetospeed): Ditto. + +2006-02-27 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc: Fix a comment. + +2006-02-27 Christopher Faylor <cgf@timesys.com> + + * cygthread.cc (cygthread::release): Add a comment. + +2006-02-27 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_netdrive.cc (fhandler_netdrive::fstat): Create unambiguous + inode number. + (fhandler_netdrive::readdir): Ditto. + +2006-02-24 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (sigheld): Define new variable. + (sig_dispatch_pending): Don't check sigq since that's racy. + (sig_send): Set sigheld flag if __SIGHOLD is specified, reset it if + __SIGNOHOLD is specified. Ignore flush signals if we're holding + signals. + +2006-02-23 Christopher Faylor <cgf@timesys.com> + + * cygwin.din (_exit): Use signal front end. + (exit): Ditto. + +2006-02-23 Christopher Faylor <cgf@timesys.com> + + * winsup.h (cygwin_hmodule): Declare. + * exceptions.cc (inside_kernel): Reverse return values to reflect + function name. Return true if we're in cygwin1.dll or if we're + executing in dll_entry. + (_cygtls::interrupt_now): Reflect reversal of inside_kernel return + value. + * hookapi.cc (cygwin_hmodule): Remove declaration. + * init.cc (dll_entry): Use in_dllentry global to record that we are + executing in dllentry. + +2006-02-22 Corinna Vinschen <corinna@vinschen.de> + + * exceptions.cc (_cygtls::interrupt_now): Reorder conditional + to call inside_kernel only if this isn't locked. + +2006-02-22 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.cc (fhandler_base::open): Add FILE_READ_ATTRIBUTES to + access flags in case of query_read_control case, add FILE_READ_DATA + in case of query_stat_control. + +2006-02-20 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (av::fixup): Check for .bat and friends specifically now + since these extensions are no longer automatically detected. + +2006-02-19 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (stackdump): Avoid dumping more than once. + +2006-02-19 Christopher Faylor <cgf@timesys.com> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Use NtOpenFile + to open the directory. + (fhandler_disk_file::readdir): Use NT_SUCCESS to determine if status + represents success. + +2006-02-19 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Drop generating + path_conv for root. + +2006-02-18 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (FS_IS_SAMBA): Move out of + path_conv::hasgood_inode. + (path_conv::is_samba): New method. + (fhandler_base::fstat_by_handle): Don't even try to use + FileIdBothDirectoryInformation on Samba. + * path.h (class path_conv): Declare is_samba method. + +2006-02-17 Christopher Faylor <cgf@timesys.com> + + * path.cc (conv_path_list): Eat empty paths when converting to POSIX. + (cygwin_conv_to_win32_path): Deal with Cygwin's necessity of adding a + '/' to the end of a path ending in '.'. + +2006-02-16 Corinna Vinschen <corinna@vinschen.de> + + * cygwin.din: Export sigignore and sigset. + * exceptions.cc (sigset): New function. + (sigignore): New function. + * include/cygwin/signal.h (SIG_HOLD): Define. + (sigignore): Declare. + (sigset): Declare. + * include/cygwin/version.h: Bump API minor number to 154. + +2006-02-13 Igor Peshansky <pechtcha@cs.nyu.edu> + + * include/mntent.h: Add missing #include. + +2006-02-13 Igor Peshansky <pechtcha@cs.nyu.edu> + + * gentls_offsets: Fix typo in error message. + +2006-02-10 Christopher Faylor <cgf@timesys.com> + + * fhandler_process.cc (format_process_stat): Use cygwin-derived start + time even on NT since it is the logical start time of the "process". + * pinfo.cc (set_myself): Don't set start time when it should have + already been set previously. + +2006-02-10 Brian Ford <Brian.Ford@FlightSafety.com> + + * times.cc (clock_getres): Use correct conversion from milliseconds to + seconds/nanoseconds. + (clock_setres): Use correct conversion to nanoseconds. + +2006-02-10 Christopher Faylor <cgf@timesys.com> + + * external.cc (sync_winenv): Rename from "setup_winenv". Use same + mechanism as spawn to determine environment variables which should be + converted back to windows form. + (cygwin_internal): Reflect setup_winenv -> sync_winenv name change. + * include/sys/cygwin.h: Ditto. + +2006-02-09 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Only set + the dirent_get_d_ino flag on filesystems having useful File IDs. + Add comment explaining why. + +2006-02-07 Corinna Vinschen <corinna@vinschen.de> + + * dtable.cc (handle_to_fn): Accommodate new argument order in call to + sys_wcstombs. + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Call sys_wcstombs + instead of just wcstombs to accommodate OEM codepages. + * miscfuncs.cc (sys_wcstombs): Split len argument in source and target + length. Always 0-terminate result in target string. + * security.cc (lsa2wchar): Remove unused function. + (lsa2str): Ditto. + (get_lsa_srv_inf): Ditto. + (get_logon_server): Accommodate new argument order in call to + sys_wcstombs. + (get_user_groups): Ditto. + (get_user_local_groups): Ditto. + (get_priv_list): Call sys_wcstombs directly instead of lsa2str. + * uinfo.cc (cygheap_user::ontherange): Accommodate new argument order + in call to sys_wcstombs. + * winsup.h (sys_wcstombs): Change prototype to match new argument order. + +2006-02-07 Corinna Vinschen <corinna@vinschen.de> + + * init.cc (respawn_wow64_process): Exit with the exit code returned + by the respawned process. + +2006-02-06 Christopher Faylor <cgf@timesys.com> + + Always zero all elements of siginfo_t throughout. + * cygtls.h (_cygtls::thread_context): Declare new field. + (_cygtls::thread_id): Ditto. + (_cygtls::signal_exit): Move into this class. + (_cygtls::copy_context): Declare new function. + (_cygtls::signal_debugger): Ditto. + * cygtls.cc (_cygtls::init_thread): Fill out thread id field. + * exceptions.cc (exception): Change message when exception info is + unknown. Copy context to thread local storage. + (_cygtls::handle_exceptions): Avoid double test for fault_guarded. + Reflect move of signal_exit to _cygtls class. + (sigpacket::process): Copy context to thread local storage. + (_cygtls::signal_exit): Move to _cygtls class. Call signal_debugger to + notify debugger of exiting signal (WIP). Call stackdump here (WIP). + (_cygtls::copy_context): Define new function. + (_cygtls::signal_debugger): Ditto. + * tlsoffsets.h: Regenerate. + * include/cygwin.h (_fpstate): New internal structure. + (ucontext): Declare new structure (WIP). + (__COPY_CONTEXT_SIZE): New define. + + * exceptions.cc (_cygtls::interrupt_setup): Clear "threadkill" field + when there is no sigwaiting thread. + (setup_handler): Move event handling into interrupt_setup. + +2006-02-06 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_socket.cc (fhandler_socket::connect): Fix formatting. + (fhandler_socket::wait): Handle SA_RESTART when signal arrives. + +2006-02-06 Corinna Vinschen <corinna@vinschen.de> + + * include/cygwin/socket.h (CMSG_FIRSTHDR): Avoid compiler warning. + +2006-02-05 Corinna Vinschen <corinna@vinschen.de> + + * include/features.h: Add comment to explain what's going to happen + here at one point. + * include/sys/stdio.h: Guard getline and getdelim prototypes with + _GNU_SOURCE to avoid collision with old-style declarations. + +2006-02-05 Corinna Vinschen <corinna@vinschen.de> + + * environ.cc (struct parse_thing): Add transparent_exe option. + * fhandler_disk_file.cc (fhandler_disk_file::link): Accommodate + transparent_exe option. Add .exe suffix for links to executable files, + if transparent_exe is set. + * fhandler_process.cc (fhandler_process::fill_filebuf): Remove .exe + suffix if transparent_exe option is set. + * path.cc (symlink_worker): Accommodate transparent_exe option. + (realpath): Don't tack on .exe suffix if transparent_exe is set. + * syscalls.cc (transparent_exe): New global variable. + (unlink): Accommodate transparent_exe option. + (open): Ditto. + (link): Ditto. + (rename): Ditto. Maybe add .exe suffix when renaming executable files. + (pathconf): Accommodate transparent_exe option. + * winsup.h: Declare transparent_exe. + +2006-02-05 Christopher Faylor <cgf@timesys.com> + Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::readdir_9x): Remove + useless code. + +2006-02-05 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::rewinddir): Remove label + "out". Move test for NULL __handle ... + (fhandler_disk_file::rewinddir_9x): ... here. + +2006-02-05 Corinna Vinschen <corinna@vinschen.de> + + * dir.cc (rewinddir): Keep dirent_get_d_ino and dirent_set_d_ino flags. + +2006-02-05 Christopher Faylor <cgf@timesys.com> + + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Don't close dir + handle when we hit EOF since rewwindir may reactivate it. + (fhandler_disk_file::readdir_9x): Eliminate superfluous temporary + variable. + (fhandler_disk_file::closedir): Return EBADF when trying to close + unopened DIR. Reorganize slightly. Return actual derived error value + rather than always returning 0. + +2006-02-04 Christopher Faylor <cgf@timesys.com> + + * dir.cc (rmdir): Reorganize check for trailing dot to return correct + error when directory does not exist. + +2006-02-03 Christopher Faylor <cgf@timesys.com> + + * dir.cc (mkdir): Reorganize check for trailing dot to return correct + error when directory exists. + * fhandler_disk_file.cc (fhandler_disk_file::mkdir): Remove special + test for path ending in '.'. + +2006-02-03 Corinna Vinschen <corinna@vinschen.de> + + * path.cc (suffix_scan::lnk_match): Return true beginning with + SCAN_APPENDLNK. + (suffix_scan::next): Rearrange code to make .lnk append order slightly + more deterministic. + * spawn.cc (exe_suffixes): Try no suffix before .exe suffix to align + evaluation with stat_suffixes. + (dll_suffixes): Ditto. + +2006-02-02 Christopher Faylor <cgf@timesys.com> + + * cygwin/version.h: Mention CW_SETUP_WINENV in comment for API minor + 153. + +2006-02-02 Corinna Vinschen <corinna@vinschen.de> + + * cygwin.din (updwtmpx): Export. + * syscalls.cc (updwtmpx): New function. + * include/utmpx.h (updwtmpx): Declare. + * include/cygwin/version.h: Bump API minor number to 153. + +2006-02-02 Christopher Faylor <cgf@timesys.com> + + * external.cc (setup_winenv): New function. + (cygwin_internal): Implement CW_SETUP_WINENV. + * sys/cygwin.h (cygwin_getinfo_types): Define CW_SETUP_WINENV. + +2006-02-02 Corinna Vinschen <corinna@vinschen.de> + + * security.cc (is_group_member): Fix comment. + +2006-02-02 Corinna Vinschen <corinna@vinschen.de> + + * security.cc (is_group_member): Use local group info type 1. Test + group for being a global group or a well-known SID before adding it + to the group list. Add comment. + +2006-02-01 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (GetTcpTable): Define. + * fhandler_socket.cc (address_in_use): New function to check if + sockaddr_in address is already in use. + (fhandler_socket::bind): Check if address is alreay in use in case of + SO_REUSEADDR, to circumvent WinSock non-standard behaviour. + +2006-02-01 Corinna Vinschen <corinna@vinschen.de> + + * spawn.cc (dll_suffixes): Add .exe and "no suffix" to the list. + +2006-01-31 Corinna Vinschen <corinna@vinschen.de> + + * dlfcn.cc (check_path_access): Call find_exec with FE_DLL option. + * path.h (enum fe_types): Add FE_DLL value. + * spawn.cc (std_suffixes): Remove. + (exe_suffixes): New suffix_info for executing files. + (dll_suffixes): New suffix_info for searching shared libraries. + (perhaps_suffix): Add opt argument. Use dll_suffixes if FE_DLL + option is given, exe_suffixes otherwise. + (find_exec): Propagate opt argument to perhaps_suffix. Drop suffix + check when testing execute permission. + (spawn_guts): Call perhaps_suffix with FE_NADA opt argument. + +2006-01-31 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (av::fixup): Remove unused argument. + (spawn_guts): Remove capitalization in debugging. + +2006-01-31 Corinna Vinschen <corinna@vinschen.de> + + * spawn.cc (find_exec): Only return files with execute permission set + if ntsec is on. Don't check execute permission of Windows batch files. + (av::fixup): Handle empty files gracefully. Drop execute permission + test here. + * path.cc (suffix_scan::next): Don't skip any suffix on first run. + +2006-01-31 Corinna Vinschen <corinna@vinschen.de> + + * path.cc (cwdstuff::set): Don't set win32 error, only POSIX errno. + +2006-01-31 Corinna Vinschen <corinna@vinschen.de> + + * path.cc (cwdstuff::set): When SetCurrentDirectory returns + ERROR_INVALID_FUNCTION, bend it over to ERROR_FILE_NOT_FOUND. Add + comment to explain why. + +2006-01-31 Corinna Vinschen <corinna@vinschen.de> + + * dir.cc (readdir_worker): Add comment about writing old 32 bit d_ino. + * include/cygwin/version.h: Bump API minor number to 152. + (CYGWIN_VERSION_CHECK_FOR_NEEDS_D_INO): Remove. + +2006-01-30 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::rewinddir): Simplify + conditional. + +2006-01-30 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (d_cachepos): Rename from d_pos to distinct + clearly from __d_position. Change throughout. + (fhandler_disk_file::rewinddir): Reset readdir cache on NT. + +2006-01-29 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (readdir_get_ino): Don't follow symlinks. + +2006-01-29 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.h (class fhandler_socket): Add saw_reuseaddr status flag. + * fhandler_socket.cc (fhandler_socket::bind): Set socket to + SO_EXCLUSIVEADDRUSE if application didn't explicitely set SO_REUSEADDR + socket option, on systems supporting SO_EXCLUSIVEADDRUSE. + * net.cc (cygwin_setsockopt): Set fhandler's saw_reuseaddr status flag + if SO_REUSEADDR socket option has been successsfully set. + * wincap.h (wincaps::has_exclusiveaddruse): New element. + * wincap.cc: Implement above element throughout. + +2006-01-28 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::mkdir): In case or error, + check for existance explicitely and set errno to EEXIST. + +2006-01-28 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (DIR_NUM_ENTRIES): New define determining + minimum number of dir entries which fit into the readdir cache. + (DIR_BUF_SIZE): Define globally as size of readdir cache. + (struct __DIR_cache): New structure used for readdir caching on NT. + (d_dirname): Accessor for struct __DIR_cache, use throughout. + (d_pos): Ditto. + (d_cache): Ditto. + (fhandler_disk_file::opendir): Allocate __d_dirname to contain readdir + cache on NT. + (fhandler_disk_file::readdir): Use buf as pointer into readdir cache. + Implement readdir caching. + +2006-01-28 Corinna Vinschen <corinna@vinschen.de> + + * include/sys/dirent.h (struct dirent): Revert misguided attempt to + rename __d_unused1 to __d_fd. + +2006-01-27 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (NtQueryDirectoryFile): Define. + * dir.cc (__opendir_with_d_ino): Just call opendir. + (opendir): Remove CYGWIN_VERSION_CHECK_FOR_NEEDS_D_INO handling. + (readdir_worker): Only try generating d_ino if it's 0. + Utilize namehash of directories fhandler. Call readdir_get_ino to + generate d_ino for "..". + (seekdir64): Keep dirent_set_d_ino flag. + * fhandler.h (enum dirent_states): Add dirent_get_d_ino. + (class fhandler_disk_file): Declare new private methods readdir_helper + and readdir_9x. + * fhandler_disk_file.cc (path_conv::hasgood_inode): New method to + evaluate if a filesystem has reliable inode numbers. + (fhandler_base::fstat_by_handle): Accommodate structure member name + change from IndexNumber to FileId. + (fhandler_base::fstat_helper): Call hasgood_inode here. + (fhandler_disk_file::opendir): Call fhaccess only for real files. + Don't append '*' to __d_dirname here, move to readdir_9x. On NT, + open directory handle here. Set dirent_get_d_ino and dirent_set_d_ino + flags according to wincap and filesystem. + (fhandler_disk_file::readdir_helper): New method to implement readdir + postprocessing only once. + (readdir_get_ino_by_handle): New static function. + (readdir_get_ino): New function to centralize inode number evaluation + in case inode number hasn't been returned by NtQueryDirectoryFile. + (fhandler_disk_file::readdir): Move old functionality to readdir_9x. + Call readdir_9x when on 9x/Me. Implement NT specific readdir here. + (fhandler_disk_file::readdir_9x): Move 9x specific readdir here. + (fhandler_disk_file::seekdir): Accommodate new NT readdir method. + (fhandler_disk_file::closedir): Ditto. + (fhandler_cygdrive::fstat): Set d_ino to namehash. Add comment. + (fhandler_cygdrive::opendir): Call get_namehash to prepare later + correct evaluation of d_ino. + (fhandler_cygdrive::readdir): Replace recursion with loop. Evaluate + drive's d_ino by calling readdir_get_ino. + * fhandler_proc.cc (fhandler_proc::readdir): Set dirent_saw_dot and + dirent_saw_dot_dot to avoid seeing . and .. entries twice. + * fhandler_process.cc (fhandler_process::readdir): Ditto. + * fhandler_registry.cc (fhandler_registry::readdir): Ditto. + * ntdll.h (STATUS_INVALID_PARAMETER): New define. + (STATUS_INVALID_LEVEL): New define. + (struct _FILE_INTERNAL_INFORMATION): Rename member IndexNumber to + FileId (as in Nebbitt). + * path.h (path_conv::hasgood_inode): Now implemented in + fhandler_disk_file.cc. + * wincap.h (wincaps::has_fileid_dirinfo): New element. + * wincap.cc: Implement above element throughout. + * winsup.h (readdir_get_ino): Add declaration. + * include/sys/dirent.h (struct dirent): Slightly rename structure + members to accommodate changes. + Remove __USE_EXPENSIVE_CYGWIN_D_INO handling and declaration of + __opendir_with_d_ino. + +2006-01-27 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (spawn_guts): Fix potential handle leak when failing exec. + +2006-01-27 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (inside_kernel): Fix to return true if we can't get the + name of the DLL for the given memory block since we are not in kernel + code. + +2006-01-26 Corinna Vinschen <corinna@vinschen.de> + + * fhandler.cc (fhandler_base::open): Fix bug in argument order to + InitializeObjectAttributes call. + +2006-01-25 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_disk_file::readdir): Fix test for + dirent_isroot to use the correct boolean operator. + +2006-01-25 Christopher Faylor <cgf@timesys.com> + + * ntdll.h: (temporarily?) Add more functions for querying directory. + +2006-01-24 Christopher Faylor <cgf@timesys.com> + + * dir.cc (readdir_worker): Turn off expensive inode calculation. + +2006-01-24 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_process.cc (fhandler_process::fill_filebuf): Disable + stripping the .exe suffix from the link target in PROCESS_EXE and + PROCESS_EXENAME case. + * path.cc (realpath): Tack on .exe suffix if necessary. + +2006-01-24 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_disk_file.cc (fhandler_base::fstat_helper): Try harder + to determine remote file systems with reliable inode numbers. Add + longish comment. + +2006-01-23 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Reset + inheritance for duplicated socket. + +2006-01-20 Christopher Faylor <cgf@timesys.com> + + * include/cygwin/version.h: Bump API minor number to 151. + * dir.cc (__opendir_with_d_ino): New function. + (opendir): Set flag if we should be calculating inodes. + (readdir_worker): Calculate d_ino by calling stat if the user has asked + for it. + (seekdir64): Maintain all persistent flag settings. + * fhandler.h (dirent_states): Add dirent_set_d_ino. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Reflect changes + to dirent structure. + * fhandler_virtual.cc (fhandler_virtual::opendir): Ditto. + * include/sys/dirent.h (struct dirent): Coalesce two similar + structures. Remove all shreds of the apparently highly confusing + references to inodes. Add support for calculating a real inode if + __USE_EXPENSIVE_CYGWIN_D_INO is defined. + +2006-01-20 Christopher Faylor <cgf@timesys.com> + + * include/sys/dirent.h: Add comments for people who are REALLY confused + about whether they should be using something called __invalid_d_ino or + not. + +2006-01-20 Corinna Vinschen <corinna@vinschen.de> + + * fhandler_socket.cc (fhandler_socket::prepare): Fix debug output. + (fhandler_socket::release): Add debug output for WSAEventSelect failure. + (fhandler_socket::ioctl): Always cancel WSAEventSelect before switching + to blocking mode. Only set nonblocking flag if ioctlsocket call + succeeded. Only print new socket state if ioctlsocket call succeeded. + +2006-01-19 Christopher Faylor <cgf@timesys.com> + + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Check posix path + for root rather than windows path. + +2006-01-19 Christopher Faylor <cgf@timesys.com> + + * dir.cc (readdir_worker): Fill in invalid fields with -1. Accommodate + name change from __ino32 to __invalid_ino32. + * include/sys/dirent.h (__invalid_ino32): Rename from __ino32. Don't + define unused d_type macros. + +2006-01-18 Christopher Faylor <cgf@timesys.com> + + * heap.cc (heap_init): Remove Sleep. + +2006-01-18 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (rresvport): Remove extern declaration. + +2006-01-18 Corinna Vinschen <corinna@vinschen.de> + + * autoload.cc (rresvport): Remove. + * net.cc (last_used_rrecvport): New global shared variable. + (cygwin_rresvport): Implement rresvport without using rresvport from + wsock32. + +2006-01-18 Corinna Vinschen <corinna@vinschen.de> + + * include/cygwin/socket.h (struct sockaddr_storage): Fix typo in + ss_family member name. + +2006-01-16 Christopher Faylor <cgf@timesys.com> + + * include/cygwin/version.h: Bump DLL minor version number to 20. + +2006-01-13 Corinna Vinschen <corinna@vinschen.de> + + * uname.cc (uname): Concatenate a "-WOW64" to utsname's sysname + member to see when running under WOW64. + +2006-01-13 Corinna Vinschen <corinna@vinschen.de> + + * net.cc (cygwin_setsockopt): Ignore errors when setting IP_TOS on + Windows 2000 and above. Clarify the comment about IP_TOS and move + to the place where the magic happens. + (get_ifconf): Remove unused code. + * wincap.h (wincaps::has_disabled_user_tos_setting): New element. + * wincap.cc: Implement above element throughout. + +2006-01-12 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (set_console_state_for_spawn): Fix to recognize + ttys >= 0. + +2006-01-12 Christopher Faylor <cgf@timesys.com> + + * fhandler.h (set_console_state_for_spawn): Whackamole the argument + back to a bool. + * spawn.cc (spawn_guts): Ditto, i.e., once again call + set_console_state_for_spawn with an indication of whether we're about + to start a cygwin process. + * fhandler_console.cc (set_console_state_for_spawn): Don't set the + console state if we know we're starting a cygwin process or if we're + using a "real" tty. + +2006-01-10 Corinna Vinschen <corinna@vinschen.de> + + * dcrt0.cc (dll_crt0_0): Remove call to wincap.init. + * init.cc (dll_entry): Rename is_wow64_proc to wow64_test_stack_marker. + Call wincap.init here before doing anything else. Use wincap.is_wow64 + to determine if we're running in a WOW64 emulator. + * mmap.cc (MapViewNT): Don't use AT_ROUND_TO_PAGE in WOW64, it's + apparently not supported. + (mmap64): Don't create mappings beyond EOF, which would need to use + AT_ROUND_TO_PAGE, on WOW64. + * wincap.cc (wincap): Throw into the .cygwin_dll_common section. + (wincapc::init): Determine if running in WOW64 and set wow_64 flag. + * wincap.h (class wincapc): Add wow64 member. + (wincapc::is_wow64): New method. + +2006-01-10 Christopher Faylor <cgf@timesys.com> + + * fhandler_proc.cc (format_proc_cpuinfo): Avoid leading whitespace in + model name. + +2006-01-09 Christopher Faylor <cgf@timesys.com> + + * spawn.cc (spawn_guts): Reorganize slightly so that 16 bit check is + done prior to check for command.com/cmd.com. Don't bother setting + CREATE_SUSPENDED flag for a MS-DOS process since it doesn't work + anyway. Avoid calling remember() when the child process has already + exited. + (av::fixup): Explicitly set cygexec flag to false on a 16 bit process. + +2006-01-09 Corinna Vinschen <corinna@vinschen.de> + + * include/getopt.h (getopt_long_only): Declare. + +2006-01-09 Eric Blake <ebb9@byu.net> + + * cygwin.din: Export getsubopt. + * include/cygwin/version.h: Bump API minor version. + +2006-01-08 Christopher Faylor <cgf@timesys.com> + + * fhandler_tty.cc (fhandler_tty_slave::dup): Don't assign a controlling + terminal to a process when duped. Linux doesn't do this, so we won't + either. + +2006-01-08 Christopher Faylor <cgf@timesys.com> + + * environ.cc (spenvs[]): windir -> WINDIR. + +2006-01-07 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (fhandler_console::need_invisible): Remove + duplicate test. + +2006-01-07 Christopher Faylor <cgf@timesys.com> + + * fhandler.h (set_console_state_for_spawn): Eliminate argument from + declaration. + * fhandler.cc (set_console_state_for_spawn): Eliminate argument from + definition. Always check for invisible console. + (fhandler_console::need_invisible): Don't do anything if the windows + station is already not visible. + * spawn.cc (spawn_guts): Accommodate change of argument to + set_console_state_for_spawn. + +2006-01-05 Christopher Faylor <cgf@timesys.com> + + * sigproc.cc (no_signals_available): Use existence of signal thread + handle to figure out if we can actually send signals rather than + relying on my_sendsig. + (hwait_sig): Make static. + (sigproc_init): Don't set my_sendsig to anything special. Use new + global static hwait_sig. + (wait_sig): Set hwait_sig to NULL when we are exiting. + +2006-01-05 Christopher Faylor <cgf@timesys.com> + + * include/getopt.h: Accommodate recent unfortunate newlib changes. + +2006-01-05 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::remove): Don't output debugging info if this + isn't a cygwin thread. + * sigproc.cc (sigproc_init): Move clearing of sync_startup here to + lessen the likelihood of trying to deal with non-cygwin threads in + dll_entry. + + * fhandler_console: Fix set_console_state_for_spawn comment. + +2006-01-05 Igor Peshansky <pechtcha@cs.nyu.edu> + + * spawn.cc (spawn_guts): Invert the argument to + set_console_state_for_spawn. + +2006-01-04 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (fhandler_console::need_invisible): Only try to + open "CygwinInvisible" windows station if opening of default station + fails. Use CloseWindowStation to close window station handle. + +2006-01-04 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (fhandler_console::need_invisible): Open up the + security of the newly created windows station. + +2006-01-04 Eric Blake <ebb9@byu.net> + + * path.cc (dot_special_chars): Add ", <, >, and |. + +2006-01-03 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (beep): Use MB_OK which is documented as using + the default bell rather than -1 which seems to behave differently on + different versions of Windows. + +2006-01-03 Christopher Faylor <cgf@timesys.com> + + * fhandler_process.cc (fhandler_process::readdir): Add missing argument + to syscall_printf. + + * fhandler_console.cc (fhandler_console::need_invisible): Use made-up + name for windows station rather than asking Windows to create one for + us. + + * spawn.cc (spawn_guts): Don't mess with console if we're detaching. + +2006-01-03 Christopher Faylor <cgf@timesys.com> + + * dir.cc (readdir_worker): Minor code cleanup. + + * fhandler_console.cc (beep): Use a more Windows-generic wav file if + the beep is missing. Use a more foolproof way to find out whether we + should be recreating the missing key. + + * registry.h (reg_key::_disposition): New field. + (reg_key::created): New function. + * registry.cc (reg_key::reg_key): Set _disposition to zero by default. + (reg_key::build_key): Fill in _disposition field. + +2006-01-03 Eric Blake <ebb9@byu.net> + + * dir.cc (readdir_worker): Ensure that saw_dot* flags are updated when + not handling inodes. + +2006-01-02 Christopher Faylor <cgf@timesys.com> + + * fhandler_console.cc (beep): New function. Restores missing "Default + Beep", if necessary. + (fhandler_console::write_normal): Use beep(). + +2006-01-02 Christopher Faylor <cgf@timesys.com> + + * dcrt0.cc (_dll_crt0): Remove more leftover debugging stuff. + (cygwin_dll_init): Remove unneeded initializations. Call _dll_crt0 + rather than dll_crt0_1. + +2006-01-02 Corinna Vinschen <corinna@vinschen.de> + + * syslog.cc: Include sys/un.h instead of sys/socket.h. + (syslogd_inited): Convert to enum type noting the exact result of + trying to connect to syslog daemon. Use this way throughout. + (connect_syslogd): New static function taking over the task to + connect to syslog socket. Use correct struct sockaddr_un instead of + struct sockaddr. + (try_connect_syslogd): Call connect_syslogd. If write fails on + connection oriented socket, try to reconnect to syslog socket and + try to write again. + +2006-01-01 Christopher Faylor <cgf@timesys.com> + + * pinfo.cc (pinfo::exit): Swap signal and normal exit value when not + started from a cygwin process - just like the good-old-days of B20. + +2006-01-01 Christopher Faylor <cgf@timesys.com> + + * strace.cc (strace::write_childpid): Remove debugging output. + +2006-01-01 Christopher Faylor <cgf@timesys.com> + + * cygtls.cc (_cygtls::remove): Remove left over debugging cruft which + caused this function to always return prematurely. + +2006-01-01 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (sigpacket::process): Pass actual reference to signal's + sigaction structure to setup_handler. + +2006-01-01 Christopher Faylor <cgf@timesys.com> + + * exceptions.cc (_cygtls::interrupt_setup): Implement SA_RESETHAND. + * include/cygwin/signal.h: Define SA_ONESHOT and SA_NOMASK. + + * dcrt0.cc (get_cygwin_startup_info): Remove commented out code. + +2006-01-01 Corinna Vinschen <corinna@vinschen.de> + + * syslog.cc (vklog): Never log kernel messages using the vsyslog + interface. diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc new file mode 100644 index 00000000000..516757e0e64 --- /dev/null +++ b/winsup/cygwin/autoload.cc @@ -0,0 +1,572 @@ +/* autoload.cc: all dynamic load stuff. + + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 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. */ + +#include "winsup.h" +#define USE_SYS_TYPES_FD_SET +#include <winsock2.h> + +/* Macro for defining "auto-load" functions. + * Note that this is self-modifying code *gasp*. + * The first invocation of a routine will trigger the loading of + * the DLL. This will then be followed by the discovery of + * the procedure's entry point, which is placed into the location + * pointed to by the stack pointer. This code then changes + * the "call" operand which invoked it to a "jmp" which will + * transfer directly to the DLL function on the next invocation. + * + * Subsequent calls to routines whose transfer address has not been + * determined will skip the "load the dll" step, starting at the + * "discovery of the entry point" step. + * + * So, immediately following the the call to one of the above routines + * we have: + * DLL info (4 bytes) Pointer to a block of information concerning + * the DLL (see below). + * DLL args (4 bytes) The number of arguments pushed on the stack by + * the call. If this is an odd value then this + * is a flag that non-existence of this function + * is not a fatal error + * func name (n bytes) asciz string containing the name of the function + * to be loaded. + * + * The DLL info block consists of the following + * load_state (4 bytes) Pointer to a word containing the routine used + * to eventually invoke the function. Initially + * points to an init function which loads the + * DLL, gets the process's load address, + * changes the contents here to point to the + * function address, and changes the call *(%eax) + * to a jmp func. If the initialization has been + * done, only the load part is done. + * DLL handle (4 bytes) The handle to use when loading the DLL. + * DLL locker (4 bytes) Word to use to avoid multi-thread access during + * initialization. + * extra init (4 bytes) Extra initialization function. + * DLL name (n bytes) asciz string containing the name of the DLL. + */ + +/* LoadDLLprime is used to prime the DLL info information, providing an + additional initialization routine to call prior to calling the first + function. */ +#define LoadDLLprime(dllname, init_also) __asm__ (" \n\ +.ifndef " #dllname "_primed \n\ + .section .data_cygwin_nocopy,\"w\" \n\ + .align 4 \n\ +."#dllname "_info: \n\ + .long _std_dll_init \n\ + .long 0 \n\ + .long -1 \n\ + .long " #init_also " \n\ + .asciz \"" #dllname "\" \n\ + .text \n\ + .set " #dllname "_primed, 1 \n\ +.endif \n\ +"); + +/* Create a "decorated" name */ +#define mangle(name, n) #name "@" #n + +/* Standard DLL load macro. May invoke a fatal error if the function isn't + found. */ +#define LoadDLLfunc(name, n, dllname) \ + LoadDLLfuncEx (name, n, dllname, 0) +#define LoadDLLfuncEx(name, n, dllname, notimp) \ + LoadDLLfuncEx2(name, n, dllname, notimp, 0) +#define LoadDLLfuncEx2(name, n, dllname, notimp, err) \ + LoadDLLfuncEx3(name, n, dllname, notimp, err, 0) + +/* Main DLL setup stuff. */ +#define LoadDLLfuncEx3(name, n, dllname, notimp, err, fn) \ + LoadDLLprime (dllname, dll_func_load) \ + __asm__ (" \n\ + .section ." #dllname "_autoload_text,\"wx\" \n\ + .global _" mangle (name, n) " \n\ + .global _win32_" mangle (name, n) " \n\ + .align 8 \n\ +_" mangle (name, n) ": \n\ +_win32_" mangle (name, n) ": \n\ + .byte 0xe9 \n\ + .long -4 + 1f - . \n\ +1:movl (2f),%eax \n\ + call *(%eax) \n\ +2:.long ." #dllname "_info \n\ + .long (" #n "+" #notimp ") | (((" #err ") & 0xff) <<16) | (((" #fn ") & 0xff) << 24) \n\ + .asciz \"" #name "\" \n\ + .text \n\ +"); + +/* DLL loader helper functions used during initialization. */ + +/* The function which finds the address, given the name and overwrites + the call so that future invocations go straight to the function in + the DLL. */ +extern "C" void dll_func_load () __asm__ ("dll_func_load"); + +/* Called by the primary initialization function "init_std_dll" to + setup the stack and eliminate future calls to init_std_dll for other + functions from this DLL. */ +extern "C" void dll_chain () __asm__ ("dll_chain"); + +extern "C" { + +__asm__ (" \n\ +msg1: \n\ + .ascii \"couldn't dynamically determine load address for '%s' (handle %p), %E\\0\"\n\ + \n\ + .align 32 \n\ +noload: \n\ + popl %edx # Get the address of the information block\n\ + movl 4(%edx),%eax # Should we 'ignore' the lack \n\ + test $1,%eax # of this function? \n\ + jz 1f # Nope. \n\ + decl %eax # Yes. This is the # of bytes + 1 \n\ + popl %edx # Caller's caller \n\ + addl %eax,%esp # Pop off bytes \n\ + andl $0xffff0000,%eax# upper word \n\ + subl %eax,%esp # adjust for possible return value \n\ + pushl %eax # Save for later \n\ + movl $127,%eax # ERROR_PROC_NOT_FOUND \n\ + pushl %eax # First argument \n\ + call _SetLastError@4 # Set it \n\ + popl %eax # Get back argument \n\ + sarl $16,%eax # return value in high order word \n\ + jmp *%edx # Return \n\ +1: \n\ + movl (%edx),%eax # Handle value \n\ + pushl 4(%eax) \n\ + leal 8(%edx),%eax # Location of name of function \n\ + push %eax \n\ + push $msg1 # The message \n\ + call ___api_fatal # Print message. Never returns \n\ + \n\ + .globl dll_func_load \n\ +dll_func_load: \n\ + movl (%esp),%eax # 'Return address' contains load info \n\ + addl $8,%eax # Address of name of function to load \n\ + pushl %eax # Second argument \n\ + movl -8(%eax),%eax # Where handle lives \n\ + movl 4(%eax),%eax # Address of Handle to DLL \n\ + pushl %eax # Handle to DLL \n\ + call _GetProcAddress@8# Load it \n\ + test %eax,%eax # Success? \n\ + jne gotit # Yes \n\ + jmp noload # Issue an error or return \n\ +gotit: \n\ + popl %edx # Pointer to 'return address' \n\ + subl %edx,%eax # Make it relative \n\ + addl $7,%eax # Tweak \n\ + subl $12,%edx # Point to jmp \n\ + movl %eax,1(%edx) # Move relative address after jump \n\ + jmp *%edx # Jump to actual function \n\ + \n\ + .global dll_chain \n\ +dll_chain: \n\ + pushl %eax # Restore 'return address' \n\ + jmp *%edx # Jump to next init function \n\ +"); + +/* C representations of the two info blocks described above. + FIXME: These structures confuse gdb for some reason. GDB can print + the whole structure but has problems with the name field? */ +struct dll_info +{ + DWORD load_state; + HANDLE handle; + LONG here; + void (*init) (); + char name[]; +}; + +struct func_info +{ + struct dll_info *dll; + LONG decoration; + char name[]; +}; + +/* Mechanism for setting up info for passing to dll_chain routines. */ +union retchain +{ + struct {long high; long low;}; + long long ll; +}; + +/* The standard DLL initialization routine. */ +__attribute__ ((used, noinline)) static long long +std_dll_init () +{ + HANDLE h; + struct func_info *func = (struct func_info *) __builtin_return_address (0); + struct dll_info *dll = func->dll; + retchain ret; + + if (InterlockedIncrement (&dll->here)) + do + { + InterlockedDecrement (&dll->here); + low_priority_sleep (0); + } + while (InterlockedIncrement (&dll->here)); + else if (!dll->handle) + { + unsigned fpu_control = 0; + __asm__ __volatile__ ("fnstcw %0": "=m" (fpu_control)); + if ((h = LoadLibrary (dll->name)) != NULL) + { + __asm__ __volatile__ ("fldcw %0": : "m" (fpu_control)); + dll->handle = h; + } + else if (!(func->decoration & 1)) + api_fatal ("could not load %s, %E", dll->name); + else + dll->handle = INVALID_HANDLE_VALUE; + } + + InterlockedDecrement (&dll->here); + + /* Kludge alert. Redirects the return address to dll_chain. */ + __asm__ __volatile__ (" \n\ + movl $dll_chain,4(%ebp) \n\ + "); + + /* Set "arguments for dll_chain. */ + ret.low = (long) dll->init; + ret.high = (long) func; + return ret.ll; +} + +/* Initialization function for winsock stuff. */ +bool NO_COPY wsock_started = 0; +WSADATA NO_COPY wsadata; +__attribute__ ((used, noinline, regparm(1))) static long long +wsock_init () +{ + static LONG NO_COPY here = -1L; + struct func_info *func = (struct func_info *) __builtin_return_address (0); + struct dll_info *dll = func->dll; + + while (InterlockedIncrement (&here)) + { + InterlockedDecrement (&here); + low_priority_sleep (0); + } + + if (!wsock_started) + { + int (*wsastartup) (int, WSADATA *); + + /* Don't use autoload to load WSAStartup to eliminate recursion. */ + wsastartup = (int (*)(int, WSADATA *)) + GetProcAddress ((HMODULE) (dll->handle), "WSAStartup"); + if (wsastartup) + { + int res = wsastartup ((2<<8) | 2, &wsadata); + + debug_printf ("res %d", res); + debug_printf ("wVersion %d", wsadata.wVersion); + debug_printf ("wHighVersion %d", wsadata.wHighVersion); + debug_printf ("szDescription %s", wsadata.szDescription); + debug_printf ("szSystemStatus %s", wsadata.szSystemStatus); + debug_printf ("iMaxSockets %d", wsadata.iMaxSockets); + debug_printf ("iMaxUdpDg %d", wsadata.iMaxUdpDg); + debug_printf ("lpVendorInfo %d", wsadata.lpVendorInfo); + + wsock_started = 1; + } + } + + /* Kludge alert. Redirects the return address to dll_chain. */ + __asm__ __volatile__ (" \n\ + movl $dll_chain,4(%ebp) \n\ + "); + + InterlockedDecrement (&here); + + volatile retchain ret; + /* Set "arguments for dll_chain. */ + ret.low = (long) dll_func_load; + ret.high = (long) func; + return ret.ll; +} + +LoadDLLprime (wsock32, _wsock_init) +LoadDLLprime (ws2_32, _wsock_init) + +LoadDLLfunc (AccessCheck, 32, advapi32) +LoadDLLfunc (AddAccessAllowedAce, 16, advapi32) +LoadDLLfunc (AddAccessDeniedAce, 16, advapi32) +LoadDLLfunc (AddAce, 20, advapi32) +LoadDLLfunc (AdjustTokenPrivileges, 24, advapi32) +LoadDLLfuncEx (AllocateLocallyUniqueId, 4, advapi32, 1) +LoadDLLfunc (CopySid, 12, advapi32) +LoadDLLfunc (CreateProcessAsUserA, 44, advapi32) +LoadDLLfuncEx (CryptAcquireContextA, 20, advapi32, 1) +LoadDLLfuncEx (CryptGenRandom, 12, advapi32, 1) +LoadDLLfuncEx (CryptReleaseContext, 8, advapi32, 1) +LoadDLLfunc (DeregisterEventSource, 4, advapi32) +LoadDLLfunc (DuplicateToken, 12, advapi32) +LoadDLLfuncEx (DuplicateTokenEx, 24, advapi32, 1) +LoadDLLfunc (EqualSid, 8, advapi32) +LoadDLLfunc (FindFirstFreeAce, 8, advapi32) +LoadDLLfunc (GetAce, 12, advapi32) +LoadDLLfunc (GetFileSecurityA, 20, advapi32) +LoadDLLfunc (GetKernelObjectSecurity, 20, advapi32) +LoadDLLfunc (GetLengthSid, 4, advapi32) +LoadDLLfunc (GetSecurityDescriptorDacl, 16, advapi32) +LoadDLLfunc (GetSecurityDescriptorGroup, 12, advapi32) +LoadDLLfunc (GetSecurityDescriptorOwner, 12, advapi32) +LoadDLLfunc (GetSecurityInfo, 32, advapi32) +LoadDLLfunc (GetSidIdentifierAuthority, 4, advapi32) +LoadDLLfunc (GetSidSubAuthority, 8, advapi32) +LoadDLLfunc (GetSidSubAuthorityCount, 4, advapi32) +LoadDLLfunc (GetTokenInformation, 20, advapi32) +LoadDLLfunc (GetUserNameA, 8, advapi32) +LoadDLLfunc (ImpersonateLoggedOnUser, 4, advapi32) +LoadDLLfunc (ImpersonateNamedPipeClient, 4, advapi32) +LoadDLLfunc (InitializeAcl, 12, advapi32) +LoadDLLfunc (InitializeSecurityDescriptor, 8, advapi32) +LoadDLLfunc (InitializeSid, 12, advapi32) +LoadDLLfunc (IsValidSid, 4, advapi32) +LoadDLLfunc (LogonUserA, 24, advapi32) +LoadDLLfunc (LookupAccountNameA, 28, advapi32) +LoadDLLfunc (LookupAccountNameW, 28, advapi32) +LoadDLLfunc (LookupAccountSidA, 28, advapi32) +LoadDLLfunc (LookupPrivilegeValueA, 12, advapi32) +LoadDLLfunc (LsaClose, 4, advapi32) +LoadDLLfunc (LsaEnumerateAccountRights, 16, advapi32) +LoadDLLfunc (LsaFreeMemory, 4, advapi32) +LoadDLLfunc (LsaNtStatusToWinError, 4, advapi32) +LoadDLLfunc (LsaOpenPolicy, 16, advapi32) +LoadDLLfunc (LsaQueryInformationPolicy, 12, advapi32) +LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32) +LoadDLLfunc (OpenProcessToken, 12, advapi32) +LoadDLLfunc (OpenThreadToken, 16, advapi32) +// LoadDLLfunc (RegCloseKey, 4, advapi32) +LoadDLLfunc (RegCreateKeyExA, 36, advapi32) +LoadDLLfunc (RegDeleteKeyA, 8, advapi32) +LoadDLLfunc (RegDeleteValueA, 8, advapi32) +LoadDLLfunc (RegLoadKeyA, 12, advapi32) +LoadDLLfunc (RegEnumKeyExA, 32, advapi32) +LoadDLLfunc (RegEnumValueA, 32, advapi32) +LoadDLLfunc (RegOpenKeyExA, 20, advapi32) +LoadDLLfunc (RegQueryInfoKeyA, 48, advapi32) +LoadDLLfunc (RegQueryValueExA, 24, advapi32) +LoadDLLfunc (RegSetValueExA, 24, advapi32) +LoadDLLfunc (RegisterEventSourceA, 8, advapi32) +LoadDLLfunc (ReportEventA, 36, advapi32) +LoadDLLfunc (RevertToSelf, 0, advapi32) +LoadDLLfunc (SetKernelObjectSecurity, 12, advapi32) +LoadDLLfunc (SetSecurityDescriptorControl, 12, advapi32) +LoadDLLfunc (SetSecurityDescriptorDacl, 16, advapi32) +LoadDLLfunc (SetSecurityDescriptorGroup, 12, advapi32) +LoadDLLfunc (SetSecurityDescriptorOwner, 12, advapi32) +LoadDLLfunc (SetTokenInformation, 16, advapi32) +LoadDLLfunc (RegGetKeySecurity, 16, advapi32) + +/* 127 == ERROR_PROC_NOT_FOUND */ +LoadDLLfuncEx2 (DsGetDcNameA, 24, netapi32, 1, 127) +LoadDLLfunc (NetApiBufferFree, 4, netapi32) +LoadDLLfuncEx (NetGetAnyDCName, 12, netapi32, 1) +LoadDLLfuncEx (NetGetDCName, 12, netapi32, 1) +LoadDLLfunc (NetLocalGroupEnum, 28, netapi32) +LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32) +LoadDLLfunc (NetUserGetGroups, 28, netapi32) +LoadDLLfunc (NetUserGetInfo, 16, netapi32) +LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32) + +/* 0xc000007a == STATUS_PROCEDURE_NOT_FOUND */ +#define LoadDLLfuncNt(name, n, dllname) \ + LoadDLLfuncEx2(name, n, dllname, 1, 0xc000007a) +LoadDLLfuncNt (NtClose, 4, ntdll) +LoadDLLfuncNt (NtCreateFile, 44, ntdll) +LoadDLLfuncNt (NtCreateSection, 28, ntdll) +LoadDLLfuncNt (NtCreateToken, 52, ntdll) +LoadDLLfuncNt (NtLockVirtualMemory, 16, ntdll) +LoadDLLfuncNt (NtMapViewOfSection, 40, ntdll) +LoadDLLfuncNt (NtOpenDirectoryObject, 12, ntdll) +LoadDLLfuncNt (NtOpenFile, 24, ntdll) +LoadDLLfuncNt (NtOpenSection, 12, ntdll) +LoadDLLfuncNt (NtQueryDirectoryObject, 28, ntdll) +LoadDLLfuncNt (NtQueryDirectoryFile, 44, ntdll) +LoadDLLfuncNt (NtQueryEaFile, 36, ntdll) +LoadDLLfuncNt (NtQueryInformationFile, 20, ntdll) +LoadDLLfuncNt (NtQueryInformationProcess, 20, ntdll) +LoadDLLfuncNt (NtQueryObject, 20, ntdll) +LoadDLLfuncNt (NtQuerySystemInformation, 16, ntdll) +LoadDLLfuncNt (NtQuerySecurityObject, 20, ntdll) +LoadDLLfuncNt (NtQueryVirtualMemory, 24, ntdll) +LoadDLLfuncNt (NtQueryVolumeInformationFile, 20, ntdll) +LoadDLLfuncNt (NtSetEaFile, 16, ntdll) +LoadDLLfuncNt (NtSetSecurityObject, 12, ntdll) +LoadDLLfuncNt (NtUnlockVirtualMemory, 16, ntdll) +LoadDLLfuncNt (NtUnmapViewOfSection, 8, ntdll) +LoadDLLfuncNt (RtlInitUnicodeString, 8, ntdll) +LoadDLLfuncNt (RtlIsDosDeviceName_U, 4, ntdll) +LoadDLLfuncNt (RtlNtStatusToDosError, 4, ntdll) + +LoadDLLfuncEx (EnumProcessModules, 16, psapi, 1) +LoadDLLfuncEx (GetModuleFileNameExA, 16, psapi, 1) +LoadDLLfuncEx (GetModuleInformation, 16, psapi, 1) +LoadDLLfuncEx (GetProcessMemoryInfo, 12, psapi, 1) +LoadDLLfuncEx (QueryWorkingSet, 12, psapi, 1) + +LoadDLLfuncEx (LsaDeregisterLogonProcess, 4, secur32, 1) +LoadDLLfuncEx (LsaFreeReturnBuffer, 4, secur32, 1) +LoadDLLfuncEx (LsaLogonUser, 56, secur32, 1) +LoadDLLfuncEx (LsaLookupAuthenticationPackage, 12, secur32, 1) +LoadDLLfuncEx (LsaRegisterLogonProcess, 12, secur32, 1) + +LoadDLLfunc (CharToOemA, 8, user32) +LoadDLLfunc (CharToOemBuffA, 12, user32) +LoadDLLfunc (CloseClipboard, 0, user32) +LoadDLLfunc (CloseWindowStation, 4, user32) +LoadDLLfunc (CreateWindowExA, 48, user32) +LoadDLLfunc (CreateWindowStationA, 16, user32) +LoadDLLfunc (DefWindowProcA, 16, user32) +LoadDLLfunc (DispatchMessageA, 4, user32) +LoadDLLfunc (EmptyClipboard, 0, user32) +LoadDLLfunc (FindWindowA, 8, user32) +LoadDLLfunc (GetClipboardData, 4, user32) +LoadDLLfunc (GetForegroundWindow, 0, user32) +LoadDLLfunc (GetKeyboardLayout, 4, user32) +LoadDLLfunc (GetMessageA, 16, user32) +LoadDLLfunc (GetPriorityClipboardFormat, 8, user32) +LoadDLLfunc (GetProcessWindowStation, 0, user32) +LoadDLLfunc (GetThreadDesktop, 4, user32) +LoadDLLfunc (GetWindowThreadProcessId, 8, user32) +LoadDLLfunc (GetUserObjectInformationA, 20, user32) +LoadDLLfunc (KillTimer, 8, user32) +LoadDLLfunc (MessageBeep, 4, user32) +LoadDLLfunc (MessageBoxA, 16, user32) +LoadDLLfunc (MsgWaitForMultipleObjects, 20, user32) +LoadDLLfunc (OemToCharBuffA, 12, user32) +LoadDLLfunc (OpenClipboard, 4, user32) +LoadDLLfunc (PeekMessageA, 20, user32) +LoadDLLfunc (PostMessageA, 16, user32) +LoadDLLfunc (PostQuitMessage, 4, user32) +LoadDLLfunc (RegisterClassA, 4, user32) +LoadDLLfunc (RegisterClipboardFormatA, 4, user32) +LoadDLLfunc (SendMessageA, 16, user32) +LoadDLLfunc (SetClipboardData, 8, user32) +LoadDLLfunc (SetProcessWindowStation, 4, user32) +LoadDLLfunc (SetTimer, 16, user32) +LoadDLLfunc (SetUserObjectSecurity, 12, user32) + +LoadDLLfunc (rcmd, 24, wsock32) + +LoadDLLfunc (accept, 12, ws2_32) +LoadDLLfunc (bind, 12, ws2_32) +LoadDLLfunc (closesocket, 4, ws2_32) +LoadDLLfunc (connect, 12, ws2_32) +LoadDLLfunc (gethostbyaddr, 12, ws2_32) +LoadDLLfunc (gethostbyname, 4, ws2_32) +LoadDLLfuncEx2 (gethostname, 8, ws2_32, 1, 1) +LoadDLLfunc (getpeername, 12, ws2_32) +LoadDLLfunc (getprotobyname, 4, ws2_32) +LoadDLLfunc (getprotobynumber, 4, ws2_32) +LoadDLLfunc (getservbyname, 8, ws2_32) +LoadDLLfunc (getservbyport, 8, ws2_32) +LoadDLLfunc (getsockname, 12, ws2_32) +LoadDLLfunc (getsockopt, 20, ws2_32) +LoadDLLfunc (inet_addr, 4, ws2_32) +LoadDLLfunc (inet_ntoa, 4, ws2_32) +LoadDLLfunc (ioctlsocket, 12, ws2_32) +LoadDLLfunc (listen, 8, ws2_32) +LoadDLLfunc (recv, 16, ws2_32) +LoadDLLfunc (recvfrom, 24, ws2_32) +LoadDLLfunc (select, 20, ws2_32) +LoadDLLfunc (send, 16, ws2_32) +LoadDLLfunc (sendto, 24, ws2_32) +LoadDLLfunc (setsockopt, 20, ws2_32) +LoadDLLfunc (shutdown, 8, ws2_32) +LoadDLLfunc (socket, 12, ws2_32) +LoadDLLfunc (WSAAsyncSelect, 16, ws2_32) +LoadDLLfunc (WSACloseEvent, 4, ws2_32) +LoadDLLfunc (WSACreateEvent, 0, ws2_32) +LoadDLLfunc (WSADuplicateSocketA, 12, ws2_32) +LoadDLLfunc (WSAGetLastError, 0, ws2_32) +LoadDLLfunc (WSAGetOverlappedResult, 20, ws2_32) +LoadDLLfunc (WSARecv, 28, ws2_32) +LoadDLLfunc (WSARecvFrom, 36, ws2_32) +LoadDLLfunc (WSASend, 28, ws2_32) +LoadDLLfunc (WSASendTo, 36, ws2_32) +LoadDLLfunc (WSASetEvent, 4, ws2_32) +LoadDLLfunc (WSASetLastError, 4, ws2_32) +LoadDLLfunc (WSASocketA, 24, ws2_32) +// LoadDLLfunc (WSAStartup, 8, ws2_32) +LoadDLLfunc (WSAWaitForMultipleEvents, 20, ws2_32) +LoadDLLfunc (WSAEventSelect, 12, ws2_32) +LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32) +LoadDLLfunc (__WSAFDIsSet, 8, ws2_32) + +LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1) +LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1) +LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1) +LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1) +LoadDLLfuncEx (GetTcpTable, 12, iphlpapi, 1) + +LoadDLLfunc (CoTaskMemFree, 4, ole32) + +LoadDLLfuncEx (CancelIo, 4, kernel32, 1) +LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1) +LoadDLLfuncEx (CreateToolhelp32Snapshot, 8, kernel32, 1) +LoadDLLfuncEx (FindFirstVolumeA, 8, kernel32, 1) +LoadDLLfuncEx (FindNextVolumeA, 12, kernel32, 1) +LoadDLLfuncEx (FindVolumeClose, 4, kernel32, 1) +LoadDLLfuncEx2 (GetCompressedFileSizeA, 8, kernel32, 1, 0xffffffff) +LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1) +LoadDLLfuncEx (GetDiskFreeSpaceEx, 16, kernel32, 1) +LoadDLLfuncEx (GetNativeSystemInfo, 4, kernel32, 1) +LoadDLLfuncEx (GetProcessWorkingSetSize, 12, kernel32, 1) +LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1) +LoadDLLfuncEx2 (IsDebuggerPresent, 0, kernel32, 1, 1) +LoadDLLfunc (IsProcessorFeaturePresent, 4, kernel32); +LoadDLLfuncEx (IsWow64Process, 8, kernel32, 1); +LoadDLLfuncEx (Process32First, 8, kernel32, 1) +LoadDLLfuncEx (Process32Next, 8, kernel32, 1) +LoadDLLfuncEx (RegisterServiceProcess, 8, kernel32, 1) +LoadDLLfuncEx (SetProcessWorkingSetSize, 12, kernel32, 1) +LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1) +LoadDLLfuncEx (SwitchToThread, 0, kernel32, 1) + +LoadDLLfunc (SHGetDesktopFolder, 4, shell32) + +LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1) +LoadDLLfuncEx (waveOutOpen, 24, winmm, 1) +LoadDLLfuncEx (waveOutReset, 4, winmm, 1) +LoadDLLfuncEx (waveOutClose, 4, winmm, 1) +LoadDLLfuncEx (waveOutGetVolume, 8, winmm, 1) +LoadDLLfuncEx (waveOutSetVolume, 8, winmm, 1) +LoadDLLfuncEx (waveOutUnprepareHeader, 12, winmm, 1) +LoadDLLfuncEx (waveOutPrepareHeader, 12, winmm, 1) +LoadDLLfuncEx (waveOutWrite, 12, winmm, 1) +LoadDLLfuncEx (timeGetDevCaps, 8, winmm, 1) +LoadDLLfuncEx (timeGetTime, 0, winmm, 1) +LoadDLLfuncEx (timeBeginPeriod, 4, winmm, 1) +LoadDLLfuncEx (timeEndPeriod, 4, winmm, 1) + +LoadDLLfuncEx (waveInGetNumDevs, 0, winmm, 1) +LoadDLLfuncEx (waveInOpen, 24, winmm, 1) +LoadDLLfuncEx (waveInUnprepareHeader, 12, winmm, 1) +LoadDLLfuncEx (waveInPrepareHeader, 12, winmm, 1) +LoadDLLfuncEx (waveInAddBuffer, 12, winmm, 1) +LoadDLLfuncEx (waveInStart, 4, winmm, 1) +LoadDLLfuncEx (waveInReset, 4, winmm, 1) +LoadDLLfuncEx (waveInClose, 4, winmm, 1) + +LoadDLLfunc (WNetGetResourceInformationA, 16, mpr) +LoadDLLfunc (WNetGetResourceParentA, 12, mpr) +LoadDLLfunc (WNetOpenEnumA, 20, mpr) +LoadDLLfunc (WNetEnumResourceA, 16, mpr) +LoadDLLfunc (WNetCloseEnum, 4, mpr) + +LoadDLLfuncEx (UuidCreate, 4, rpcrt4, 1) +LoadDLLfuncEx (UuidCreateSequential, 4, rpcrt4, 1) +} diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc new file mode 100644 index 00000000000..6dc9107b4cb --- /dev/null +++ b/winsup/cygwin/security.cc @@ -0,0 +1,1893 @@ +/* security.cc: NT security functions + + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + + Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de + Completely rewritten by Corinna Vinschen <corinna@vinschen.de> + +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. */ + +#include "winsup.h" +#include <grp.h> +#include <pwd.h> +#include <unistd.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <ctype.h> +#include <winnls.h> +#include <wingdi.h> +#include <winuser.h> +#include <wininet.h> +#include <ntsecapi.h> +#include <subauth.h> +#include <aclapi.h> +#include <dsgetdc.h> +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "pinfo.h" +#include "cygheap.h" +#include <ntdef.h> +#include "ntdll.h" +#include "lm.h" +#include "pwdgrp.h" + +bool allow_ntsec; +/* allow_smbntsec is handled exclusively in path.cc (path_conv::check). + It's defined here because of it's strong relationship to allow_ntsec. */ +bool allow_smbntsec; +bool allow_traverse; + +cygsid * +cygsidlist::alloc_sids (int n) +{ + if (n > 0) + return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid)); + else + return NULL; +} + +void +cygsidlist::free_sids () +{ + if (sids) + cfree (sids); + sids = NULL; + count = maxcount = 0; + type = cygsidlist_empty; +} + +extern "C" void +cygwin_set_impersonation_token (const HANDLE hToken) +{ + debug_printf ("set_impersonation_token (%d)", hToken); + cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken; +} + +void +extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) +{ + char *d, *u, *c; + + domain[0] = 0; + strlcpy (user, pw->pw_name, UNLEN + 1); + debug_printf ("pw_gecos %x (%s)", pw->pw_gecos, pw->pw_gecos); + + if ((d = strstr (pw->pw_gecos, "U-")) != NULL && + (d == pw->pw_gecos || d[-1] == ',')) + { + c = strechr (d + 2, ','); + if ((u = strechr (d + 2, '\\')) >= c) + u = d + 1; + else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2) + strlcpy (domain, d + 2, u - d - 1); + if (c - u <= UNLEN + 1) + strlcpy (user, u + 1, c - u); + } + if (domain[0]) + return; + + cygsid psid; + DWORD ulen = UNLEN + 1; + DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + SID_NAME_USE use; + if (psid.getfrompw (pw)) + LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use); +} + +extern "C" HANDLE +cygwin_logon_user (const struct passwd *pw, const char *password) +{ + if (!wincap.has_security ()) + { + set_errno (ENOSYS); + return INVALID_HANDLE_VALUE; + } + if (!pw) + { + set_errno (EINVAL); + return INVALID_HANDLE_VALUE; + } + + char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char nt_user[UNLEN + 1]; + HANDLE hToken; + + extract_nt_dom_user (pw, nt_domain, nt_user); + debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password); + /* CV 2005-06-08: LogonUser should run under the primary process token, + otherwise it returns with ERROR_ACCESS_DENIED on W2K. Don't ask me why. */ + RevertToSelf (); + if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password, + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hToken)) + { + __seterrno (); + hToken = INVALID_HANDLE_VALUE; + } + else if (!SetHandleInformation (hToken, + HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT)) + { + __seterrno (); + CloseHandle (hToken); + hToken = INVALID_HANDLE_VALUE; + } + cygheap->user.reimpersonate (); + debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name); + return hToken; +} + +static void +str2lsa (LSA_STRING &tgt, const char *srcstr) +{ + tgt.Length = strlen (srcstr); + tgt.MaximumLength = tgt.Length + 1; + tgt.Buffer = (PCHAR) srcstr; +} + +static void +str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr) +{ + tgt.Length = strlen (srcstr); + tgt.MaximumLength = tgt.Length + 1; + tgt.Buffer = (PCHAR) buf; + memcpy (buf, srcstr, tgt.MaximumLength); +} + +/* The dimension of buf is assumed to be at least strlen(srcstr) + 1, + The result will be shorter if the input has multibyte chars */ +void +str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr) +{ + tgt.Buffer = (PWCHAR) buf; + tgt.MaximumLength = (strlen (srcstr) + 1) * sizeof (WCHAR); + tgt.Length = sys_mbstowcs (buf, srcstr, tgt.MaximumLength / sizeof (WCHAR)) + * sizeof (WCHAR); + if (tgt.Length) + tgt.Length -= sizeof (WCHAR); +} + +void +str2uni_cat (UNICODE_STRING &tgt, const char *srcstr) +{ + int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR), srcstr, + (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR)); + if (len) + tgt.Length += (len - 1) * sizeof (WCHAR); + else + tgt.Length = tgt.MaximumLength = 0; +} + +static LSA_HANDLE +open_local_policy () +{ + LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 }; + LSA_HANDLE lsa = INVALID_HANDLE_VALUE; + + NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa); + if (ret != STATUS_SUCCESS) + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + return lsa; +} + +static void +close_local_policy (LSA_HANDLE &lsa) +{ + if (lsa != INVALID_HANDLE_VALUE) + LsaClose (lsa); + lsa = INVALID_HANDLE_VALUE; +} + +/* CV, 2006-07-06: Missing in w32api. */ +extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG, + PDOMAIN_CONTROLLER_INFOA *); +#define DS_FORCE_REDISCOVERY 1 + +bool +get_logon_server (const char *domain, char *server, WCHAR *wserver, + bool rediscovery) +{ + DWORD dret; + PDOMAIN_CONTROLLER_INFOA pci; + NET_API_STATUS nret; + WCHAR *buf; + DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1; + WCHAR wdomain[size]; + + /* Empty domain is interpreted as local system */ + if ((GetComputerName (server + 2, &size)) && + (strcasematch (domain, server + 2) || !domain[0])) + { + server[0] = server[1] = '\\'; + if (wserver) + sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1); + return true; + } + + /* Try to get any available domain controller for this domain */ + dret = DsGetDcNameA (NULL, domain, NULL, NULL, + rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci); + if (dret == ERROR_SUCCESS) + { + strcpy (server, pci->DomainControllerName); + sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1); + NetApiBufferFree (pci); + debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server); + return true; + } + else if (dret == ERROR_PROC_NOT_FOUND) + { + /* NT4 w/o DSClient */ + sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1); + if (rediscovery) + nret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf); + else + nret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf); + if (nret == NERR_Success) + { + sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf); + if (wserver) + for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);) + ; + NetApiBufferFree (buf); + debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server); + return true; + } + } + __seterrno_from_win_error (nret); + return false; +} + +static bool +get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, + char *domain) +{ + char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; + WCHAR wuser[UNLEN + 1]; + sys_mbstowcs (wuser, user, UNLEN + 1); + LPGROUP_USERS_INFO_0 buf; + DWORD cnt, tot, len; + NET_API_STATUS ret; + + /* Look only on logonserver */ + ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot); + if (ret) + { + __seterrno_from_win_error (ret); + /* It's no error when the user name can't be found. */ + return ret == NERR_UserNotFound; + } + + len = strlen (domain); + strcpy (dgroup, domain); + dgroup[len++] = '\\'; + + for (DWORD i = 0; i < cnt; ++i) + { + cygsid gsid; + DWORD glen = MAX_SID_LEN; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD dlen = sizeof (domain); + SID_NAME_USE use = SidTypeInvalid; + + sys_wcstombs (dgroup + len, GNLEN + 1, buf[i].grui0_name); + if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s), %E", dgroup); + else if (legal_sid_type (use)) + grp_list += gsid; + else + debug_printf ("Global group %s invalid. Domain: %s Use: %d", + dgroup, domain, use); + } + + NetApiBufferFree (buf); + return true; +} + +static bool +is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list) +{ + LPLOCALGROUP_MEMBERS_INFO_1 buf; + DWORD cnt, tot; + NET_API_STATUS ret; + + /* Members can be users or global groups */ + ret = NetLocalGroupGetMembers (NULL, wgroup, 1, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); + if (ret) + return false; + + bool retval = true; + for (DWORD bidx = 0; bidx < cnt; ++bidx) + if (EqualSid (pusersid, buf[bidx].lgrmi1_sid)) + goto done; + else + { + /* The extra test for the group being a global group or a well-known + group is necessary, since apparently also aliases (for instance + Administrators or Users) can be members of local groups, even + though MSDN states otherwise. The GUI refuses to put aliases into + local groups, but the CLI interface allows it. However, a normal + logon token does not contain groups, in which the user is only + indirectly a member by being a member of an alias in this group. + So we also should not put them into the token group list. + Note: Allowing those groups in our group list renders external + tokens invalid, so that it becomes impossible to logon with + password and valid logon token. */ + for (int glidx = 0; glidx < grp_list.count; ++glidx) + if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup + || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup) + && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid)) + goto done; + } + + retval = false; + done: + NetApiBufferFree (buf); + return retval; +} + +static bool +get_user_local_groups (cygsidlist &grp_list, PSID pusersid) +{ + LPLOCALGROUP_INFO_0 buf; + DWORD cnt, tot; + NET_API_STATUS ret; + + ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf, + MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); + if (ret) + { + __seterrno_from_win_error (ret); + return false; + } + + char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; + char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; + DWORD blen, llen; + SID_NAME_USE use; + + blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1; + if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use) + || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1))) + { + __seterrno (); + return false; + } + bgroup[blen++] = lgroup[llen++] = '\\'; + + for (DWORD i = 0; i < cnt; ++i) + if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list)) + { + cygsid gsid; + DWORD glen = MAX_SID_LEN; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + DWORD dlen = sizeof (domain); + + use = SidTypeInvalid; + sys_wcstombs (bgroup + blen, GNLEN + 1, buf[i].lgrpi0_name); + if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use)) + { + if (GetLastError () != ERROR_NONE_MAPPED) + debug_printf ("LookupAccountName(%s), %E", bgroup); + strcpy (lgroup + llen, bgroup + blen); + if (!LookupAccountName (NULL, lgroup, gsid, &glen, + domain, &dlen, &use)) + debug_printf ("LookupAccountName(%s), %E", lgroup); + } + if (!legal_sid_type (use)) + debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use); + else if (!grp_list.contains (gsid)) + grp_list += gsid; + } + NetApiBufferFree (buf); + return true; +} + +static bool +sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid) +{ + if (!grps) + return false; + for (DWORD i = 0; i < grps->GroupCount; ++i) + if (sid == grps->Groups[i].Sid) + return true; + return false; +} + +#if 0 /* Unused */ +static BOOL +get_user_primary_group (WCHAR *wlogonserver, const char *user, + PSID pusersid, cygsid &pgrpsid) +{ + LPUSER_INFO_3 buf; + WCHAR wuser[UNLEN + 1]; + NET_API_STATUS ret; + BOOL retval = FALSE; + UCHAR count = 0; + + if (well_known_system_sid == pusersid) + { + pgrpsid = well_known_system_sid; + return TRUE; + } + + sys_mbstowcs (wuser, user, UNLEN + 1); + ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf); + if (ret) + { + __seterrno_from_win_error (ret); + return FALSE; + } + + pgrpsid = pusersid; + if (IsValidSid (pgrpsid) + && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) + { + *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; + retval = TRUE; + } + NetApiBufferFree (buf); + return retval; +} +#endif + +static void +get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list) +{ + struct __group32 *gr; + cygsid gsid; + + for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) + { + if (gr->gr_gid == (__gid32_t) pw->pw_gid) + goto found; + else if (gr->gr_mem) + for (int gi = 0; gr->gr_mem[gi]; ++gi) + if (strcasematch (pw->pw_name, gr->gr_mem[gi])) + goto found; + continue; + found: + if (gsid.getfromgr (gr) && !grp_list.contains (gsid)) + grp_list += gsid; + + } +} + +static void +get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, + LUID auth_luid, int &auth_pos) +{ + auth_pos = -1; + if (my_grps) + { + if (sid_in_token_groups (my_grps, well_known_local_sid)) + grp_list += well_known_local_sid; + if (sid_in_token_groups (my_grps, well_known_dialup_sid)) + grp_list += well_known_dialup_sid; + if (sid_in_token_groups (my_grps, well_known_network_sid)) + grp_list += well_known_network_sid; + if (sid_in_token_groups (my_grps, well_known_batch_sid)) + grp_list += well_known_batch_sid; + if (sid_in_token_groups (my_grps, well_known_interactive_sid)) + grp_list += well_known_interactive_sid; + if (sid_in_token_groups (my_grps, well_known_service_sid)) + grp_list += well_known_service_sid; + } + else + { + grp_list += well_known_local_sid; + grp_list += well_known_interactive_sid; + } + if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */ + { + char buf[64]; + __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart, + auth_luid.LowPart); + grp_list += buf; + auth_pos = grp_list.count - 1; + } +} + +bool +get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw) +{ + char user[UNLEN + 1]; + char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + + if (well_known_system_sid == usersid) + { + grp_list += well_known_admins_sid; + get_unix_group_sidlist (pw, grp_list); + return true; + } + + grp_list += well_known_world_sid; + grp_list += well_known_authenticated_users_sid; + extract_nt_dom_user (pw, domain, user); + if (get_logon_server (domain, server, wserver, false) + && !get_user_groups (wserver, grp_list, user, domain) + && get_logon_server (domain, server, wserver, true)) + get_user_groups (wserver, grp_list, user, domain); + get_unix_group_sidlist (pw, grp_list); + return get_user_local_groups (grp_list, usersid); +} + +static bool +get_initgroups_sidlist (cygsidlist &grp_list, + PSID usersid, PSID pgrpsid, struct passwd *pw, + PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos) +{ + grp_list += well_known_world_sid; + grp_list += well_known_authenticated_users_sid; + if (well_known_system_sid == usersid) + auth_pos = -1; + else + get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos); + if (!get_server_groups (grp_list, usersid, pw)) + return false; + + /* special_pgrp true if pgrpsid is not in normal groups */ + if (!grp_list.contains (pgrpsid)) + grp_list += pgrpsid; + return true; +} + +static void +get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps, + user_groups &groups, LUID auth_luid, int &auth_pos) +{ + PSID pgpsid = groups.pgsid; + tmp_list += well_known_world_sid; + tmp_list += well_known_authenticated_users_sid; + get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos); + for (int gidx = 0; gidx < groups.sgsids.count; gidx++) + if (!tmp_list.contains (groups.sgsids.sids[gidx])) + tmp_list += groups.sgsids.sids[gidx]; + if (!groups.sgsids.contains (pgpsid)) + tmp_list += pgpsid; +} + +static const cygpriv_idx sys_privs[] = { + SE_TCB_PRIV, + SE_ASSIGNPRIMARYTOKEN_PRIV, + SE_CREATE_TOKEN_PRIV, + SE_CHANGE_NOTIFY_PRIV, + SE_SECURITY_PRIV, + SE_BACKUP_PRIV, + SE_RESTORE_PRIV, + SE_SYSTEMTIME_PRIV, + SE_SHUTDOWN_PRIV, + SE_REMOTE_SHUTDOWN_PRIV, + SE_TAKE_OWNERSHIP_PRIV, + SE_DEBUG_PRIV, + SE_SYSTEM_ENVIRONMENT_PRIV, + SE_SYSTEM_PROFILE_PRIV, + SE_PROF_SINGLE_PROCESS_PRIV, + SE_INC_BASE_PRIORITY_PRIV, + SE_LOAD_DRIVER_PRIV, + SE_CREATE_PAGEFILE_PRIV, + SE_INCREASE_QUOTA_PRIV, + SE_LOCK_MEMORY_PRIV, + SE_CREATE_PERMANENT_PRIV, + SE_AUDIT_PRIV, + SE_UNDOCK_PRIV, + SE_MANAGE_VOLUME_PRIV, + SE_IMPERSONATE_PRIV, + SE_CREATE_GLOBAL_PRIV +}; + +#define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs) + +PTOKEN_PRIVILEGES +get_system_priv_list (cygsidlist &grp_list) +{ + const LUID *priv; + PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) + malloc (sizeof (ULONG) + + SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES)); + if (!privs) + { + debug_printf ("malloc (system_privs) failed."); + return NULL; + } + privs->PrivilegeCount = 0; + + for (DWORD i = 0; i < SYSTEM_PRIVILEGES_COUNT; ++i) + if ((priv = privilege_luid (sys_privs[i]))) + { + privs->Privileges[privs->PrivilegeCount].Luid = *priv; + privs->Privileges[privs->PrivilegeCount].Attributes = + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + ++privs->PrivilegeCount; + } + return privs; +} + +PTOKEN_PRIVILEGES +get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) +{ + PLSA_UNICODE_STRING privstrs; + ULONG cnt; + PTOKEN_PRIVILEGES privs = NULL; + NTSTATUS ret; + char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + + if (usersid == well_known_system_sid) + return get_system_priv_list (grp_list); + + for (int grp = -1; grp < grp_list.count; ++grp) + { + if (grp == -1) + { + if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, + &cnt)) != STATUS_SUCCESS) + continue; + } + else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], + &privstrs, &cnt)) + != STATUS_SUCCESS) + continue; + for (ULONG i = 0; i < cnt; ++i) + { + const LUID *priv; + PTOKEN_PRIVILEGES tmp; + DWORD tmp_count; + + sys_wcstombs (buf, sizeof (buf), + privstrs[i].Buffer, privstrs[i].Length / 2); + if (!(priv = privilege_luid_by_name (buf))) + continue; + + if (privs) + { + DWORD pcnt = privs->PrivilegeCount; + LUID_AND_ATTRIBUTES *p = privs->Privileges; + for (; pcnt > 0; --pcnt, ++p) + if (priv->HighPart == p->Luid.HighPart + && priv->LowPart == p->Luid.LowPart) + goto next_account_right; + } + + tmp_count = privs ? privs->PrivilegeCount : 0; + tmp = (PTOKEN_PRIVILEGES) + realloc (privs, sizeof (ULONG) + + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); + if (!tmp) + { + if (privs) + free (privs); + LsaFreeMemory (privstrs); + debug_printf ("realloc (privs) failed."); + return NULL; + } + tmp->PrivilegeCount = tmp_count; + privs = tmp; + privs->Privileges[privs->PrivilegeCount].Luid = *priv; + privs->Privileges[privs->PrivilegeCount].Attributes = + SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; + ++privs->PrivilegeCount; + + next_account_right: + ; + } + LsaFreeMemory (privstrs); + } + return privs; +} + +/* Accept a token if + - the requested usersid matches the TokenUser and + - if setgroups has been called: + the token groups that are listed in /etc/group match the union of + the requested primary and supplementary groups in gsids. + - else the (unknown) implicitly requested supplementary groups and those + in the token are the groups associated with the usersid. We assume + they match and verify only the primary groups. + The requested primary group must appear in the token. + The primary group in the token is a group associated with the usersid, + except if the token is internal and the group is in the token SD + (see create_token). In that latter case that group must match the + requested primary group. */ +bool +verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) +{ + DWORD size; + bool intern = false; + + if (pintern) + { + TOKEN_SOURCE ts; + if (!GetTokenInformation (token, TokenSource, + &ts, sizeof ts, &size)) + debug_printf ("GetTokenInformation(), %E"); + else + *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); + } + /* Verify usersid */ + cygsid tok_usersid = NO_SID; + if (!GetTokenInformation (token, TokenUser, + &tok_usersid, sizeof tok_usersid, &size)) + debug_printf ("GetTokenInformation(), %E"); + if (usersid != tok_usersid) + return false; + + /* For an internal token, if setgroups was not called and if the sd group + is not well_known_null_sid, it must match pgrpsid */ + if (intern && !groups.issetgroups ()) + { + const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR); + PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz); + cygpsid gsid (NO_SID); + if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION, + sd_buf, sd_buf_siz, &size)) + debug_printf ("GetKernelObjectSecurity(), %E"); + else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid, + (BOOL *) &size)) + debug_printf ("GetSecurityDescriptorGroup(), %E"); + if (well_known_null_sid != gsid) + return gsid == groups.pgsid; + } + + PTOKEN_GROUPS my_grps; + bool sawpg = false, ret = false; + + if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + debug_printf ("GetTokenInformation(token, TokenGroups), %E"); + else if (!(my_grps = (PTOKEN_GROUPS) alloca (size))) + debug_printf ("alloca (my_grps) failed."); + else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size)) + debug_printf ("GetTokenInformation(my_token, TokenGroups), %E"); + else + { + if (groups.issetgroups ()) /* setgroups was called */ + { + cygsid gsid; + struct __group32 *gr; + bool saw[groups.sgsids.count]; + memset (saw, 0, sizeof(saw)); + + /* token groups found in /etc/group match the user.gsids ? */ + for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) + if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid)) + { + int pos = groups.sgsids.position (gsid); + if (pos >= 0) + saw[pos] = true; + else if (groups.pgsid == gsid) + sawpg = true; + else if (gsid != well_known_world_sid + && gsid != usersid) + goto done; + } + /* user.sgsids groups must be in the token */ + for (int gidx = 0; gidx < groups.sgsids.count; gidx++) + if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx])) + goto done; + } + /* The primary group must be in the token */ + ret = sawpg + || sid_in_token_groups (my_grps, groups.pgsid) + || groups.pgsid == usersid; + } +done: + return ret; +} + +HANDLE +create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) +{ + NTSTATUS ret; + LSA_HANDLE lsa = INVALID_HANDLE_VALUE; + + cygsidlist tmp_gsids (cygsidlist_auto, 12); + + SECURITY_QUALITY_OF_SERVICE sqos = + { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; + OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos }; + LUID auth_luid = SYSTEM_LUID; + LARGE_INTEGER exp = { QuadPart:INT64_MAX }; + + TOKEN_USER user; + PTOKEN_GROUPS new_tok_gsids = NULL; + PTOKEN_PRIVILEGES privs = NULL; + TOKEN_OWNER owner; + TOKEN_PRIMARY_GROUP pgrp; + TOKEN_DEFAULT_DACL dacl = {}; + TOKEN_SOURCE source; + TOKEN_STATISTICS stats; + memcpy (source.SourceName, "Cygwin.1", 8); + source.SourceIdentifier.HighPart = 0; + source.SourceIdentifier.LowPart = 0x0101; + + HANDLE token = INVALID_HANDLE_VALUE; + HANDLE primary_token = INVALID_HANDLE_VALUE; + + PTOKEN_GROUPS my_tok_gsids = NULL; + DWORD size; + + /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ + push_self_privilege (SE_CREATE_TOKEN_PRIV, true); + + /* Open policy object. */ + if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE) + goto out; + + /* User, owner, primary group. */ + user.User.Sid = usersid; + user.User.Attributes = 0; + owner.Owner = usersid; + + /* Retrieve authentication id and group list from own process. */ + if (hProcToken) + { + /* Switching user context to SYSTEM doesn't inherit the authentication + id of the user account running current process. */ + if (usersid != well_known_system_sid) + if (!GetTokenInformation (hProcToken, TokenStatistics, + &stats, sizeof stats, &size)) + debug_printf + ("GetTokenInformation(hProcToken, TokenStatistics), %E"); + else + auth_luid = stats.AuthenticationId; + + /* Retrieving current processes group list to be able to inherit + some important well known group sids. */ + if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E"); + else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size))) + debug_printf ("malloc (my_tok_gsids) failed."); + else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids, + size, &size)) + { + debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E"); + free (my_tok_gsids); + my_tok_gsids = NULL; + } + } + + /* Create list of groups, the user is member in. */ + int auth_pos; + if (new_groups.issetgroups ()) + get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid, + auth_pos); + else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw, + my_tok_gsids, auth_luid, auth_pos)) + goto out; + + /* Primary group. */ + pgrp.PrimaryGroup = new_groups.pgsid; + + /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ + char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)]; + new_tok_gsids = (PTOKEN_GROUPS) grps_buf; + new_tok_gsids->GroupCount = tmp_gsids.count; + for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i) + { + new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i]; + new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; + } + if (auth_pos >= 0) + new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; + + /* Retrieve list of privileges of that user. */ + if (!(privs = get_priv_list (lsa, usersid, tmp_gsids))) + goto out; + + /* Let's be heroic... */ + ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, + &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, + &pgrp, &dacl, &source); + if (ret) + __seterrno_from_nt_status (ret); + else if (GetLastError () == ERROR_PROC_NOT_FOUND) + { + __seterrno (); + debug_printf ("Loading NtCreateToken failed."); + } + else + { + /* Convert to primary token. */ + if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none, + SecurityImpersonation, TokenPrimary, + &primary_token)) + { + __seterrno (); + debug_printf ("DuplicateTokenEx %E"); + } + } + +out: + pop_self_privilege (); + if (token != INVALID_HANDLE_VALUE) + CloseHandle (token); + if (privs) + free (privs); + if (my_tok_gsids) + free (my_tok_gsids); + close_local_policy (lsa); + + debug_printf ("%d = create_token ()", primary_token); + return primary_token; +} + +int subauth_id = 255; + +HANDLE +subauth (struct passwd *pw) +{ + LSA_STRING name; + HANDLE lsa_hdl; + LSA_OPERATIONAL_MODE sec_mode; + NTSTATUS ret, ret2; + ULONG package_id, size; + struct { + LSA_STRING str; + CHAR buf[16]; + } origin; + struct { + MSV1_0_LM20_LOGON auth; + WCHAR dombuf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR usrbuf[UNLEN + 1]; + WCHAR wkstbuf[1]; + CHAR authinf1[1]; + CHAR authinf2[1]; + } subbuf; + TOKEN_SOURCE ts; + PMSV1_0_LM20_LOGON_PROFILE profile; + LUID luid; + QUOTA_LIMITS quota; + char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + char nt_user[UNLEN + 1]; + HANDLE user_token = INVALID_HANDLE_VALUE; + HANDLE primary_token = INVALID_HANDLE_VALUE; + + push_self_privilege (SE_TCB_PRIV, true); + + /* Register as logon process. */ + str2lsa (name, "Cygwin"); + SetLastError (0); + ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaRegisterLogonProcess: %d", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + goto out; + } + else if (GetLastError () == ERROR_PROC_NOT_FOUND) + { + debug_printf ("Couldn't load Secur32.dll"); + goto out; + } + /* Get handle to MSV1_0 package. */ + str2lsa (name, MSV1_0_PACKAGE_NAME); + ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaLookupAuthenticationPackage: %d", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + LsaDeregisterLogonProcess (lsa_hdl); + goto out; + } + /* Create origin. */ + str2buf2lsa (origin.str, origin.buf, "Cygwin"); + /* Create token source. */ + memcpy (ts.SourceName, "Cygwin.1", 8); + ts.SourceIdentifier.HighPart = 0; + ts.SourceIdentifier.LowPart = 0x0100; + /* Get user information. */ + extract_nt_dom_user (pw, nt_domain, nt_user); + /* Fill subauth with values. */ + subbuf.auth.MessageType = MsV1_0NetworkLogon; + str2buf2uni (subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain); + str2buf2uni (subbuf.auth.UserName, subbuf.usrbuf, nt_user); + str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, ""); + memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH); + str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, ""); + str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,""); + subbuf.auth.ParameterControl = 0 | (subauth_id << 24); + /* Try to logon... */ + ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network, + package_id, &subbuf, sizeof subbuf, + NULL, &ts, (PVOID *) &profile, &size, + &luid, &user_token, "a, &ret2); + if (ret != STATUS_SUCCESS) + { + debug_printf ("LsaLogonUser: %d", ret); + __seterrno_from_win_error (LsaNtStatusToWinError (ret)); + LsaDeregisterLogonProcess (lsa_hdl); + goto out; + } + LsaFreeReturnBuffer (profile); + /* Convert to primary token. */ + if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sec_none, + SecurityImpersonation, TokenPrimary, &primary_token)) + __seterrno (); + +out: + pop_self_privilege (); + if (user_token != INVALID_HANDLE_VALUE) + CloseHandle (user_token); + return primary_token; +} + +/* read_sd reads a security descriptor from a file. + In case of error, -1 is returned and errno is set. + If sd_buf is too small, 0 is returned and sd_size + is set to the needed buffer size. + On success, 1 is returned. + + GetFileSecurity() is used instead of BackupRead() + to avoid access denied errors if the caller has + not the permission to open that file for read. + + Originally the function should return the size + of the SD on success. Unfortunately NT returns + 0 in `len' on success, while W2K returns the + correct size! + + 2003-11-26: Now the function allocates the space needed by itself so + it knows the real size and returns it in the security_descriptor object. +*/ + +LONG +read_sd (const char *file, security_descriptor &sd) +{ + + DWORD len = 0; + const char *pfile = file; + char fbuf[CYG_MAX_PATH]; + if (current_codepage == oem_cp) + { + DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file)); + bzero (fbuf, sizeof (fbuf)); + OemToCharBuff (file, fbuf, fname_len); + pfile = fbuf; + } + + if (!GetFileSecurity (pfile, + OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION, + NULL, 0, &len) + && GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + debug_printf ("file %s", file); + __seterrno (); + return -1; + } + debug_printf ("file %s: len %d", file, len); + if (!sd.malloc (len)) + { + set_errno (ENOMEM); + return -1; + } + if (!GetFileSecurity (pfile, + OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION, + sd, len, &len)) + { + __seterrno (); + return -1; + } + return sd.size (); +} + +LONG +write_sd (HANDLE fh, const char *file, security_descriptor &sd) +{ + NTSTATUS ret = STATUS_SUCCESS; + int retry = 0; + int res = -1; + for (; retry < 2; ++retry) + { + if (retry && (fh = CreateFile (file, WRITE_OWNER | WRITE_DAC, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL + | FILE_FLAG_BACKUP_SEMANTICS, + NULL)) == INVALID_HANDLE_VALUE) + break; + if (fh && (ret = NtSetSecurityObject (fh, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd)) == STATUS_SUCCESS) + break; + } + if (retry && fh != INVALID_HANDLE_VALUE) + CloseHandle (fh); + if (fh == INVALID_HANDLE_VALUE) /* CreateFile failed */ + __seterrno (); + else if (ret != STATUS_SUCCESS) /* NtSetSecurityObject failed */ + __seterrno_from_nt_status (ret); + else /* Everything's fine. */ + res = 0; + return res; +} + +static void +get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid, + PSID group_sid, bool grp_member) +{ + ACCESS_ALLOWED_ACE *ace; + int allow = 0; + int deny = 0; + int *flags, *anti; + + for (DWORD i = 0; i < acl->AceCount; ++i) + { + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + if (ace->Header.AceFlags & INHERIT_ONLY) + continue; + switch (ace->Header.AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + flags = &allow; + anti = &deny; + break; + case ACCESS_DENIED_ACE_TYPE: + flags = &deny; + anti = &allow; + break; + default: + continue; + } + + cygpsid ace_sid ((PSID) &ace->SidStart); + if (ace_sid == well_known_world_sid) + { + if (ace->Mask & FILE_READ_BITS) + *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0) + | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) + | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_BITS) + *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0) + | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) + | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXEC_BITS) + *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0) + | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) + | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); + if ((S_ISDIR (*attribute)) && + (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD)) + == (FILE_WRITE_DATA | FILE_EXECUTE)) + *flags |= S_ISVTX; + } + else if (ace_sid == well_known_null_sid) + { + /* Read SUID, SGID and VTX bits from NULL ACE. */ + if (ace->Mask & FILE_READ_DATA) + *flags |= S_ISVTX; + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_ISGID; + if (ace->Mask & FILE_APPEND_DATA) + *flags |= S_ISUID; + } + else if (ace_sid == owner_sid) + { + if (ace->Mask & FILE_READ_BITS) + *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_BITS) + *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXEC_BITS) + *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + else if (ace_sid == group_sid) + { + if (ace->Mask & FILE_READ_BITS) + *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) + | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_BITS) + *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) + | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXEC_BITS) + *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) + | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + } + *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); + if (owner_sid && group_sid && EqualSid (owner_sid, group_sid) + /* FIXME: temporary exception for /var/empty */ + && well_known_system_sid != group_sid) + { + allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP); + allow |= (((allow & S_IRUSR) ? S_IRGRP : 0) + | ((allow & S_IWUSR) ? S_IWGRP : 0) + | ((allow & S_IXUSR) ? S_IXGRP : 0)); + } + *attribute |= allow; +} + +static void +get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute, + __uid32_t *uidret, __gid32_t *gidret) +{ + if (!psd) + { + /* If reading the security descriptor failed, treat the object + as unreadable. */ + if (attribute) + *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); + if (uidret) + *uidret = ILLEGAL_UID; + if (gidret) + *gidret = ILLEGAL_GID; + return; + } + + cygpsid owner_sid; + cygpsid group_sid; + BOOL dummy; + + if (!GetSecurityDescriptorOwner (psd, (PSID *) &owner_sid, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %E"); + if (!GetSecurityDescriptorGroup (psd, (PSID *) &group_sid, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %E"); + + __uid32_t uid; + __gid32_t gid; + bool grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid); + if (uidret) + *uidret = uid; + if (gidret) + *gidret = gid; + + if (!attribute) + { + syscall_printf ("uid %d, gid %d", uid, gid); + return; + } + + PACL acl; + BOOL acl_exists; + + if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) + { + __seterrno (); + debug_printf ("GetSecurityDescriptorDacl %E"); + *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); + } + else if (!acl_exists || !acl) + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + else + get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member); + + syscall_printf ("%sACL %x, uid %d, gid %d", + (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid); +} + +static void +get_nt_attribute (const char *file, mode_t *attribute, + __uid32_t *uidret, __gid32_t *gidret) +{ + security_descriptor sd; + + if (read_sd (file, sd) <= 0) + debug_printf ("read_sd %E"); + get_info_from_sd (sd, attribute, uidret, gidret); +} + +static int +get_reg_security (HANDLE handle, security_descriptor &sd_ret) +{ + LONG ret; + DWORD len = 0; + + ret = RegGetKeySecurity ((HKEY) handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, &len); + if (ret == ERROR_INSUFFICIENT_BUFFER) + { + if (!sd_ret.malloc (len)) + set_errno (ENOMEM); + else + ret = RegGetKeySecurity ((HKEY) handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, &len); + } + if (ret != ERROR_SUCCESS) + { + __seterrno (); + return -1; + } + return 0; +} + +int +get_nt_object_security (HANDLE handle, SE_OBJECT_TYPE object_type, + security_descriptor &sd_ret) +{ + NTSTATUS ret; + ULONG len = 0; + + /* Unfortunately, NtQuerySecurityObject doesn't work on predefined registry + keys like HKEY_LOCAL_MACHINE. It fails with "Invalid Handle". So we + have to retreat to the Win32 registry functions for registry keys. + What bugs me is that RegGetKeySecurity is obviously just a wrapper + around NtQuerySecurityObject, but there seems to be no function to + convert pseudo HKEY values to real handles. */ + if (object_type == SE_REGISTRY_KEY) + return get_reg_security (handle, sd_ret); + + ret = NtQuerySecurityObject (handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, len, &len); + if (ret == STATUS_BUFFER_TOO_SMALL) + { + if (!sd_ret.malloc (len)) + set_errno (ENOMEM); + else + ret = NtQuerySecurityObject (handle, + DACL_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION, + sd_ret, len, &len); + } + if (ret != STATUS_SUCCESS) + { + __seterrno_from_nt_status (ret); + return -1; + } + return 0; +} + +static int +get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, + mode_t *attribute, __uid32_t *uidret, + __gid32_t *gidret) +{ + security_descriptor sd; + PSECURITY_DESCRIPTOR psd = NULL; + + if (get_nt_object_security (handle, object_type, sd)) + { + if (object_type == SE_FILE_OBJECT) + return -1; + } + else + psd = sd; + get_info_from_sd (psd, attribute, uidret, gidret); + return 0; +} + +int +get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, + mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) +{ + if (allow_ntsec) + { + get_nt_object_attribute (handle, object_type, attribute, uidret, gidret); + return 0; + } + /* The entries are already set to default values */ + return -1; +} + +int +get_file_attribute (int use_ntsec, HANDLE handle, const char *file, + mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) +{ + int res; + syscall_printf ("file: %s", file); + + if (use_ntsec && allow_ntsec) + { + if (!handle || get_nt_object_attribute (handle, SE_FILE_OBJECT, + attribute, uidret, gidret)) + get_nt_attribute (file, attribute, uidret, gidret); + return 0; + } + + if (uidret) + *uidret = myself->uid; + if (gidret) + *gidret = myself->gid; + + if (!attribute) + return 0; + + if (allow_ntea) + { + int oatt = *attribute; + res = read_ea (handle, file, ".UNIXATTR", (char *)attribute, + sizeof (*attribute)); + *attribute |= oatt; + } + else + res = 0; + + return res > 0 ? 0 : -1; +} + +bool +add_access_allowed_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return false; + } + ACCESS_ALLOWED_ACE *ace; + if (inherit && GetAce (acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (sid); + return true; +} + +bool +add_access_denied_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return false; + } + ACCESS_DENIED_ACE *ace; + if (inherit && GetAce (acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); + return true; +} + +static PSECURITY_DESCRIPTOR +alloc_sd (__uid32_t uid, __gid32_t gid, int attribute, + security_descriptor &sd_ret) +{ + BOOL dummy; + + debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute); + + /* Get owner and group from current security descriptor. */ + PSID cur_owner_sid = NULL; + PSID cur_group_sid = NULL; + if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %E"); + if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %E"); + + /* Get SID of owner. */ + cygsid owner_sid; + /* Check for current user first */ + if (uid == myself->uid) + owner_sid = cygheap->user.sid (); + else if (uid == ILLEGAL_UID) + owner_sid = cur_owner_sid; + else if (!owner_sid.getfrompw (internal_getpwuid (uid))) + { + set_errno (EINVAL); + return NULL; + } + owner_sid.debug_print ("alloc_sd: owner SID ="); + + /* Get SID of new group. */ + cygsid group_sid; + /* Check for current user first */ + if (gid == myself->gid) + group_sid = cygheap->user.groups.pgsid; + else if (gid == ILLEGAL_GID) + group_sid = cur_group_sid; + else if (!group_sid.getfromgr (internal_getgrgid (gid))) + { + set_errno (EINVAL); + return NULL; + } + group_sid.debug_print ("alloc_sd: group SID ="); + + /* Initialize local security descriptor. */ + SECURITY_DESCRIPTOR sd; + if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + __seterrno (); + return NULL; + } + + /* + * We set the SE_DACL_PROTECTED flag here to prevent the DACL from being + * modified by inheritable ACEs. + * This flag as well as the SetSecurityDescriptorControl call are available + * only since Win2K. + */ + if (wincap.has_security_descriptor_control ()) + SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); + + /* Create owner for local security descriptor. */ + if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE)) + { + __seterrno (); + return NULL; + } + + /* Create group for local security descriptor. */ + if (!SetSecurityDescriptorGroup (&sd, group_sid, FALSE)) + { + __seterrno (); + return NULL; + } + + /* Initialize local access control list. */ + PACL acl = (PACL) alloca (3072); + if (!InitializeAcl (acl, 3072, ACL_REVISION)) + { + __seterrno (); + return NULL; + } + + /* From here fill ACL. */ + size_t acl_len = sizeof (ACL); + int ace_off = 0; + + /* Construct allow attribute for owner. */ + DWORD owner_allow = STANDARD_RIGHTS_ALL + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; + /* This has nothing to do with traverse checking in the first place, but + since traverse checking is the setting which switches to POSIX-like + permission rules, the below is all too similar. Removing the delete + bit for a file or directory results in checking the parent directories' + ACL, if the current user has the FILE_DELETE_CHILD bit set. This is + how it is on POSIX systems. */ + if (allow_traverse) + owner_allow &= ~DELETE; + if (attribute & S_IRUSR) + owner_allow |= FILE_GENERIC_READ; + if (attribute & S_IWUSR) + owner_allow |= FILE_GENERIC_WRITE; + if (attribute & S_IXUSR) + owner_allow |= FILE_GENERIC_EXECUTE; + if (S_ISDIR (attribute) + && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)) + owner_allow |= FILE_DELETE_CHILD; + + /* Construct allow attribute for group. */ + DWORD group_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IRGRP) + group_allow |= FILE_GENERIC_READ; + if (attribute & S_IWGRP) + group_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; + if (attribute & S_IXGRP) + group_allow |= FILE_GENERIC_EXECUTE; + if (S_ISDIR (attribute) + && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP) + && !(attribute & S_ISVTX)) + group_allow |= FILE_DELETE_CHILD; + + /* Construct allow attribute for everyone. */ + DWORD other_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IROTH) + other_allow |= FILE_GENERIC_READ; + if (attribute & S_IWOTH) + other_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; + if (attribute & S_IXOTH) + other_allow |= FILE_GENERIC_EXECUTE; + if (S_ISDIR (attribute) + && (attribute & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) + && !(attribute & S_ISVTX)) + other_allow |= FILE_DELETE_CHILD; + + /* Construct SUID, SGID and VTX bits in NULL ACE. */ + DWORD null_allow = 0L; + if (attribute & (S_ISUID | S_ISGID | S_ISVTX)) + { + if (attribute & S_ISUID) + null_allow |= FILE_APPEND_DATA; + if (attribute & S_ISGID) + null_allow |= FILE_WRITE_DATA; + if (attribute & S_ISVTX) + null_allow |= FILE_READ_DATA; + } + + /* Add owner and group permissions if SIDs are equal + and construct deny attributes for group and owner. */ + bool isownergroup; + if ((isownergroup = (owner_sid == group_sid))) + owner_allow |= group_allow; + + DWORD owner_deny = ~owner_allow & (group_allow | other_allow); + owner_deny &= ~(STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA); + + DWORD group_deny = ~group_allow & other_allow; + group_deny &= ~(STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA); + + /* Set deny ACE for owner. */ + if (owner_deny + && !add_access_denied_ace (acl, ace_off++, owner_deny, + owner_sid, acl_len, NO_INHERITANCE)) + return NULL; + /* Set deny ACE for group here to respect the canonical order, + if this does not impact owner */ + if (group_deny && !(group_deny & owner_allow) && !isownergroup + && !add_access_denied_ace (acl, ace_off++, group_deny, + group_sid, acl_len, NO_INHERITANCE)) + return NULL; + /* Set allow ACE for owner. */ + if (!add_access_allowed_ace (acl, ace_off++, owner_allow, + owner_sid, acl_len, NO_INHERITANCE)) + return NULL; + /* Set deny ACE for group, if still needed. */ + if (group_deny & owner_allow && !isownergroup + && !add_access_denied_ace (acl, ace_off++, group_deny, + group_sid, acl_len, NO_INHERITANCE)) + return NULL; + /* Set allow ACE for group. */ + if (!isownergroup + && !add_access_allowed_ace (acl, ace_off++, group_allow, + group_sid, acl_len, NO_INHERITANCE)) + return NULL; + + /* Set allow ACE for everyone. */ + if (!add_access_allowed_ace (acl, ace_off++, other_allow, + well_known_world_sid, acl_len, NO_INHERITANCE)) + return NULL; + /* Set null ACE for special bits. */ + if (null_allow + && !add_access_allowed_ace (acl, ace_off++, null_allow, + well_known_null_sid, acl_len, NO_INHERITANCE)) + return NULL; + + /* Fill ACL with unrelated ACEs from current security descriptor. */ + PACL oacl; + BOOL acl_exists = FALSE; + ACCESS_ALLOWED_ACE *ace; + if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) + && acl_exists && oacl) + for (DWORD i = 0; i < oacl->AceCount; ++i) + if (GetAce (oacl, i, (PVOID *) &ace)) + { + cygpsid ace_sid ((PSID) &ace->SidStart); + + /* Check for related ACEs. */ + if (ace_sid == well_known_null_sid) + continue; + if ((ace_sid == cur_owner_sid) + || (ace_sid == owner_sid) + || (ace_sid == cur_group_sid) + || (ace_sid == group_sid) + || (ace_sid == well_known_world_sid)) + { + if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT) + ace->Header.AceFlags |= INHERIT_ONLY; + else + continue; + } + /* + * Add unrelated ACCESS_DENIED_ACE to the beginning but + * behind the owner_deny, ACCESS_ALLOWED_ACE to the end. + * FIXME: this would break the order of the inherit_only ACEs + */ + if (!AddAce (acl, ACL_REVISION, + ace->Header.AceType == ACCESS_DENIED_ACE_TYPE? + (owner_deny ? 1 : 0) : MAXDWORD, + (LPVOID) ace, ace->Header.AceSize)) + { + __seterrno (); + return NULL; + } + acl_len += ace->Header.AceSize; + } + + /* Construct appropriate inherit attribute for new directories */ + if (S_ISDIR (attribute) && !acl_exists) + { + const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY; + +#if 0 /* FIXME: Not done currently as this breaks the canonical order */ + /* Set deny ACE for owner. */ + if (owner_deny + && !add_access_denied_ace (acl, ace_off++, owner_deny, + well_known_creator_owner_sid, acl_len, inherit)) + return NULL; + /* Set deny ACE for group here to respect the canonical order, + if this does not impact owner */ + if (group_deny && !(group_deny & owner_allow) + && !add_access_denied_ace (acl, ace_off++, group_deny, + well_known_creator_group_sid, acl_len, inherit)) + return NULL; +#endif + /* Set allow ACE for owner. */ + if (!add_access_allowed_ace (acl, ace_off++, owner_allow, + well_known_creator_owner_sid, acl_len, inherit)) + return NULL; +#if 0 /* FIXME: Not done currently as this breaks the canonical order and + won't be preserved on chown and chmod */ + /* Set deny ACE for group, conflicting with owner_allow. */ + if (group_deny & owner_allow + && !add_access_denied_ace (acl, ace_off++, group_deny, + well_known_creator_group_sid, acl_len, inherit)) + return NULL; +#endif + /* Set allow ACE for group. */ + if (!add_access_allowed_ace (acl, ace_off++, group_allow, + well_known_creator_group_sid, acl_len, inherit)) + return NULL; + /* Set allow ACE for everyone. */ + if (!add_access_allowed_ace (acl, ace_off++, other_allow, + well_known_world_sid, acl_len, inherit)) + return NULL; + } + + /* Set AclSize to computed value. */ + acl->AclSize = acl_len; + debug_printf ("ACL-Size: %d", acl_len); + + /* Create DACL for local security descriptor. */ + if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + { + __seterrno (); + return NULL; + } + + /* Make self relative security descriptor. */ + DWORD sd_size = 0; + MakeSelfRelativeSD (&sd, sd_ret, &sd_size); + if (sd_size <= 0) + { + __seterrno (); + return NULL; + } + if (!sd_ret.malloc (sd_size)) + { + set_errno (ENOMEM); + return NULL; + } + if (!MakeSelfRelativeSD (&sd, sd_ret, &sd_size)) + { + __seterrno (); + return NULL; + } + debug_printf ("Created SD-Size: %u", sd_ret.size ()); + + return sd_ret; +} + +void +set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, + security_descriptor &sd) +{ + psa->lpSecurityDescriptor = sd.malloc (SECURITY_DESCRIPTOR_MIN_LENGTH); + InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR)psa->lpSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); + psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), + attribute, sd); +} + +static int +set_nt_attribute (HANDLE handle, const char *file, + __uid32_t uid, __gid32_t gid, int attribute) +{ + if (!wincap.has_security ()) + return 0; + + security_descriptor sd; + + if ((!handle || get_nt_object_security (handle, SE_FILE_OBJECT, sd)) + && read_sd (file, sd) <= 0) + { + debug_printf ("read_sd %E"); + return -1; + } + + if (!alloc_sd (uid, gid, attribute, sd)) + return -1; + + return write_sd (handle, file, sd); +} + +int +set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, + __uid32_t uid, __gid32_t gid, int attribute) +{ + int ret = 0; + + if (use_ntsec && allow_ntsec) + ret = set_nt_attribute (handle, file, uid, gid, attribute); + else if (allow_ntea && !write_ea (handle, file, ".UNIXATTR", + (char *) &attribute, sizeof (attribute))) + { + __seterrno (); + ret = -1; + } + syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", + ret, file, uid, gid, attribute); + return ret; +} + +int +set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, + int attribute) +{ + return set_file_attribute (use_ntsec, handle, file, + myself->uid, myself->gid, attribute); +} + +int +check_file_access (const char *fn, int flags) +{ + int ret = -1; + + security_descriptor sd; + + HANDLE hToken; + BOOL status; + char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)]; + DWORD desired = 0, granted, plength = sizeof pbuf; + static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS }; + if (read_sd (fn, sd) <= 0) + goto done; + + if (cygheap->user.issetuid ()) + hToken = cygheap->user.token (); + else + hToken = hProcImpToken; + + if (flags & R_OK) + desired |= FILE_READ_DATA; + if (flags & W_OK) + desired |= FILE_WRITE_DATA; + if (flags & X_OK) + desired |= FILE_EXECUTE; + if (!AccessCheck (sd, hToken, desired, &mapping, + (PPRIVILEGE_SET) pbuf, &plength, &granted, &status)) + __seterrno (); + else if (!status) + set_errno (EACCES); + else + ret = 0; + done: + debug_printf ("flags %x, ret %d", flags, ret); + return ret; +} diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h new file mode 100644 index 00000000000..3155ec6e38c --- /dev/null +++ b/winsup/cygwin/security.h @@ -0,0 +1,402 @@ +/* security.h: security declarations + + Copyright 2000, 2001, 2002, 2003, 2004, 2005 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 _SECURITY_H +#define _SECURITY_H + +#include <accctrl.h> + +#define DEFAULT_UID DOMAIN_USER_RID_ADMIN +#define UNKNOWN_UID 400 /* Non conflicting number */ +#define UNKNOWN_GID 401 + +#define MAX_SID_LEN 40 +#define MAX_DACL_LEN(n) (sizeof (ACL) \ + + (n) * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + MAX_SID_LEN)) +#define ACL_DEFAULT_SIZE 3072 +#define NO_SID ((PSID)NULL) + +/* Macro to define variable length SID structures */ +#define SID(name, comment, authority, count, rid...) \ +static NO_COPY struct { \ + BYTE Revision; \ + BYTE SubAuthorityCount; \ + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; \ + DWORD SubAuthority[count]; \ +} name##_struct = { SID_REVISION, count, {authority}, {rid}}; \ +cygpsid NO_COPY name = (PSID) &name##_struct; + +#define FILE_READ_BITS (FILE_READ_DATA | GENERIC_READ | GENERIC_ALL) +#define FILE_WRITE_BITS (FILE_WRITE_DATA | GENERIC_WRITE | GENERIC_ALL) +#define FILE_EXEC_BITS (FILE_EXECUTE | GENERIC_EXECUTE | GENERIC_ALL) + +class cygpsid { +protected: + PSID psid; +public: + cygpsid () {} + cygpsid (PSID nsid) { psid = nsid; } + operator const PSID () { return psid; } + const PSID operator= (PSID nsid) { return psid = nsid;} + __uid32_t get_id (BOOL search_grp, int *type = NULL); + int get_uid () { return get_id (FALSE); } + int get_gid () { return get_id (TRUE); } + + char *string (char *nsidstr) const; + + bool operator== (const PSID nsid) const + { + if (!psid || !nsid) + return nsid == psid; + return EqualSid (psid, nsid); + } + bool operator!= (const PSID nsid) const + { return !(*this == nsid); } + bool operator== (const char *nsidstr) const; + bool operator!= (const char *nsidstr) const + { return !(*this == nsidstr); } + + void debug_print (const char *prefix = NULL) const + { + char buf[256] __attribute__ ((unused)); + debug_printf ("%s %s", prefix ?: "", string (buf) ?: "NULL"); + } +}; + +class cygsid : public cygpsid { + char sbuf[MAX_SID_LEN]; + + const PSID getfromstr (const char *nsidstr); + PSID get_sid (DWORD s, DWORD cnt, DWORD *r); + + inline const PSID assign (const PSID nsid) + { + if (!nsid) + psid = NO_SID; + else + { + psid = (PSID) sbuf; + CopySid (MAX_SID_LEN, psid, nsid); + } + return psid; + } + +public: + inline operator const PSID () { return psid; } + + inline const PSID operator= (cygsid &nsid) + { return assign (nsid); } + inline const PSID operator= (const PSID nsid) + { return assign (nsid); } + inline const PSID operator= (const char *nsidstr) + { return getfromstr (nsidstr); } + + inline cygsid () : cygpsid ((PSID) sbuf) {} + inline cygsid (const PSID nsid) { *this = nsid; } + inline cygsid (const char *nstrsid) { *this = nstrsid; } + + inline PSID set () { return psid = (PSID) sbuf; } + + BOOL getfrompw (const struct passwd *pw); + BOOL getfromgr (const struct __group32 *gr); +}; + +typedef enum { cygsidlist_empty, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type; +class cygsidlist { + int maxcount; +public: + int count; + cygsid *sids; + cygsidlist_type type; + + cygsidlist (cygsidlist_type t, int m) + { + type = t; + count = 0; + maxcount = m; + if (t == cygsidlist_alloc) + sids = alloc_sids (m); + else + sids = new cygsid [m]; + } + ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; } + + BOOL add (const PSID nsi) /* Only with auto for now */ + { + if (count >= maxcount) + { + cygsid *tmp = new cygsid [ 2 * maxcount]; + if (!tmp) + return FALSE; + maxcount *= 2; + for (int i = 0; i < count; ++i) + tmp[i] = sids[i]; + delete [] sids; + sids = tmp; + } + sids[count++] = nsi; + return TRUE; + } + BOOL add (cygsid &nsi) { return add ((PSID) nsi); } + BOOL add (const char *sidstr) + { cygsid nsi (sidstr); return add (nsi); } + BOOL addfromgr (struct __group32 *gr) /* Only with alloc */ + { return sids[count].getfromgr (gr) && ++count; } + + BOOL operator+= (cygsid &si) { return add (si); } + BOOL operator+= (const char *sidstr) { return add (sidstr); } + BOOL operator+= (const PSID psid) { return add (psid); } + + int position (const PSID sid) const + { + for (int i = 0; i < count; ++i) + if (sids[i] == sid) + return i; + return -1; + } + + BOOL contains (const PSID sid) const { return position (sid) >= 0; } + cygsid *alloc_sids (int n); + void free_sids (); + void debug_print (const char *prefix = NULL) const + { + debug_printf ("-- begin sidlist ---"); + if (!count) + debug_printf ("No elements"); + for (int i = 0; i < count; ++i) + sids[i].debug_print (prefix); + debug_printf ("-- ende sidlist ---"); + } +}; + +/* Wrapper class to allow simple deleting of buffer space allocated + by read_sd() */ +class security_descriptor { +protected: + PSECURITY_DESCRIPTOR psd; + DWORD sd_size; +public: + security_descriptor () : psd (NULL), sd_size (0) {} + ~security_descriptor () { free (); } + + PSECURITY_DESCRIPTOR malloc (size_t nsize); + PSECURITY_DESCRIPTOR realloc (size_t nsize); + void free (); + + inline DWORD size () const { return sd_size; } + inline operator const PSECURITY_DESCRIPTOR () { return psd; } +}; + +class user_groups { +public: + cygsid pgsid; + cygsidlist sgsids; + BOOL ischanged; + + BOOL issetgroups () const { return (sgsids.type == cygsidlist_alloc); } + void update_supp (const cygsidlist &newsids) + { + sgsids.free_sids (); + sgsids = newsids; + ischanged = TRUE; + } + void clear_supp () + { + if (issetgroups ()) + { + sgsids.free_sids (); + ischanged = TRUE; + } + } + void update_pgrp (const PSID sid) + { + pgsid = sid; + ischanged = TRUE; + } +}; + +extern cygpsid well_known_null_sid; +extern cygpsid well_known_world_sid; +extern cygpsid well_known_local_sid; +extern cygpsid well_known_creator_owner_sid; +extern cygpsid well_known_creator_group_sid; +extern cygpsid well_known_dialup_sid; +extern cygpsid well_known_network_sid; +extern cygpsid well_known_batch_sid; +extern cygpsid well_known_interactive_sid; +extern cygpsid well_known_service_sid; +extern cygpsid well_known_authenticated_users_sid; +extern cygpsid well_known_system_sid; +extern cygpsid well_known_admins_sid; + +/* Order must be same as cygpriv in sec_helper.cc. */ +enum cygpriv_idx { + SE_CREATE_TOKEN_PRIV = 0, + SE_ASSIGNPRIMARYTOKEN_PRIV, + SE_LOCK_MEMORY_PRIV, + SE_INCREASE_QUOTA_PRIV, + SE_UNSOLICITED_INPUT_PRIV, + SE_MACHINE_ACCOUNT_PRIV, + SE_TCB_PRIV, + SE_SECURITY_PRIV, + SE_TAKE_OWNERSHIP_PRIV, + SE_LOAD_DRIVER_PRIV, + SE_SYSTEM_PROFILE_PRIV, + SE_SYSTEMTIME_PRIV, + SE_PROF_SINGLE_PROCESS_PRIV, + SE_INC_BASE_PRIORITY_PRIV, + SE_CREATE_PAGEFILE_PRIV, + SE_CREATE_PERMANENT_PRIV, + SE_BACKUP_PRIV, + SE_RESTORE_PRIV, + SE_SHUTDOWN_PRIV, + SE_DEBUG_PRIV, + SE_AUDIT_PRIV, + SE_SYSTEM_ENVIRONMENT_PRIV, + SE_CHANGE_NOTIFY_PRIV, + SE_REMOTE_SHUTDOWN_PRIV, + SE_CREATE_GLOBAL_PRIV, + SE_UNDOCK_PRIV, + SE_MANAGE_VOLUME_PRIV, + SE_IMPERSONATE_PRIV, + SE_ENABLE_DELEGATION_PRIV, + SE_SYNC_AGENT_PRIV, + + SE_NUM_PRIVS +}; + +const LUID *privilege_luid (enum cygpriv_idx idx); +const LUID *privilege_luid_by_name (const char *pname); +const char *privilege_name (enum cygpriv_idx idx); + +inline BOOL +legal_sid_type (SID_NAME_USE type) +{ + return type == SidTypeUser || type == SidTypeGroup + || type == SidTypeAlias || type == SidTypeWellKnownGroup; +} + +extern bool allow_ntea; +extern bool allow_ntsec; +extern bool allow_smbntsec; +extern bool allow_traverse; + +/* File manipulation */ +int __stdcall get_file_attribute (int, HANDLE, const char *, mode_t *, + __uid32_t * = NULL, __gid32_t * = NULL); +int __stdcall set_file_attribute (bool, HANDLE, const char *, int); +int __stdcall set_file_attribute (bool, HANDLE, const char *, __uid32_t, __gid32_t, int); +int __stdcall get_nt_object_security (HANDLE, SE_OBJECT_TYPE, + security_descriptor &); +int __stdcall get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, mode_t *, + __uid32_t * = NULL, __gid32_t * = NULL); +LONG __stdcall read_sd (const char *file, security_descriptor &sd); +LONG __stdcall write_sd (HANDLE fh, const char *file, security_descriptor &sd); +bool __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); +bool __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit); +int __stdcall check_file_access (const char *, int); + +void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, + security_descriptor &sd_buf); + +bool get_sids_info (cygpsid, cygpsid, __uid32_t * , __gid32_t *); + +/* sec_acl.cc */ +struct __acl32; +extern "C" int aclsort32 (int, int, __acl32 *); +extern "C" int acl32 (const char *, int, int, __acl32 *); +int getacl (HANDLE, const char *, DWORD, int, __acl32 *); +int setacl (HANDLE, const char *, int, __acl32 *); + +struct _UNICODE_STRING; +void __stdcall str2buf2uni (_UNICODE_STRING &, WCHAR *, const char *) __attribute__ ((regparm (3))); +void __stdcall str2uni_cat (_UNICODE_STRING &, const char *) __attribute__ ((regparm (2))); + +/* Try a subauthentication. */ +HANDLE subauth (struct passwd *pw); +/* Try creating a token directly. */ +HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw); +/* Verify an existing token */ +bool verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern = NULL); +/* Get groups of a user */ +bool get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw); + +/* Extract U-domain\user field from passwd entry. */ +void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user); +/* Get default logonserver for a domain. */ +bool get_logon_server (const char * domain, char * server, WCHAR *wserver, + bool rediscovery); + +/* sec_helper.cc: Security helper functions. */ +int set_privilege (HANDLE token, enum cygpriv_idx privilege, bool enable); +void set_cygwin_privileges (HANDLE token); + +#define set_process_privilege(p,v) set_privilege (hProcImpToken, (p), (v)) + +#define _push_thread_privilege(_priv, _val, _check) { \ + HANDLE _token = NULL, _dup_token = NULL; \ + if (wincap.has_security ()) \ + { \ + _token = (cygheap->user.issetuid () && (_check)) \ + ? cygheap->user.token () : hProcImpToken; \ + if (!DuplicateTokenEx (_token, MAXIMUM_ALLOWED, NULL, \ + SecurityImpersonation, TokenImpersonation, \ + &_dup_token)) \ + debug_printf ("DuplicateTokenEx: %E"); \ + else if (!ImpersonateLoggedOnUser (_dup_token)) \ + debug_printf ("ImpersonateLoggedOnUser: %E"); \ + else \ + set_privilege (_dup_token, (_priv), (_val)); \ + } +#define push_thread_privilege(_priv, _val) _push_thread_privilege(_priv,_val,1) +#define push_self_privilege(_priv, _val) _push_thread_privilege(_priv,_val,0) + +#define pop_thread_privilege() \ + if (_dup_token) \ + { \ + ImpersonateLoggedOnUser (_token); \ + CloseHandle (_dup_token); \ + } \ + } +#define pop_self_privilege() pop_thread_privilege() + +/* shared.cc: */ +/* Retrieve a security descriptor that allows all access */ +SECURITY_DESCRIPTOR *__stdcall get_null_sd (); + +/* Various types of security attributes for use in Create* functions. */ +extern SECURITY_ATTRIBUTES sec_none, sec_none_nih, sec_all, sec_all_nih; +extern SECURITY_ATTRIBUTES *__stdcall __sec_user (PVOID sa_buf, PSID sid1, PSID sid2, + DWORD access2, BOOL inherit) + __attribute__ ((regparm (3))); +extern bool sec_acl (PACL acl, bool original, bool admins, PSID sid1 = NO_SID, + PSID sid2 = NO_SID, DWORD access2 = 0); + +int __stdcall read_ea (HANDLE hdl, const char *file, const char *attrname, + char *buf, int len); +BOOL __stdcall write_ea (HANDLE hdl, const char *file, const char *attrname, + const char *buf, int len); + +/* Note: sid1 is usually (read: currently always) the current user's + effective sid (cygheap->user.sid ()). */ +extern inline SECURITY_ATTRIBUTES * +sec_user_nih (SECURITY_ATTRIBUTES *sa_buf, PSID sid1, PSID sid2 = NULL, + DWORD access2 = 0) +{ + return __sec_user (sa_buf, sid1, sid2, access2, FALSE); +} + +extern inline SECURITY_ATTRIBUTES * +sec_user (SECURITY_ATTRIBUTES *sa_buf, PSID sid1, PSID sid2 = NULL, + DWORD access2 = 0) +{ + return __sec_user (sa_buf, sid1, sid2, access2, TRUE); +} +#endif /*_SECURITY_H*/ diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc new file mode 100644 index 00000000000..b8519cfbc12 --- /dev/null +++ b/winsup/cygwin/uinfo.cc @@ -0,0 +1,572 @@ +/* uinfo.cc: user info (uid, gid, etc...) + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 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. */ + +#include "winsup.h" +#include <pwd.h> +#include <unistd.h> +#include <winnls.h> +#include <wininet.h> +#include <utmp.h> +#include <limits.h> +#include <stdlib.h> +#include <lm.h> +#include <sys/cygwin.h> +#include "cygerrno.h" +#include "pinfo.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "registry.h" +#include "child_info.h" +#include "environ.h" +#include "pwdgrp.h" + +/* Initialize the part of cygheap_user that does not depend on files. + The information is used in shared.cc for the user shared. + Final initialization occurs in uinfo_init */ +void +cygheap_user::init () +{ + char user_name[UNLEN + 1]; + DWORD user_name_len = UNLEN + 1; + + set_name (GetUserName (user_name, &user_name_len) ? user_name : "unknown"); + + if (!wincap.has_security ()) + return; + + DWORD siz; + PSECURITY_DESCRIPTOR psd; + + if (!GetTokenInformation (hProcToken, TokenPrimaryGroup, + &groups.pgsid, sizeof (cygsid), &siz)) + system_printf ("GetTokenInformation (TokenPrimaryGroup), %E"); + + /* Get the SID from current process and store it in effec_cygsid */ + if (!GetTokenInformation (hProcToken, TokenUser, &effec_cygsid, + sizeof (cygsid), &siz)) + { + system_printf ("GetTokenInformation (TokenUser), %E"); + return; + } + + /* Set token owner to the same value as token user */ + if (!SetTokenInformation (hProcToken, TokenOwner, &effec_cygsid, + sizeof (cygsid))) + debug_printf ("SetTokenInformation(TokenOwner), %E"); + + /* Standard way to build a security descriptor with the usual DACL */ + PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024); + psd = (PSECURITY_DESCRIPTOR) + (sec_user_nih (sa_buf, sid()))->lpSecurityDescriptor; + + BOOL acl_exists, dummy; + TOKEN_DEFAULT_DACL dacl; + if (GetSecurityDescriptorDacl (psd, &acl_exists, &dacl.DefaultDacl, &dummy) + && acl_exists && dacl.DefaultDacl) + { + /* Set the default DACL and the process DACL */ + if (!SetTokenInformation (hProcToken, TokenDefaultDacl, &dacl, + sizeof (dacl))) + system_printf ("SetTokenInformation (TokenDefaultDacl), %E"); + if (!SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION, psd)) + system_printf ("SetKernelObjectSecurity, %E"); + } + else + system_printf("Cannot get dacl, %E"); +} + +void +internal_getlogin (cygheap_user &user) +{ + struct passwd *pw = NULL; + + if (wincap.has_security ()) + { + cygpsid psid = user.sid (); + pw = internal_getpwsid (psid); + } + + if (!pw && !(pw = internal_getpwnam (user.name ())) + && !(pw = internal_getpwuid (DEFAULT_UID))) + debug_printf ("user not found in augmented /etc/passwd"); + else + { + myself->uid = pw->pw_uid; + myself->gid = pw->pw_gid; + user.set_name (pw->pw_name); + if (wincap.has_security ()) + { + cygsid gsid; + if (gsid.getfromgr (internal_getgrgid (pw->pw_gid))) + { + if (gsid != user.groups.pgsid) + { + /* Set primary group to the group in /etc/passwd. */ + if (!SetTokenInformation (hProcToken, TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(TokenPrimaryGroup), %E"); + if (!SetTokenInformation (hProcImpToken, TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(TokenPrimaryGroup), %E"); + else + user.groups.pgsid = gsid; + } + } + else + debug_printf ("gsid not found in augmented /etc/group"); + } + } + cygheap->user.ontherange (CH_HOME, pw); +} + +void +uinfo_init () +{ + if (child_proc_info && !cygheap->user.has_impersonation_tokens ()) + return; + + if (!child_proc_info) + internal_getlogin (cygheap->user); /* Set the cygheap->user. */ + /* Conditions must match those in spawn to allow starting child + processes with ruid != euid and rgid != egid. */ + else if (cygheap->user.issetuid () + && cygheap->user.saved_uid == cygheap->user.real_uid + && cygheap->user.saved_gid == cygheap->user.real_gid + && !cygheap->user.groups.issetgroups ()) + { + cygheap->user.reimpersonate (); + return; + } + else + cygheap->user.close_impersonation_tokens (); + + cygheap->user.saved_uid = cygheap->user.real_uid = myself->uid; + cygheap->user.saved_gid = cygheap->user.real_gid = myself->gid; + cygheap->user.external_token = NO_IMPERSONATION; + cygheap->user.internal_token = NO_IMPERSONATION; + cygheap->user.curr_primary_token = NO_IMPERSONATION; + cygheap->user.current_token = NO_IMPERSONATION; + cygheap->user.set_saved_sid (); /* Update the original sid */ + cygheap->user.reimpersonate (); +} + +extern "C" int +getlogin_r (char *name, size_t namesize) +{ + char *login = getlogin (); + size_t len = strlen (login) + 1; + if (len > namesize) + return ERANGE; + myfault efault; + if (efault.faulted ()) + return EFAULT; + strncpy (name, login, len); + return 0; +} + +extern "C" char * +getlogin (void) +{ + return strcpy (_my_tls.locals.username, cygheap->user.name ()); +} + +extern "C" __uid32_t +getuid32 (void) +{ + return cygheap->user.real_uid; +} + +extern "C" __uid16_t +getuid (void) +{ + return cygheap->user.real_uid; +} + +extern "C" __gid32_t +getgid32 (void) +{ + return cygheap->user.real_gid; +} + +extern "C" __gid16_t +getgid (void) +{ + return cygheap->user.real_gid; +} + +extern "C" __uid32_t +geteuid32 (void) +{ + return myself->uid; +} + +extern "C" __uid16_t +geteuid (void) +{ + return myself->uid; +} + +extern "C" __gid32_t +getegid32 (void) +{ + return myself->gid; +} + +extern "C" __gid16_t +getegid (void) +{ + return myself->gid; +} + +/* Not quite right - cuserid can change, getlogin can't */ +extern "C" char * +cuserid (char *src) +{ + if (!src) + return getlogin (); + + strcpy (src, getlogin ()); + return src; +} + +const char * +cygheap_user::ontherange (homebodies what, struct passwd *pw) +{ + LPUSER_INFO_3 ui = NULL; + WCHAR wuser[UNLEN + 1]; + NET_API_STATUS ret; + char homepath_env_buf[CYG_MAX_PATH]; + char homedrive_env_buf[3]; + char *newhomedrive = NULL; + char *newhomepath = NULL; + + + debug_printf ("what %d, pw %p", what, pw); + if (what == CH_HOME) + { + char *p; + if (homedrive) + newhomedrive = homedrive; + else if ((p = getenv ("HOMEDRIVE"))) + newhomedrive = p; + + if (homepath) + newhomepath = homepath; + else if ((p = getenv ("HOMEPATH"))) + newhomepath = p; + + if ((p = getenv ("HOME"))) + debug_printf ("HOME is already in the environment %s", p); + else + { + if (pw && pw->pw_dir && *pw->pw_dir) + { + debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir); + setenv ("HOME", pw->pw_dir, 1); + } + else if (!newhomedrive || !newhomepath) + setenv ("HOME", "/", 1); + else + { + char home[CYG_MAX_PATH]; + char buf[CYG_MAX_PATH]; + strcpy (buf, newhomedrive); + strcat (buf, newhomepath); + cygwin_conv_to_full_posix_path (buf, home); + debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home); + setenv ("HOME", home, 1); + } + } + } + + if (what != CH_HOME && homepath == NULL && newhomepath == NULL) + { + if (!pw) + pw = internal_getpwnam (name ()); + if (pw && pw->pw_dir && *pw->pw_dir) + cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf); + else + { + homepath_env_buf[0] = homepath_env_buf[1] = '\0'; + if (logsrv ()) + { + WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + sys_mbstowcs (wlogsrv, logsrv (), + sizeof (wlogsrv) / sizeof (*wlogsrv)); + sys_mbstowcs (wuser, winname (), sizeof (wuser) / sizeof (*wuser)); + if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui))) + { + sys_wcstombs (homepath_env_buf, CYG_MAX_PATH, + ui->usri3_home_dir); + if (!homepath_env_buf[0]) + { + sys_wcstombs (homepath_env_buf, CYG_MAX_PATH, + ui->usri3_home_dir_drive); + if (homepath_env_buf[0]) + strcat (homepath_env_buf, "\\"); + else + cygwin_conv_to_full_win32_path ("/", homepath_env_buf); + } + } + } + if (ui) + NetApiBufferFree (ui); + } + + if (homepath_env_buf[1] != ':') + { + newhomedrive = almost_null; + newhomepath = homepath_env_buf; + } + else + { + homedrive_env_buf[0] = homepath_env_buf[0]; + homedrive_env_buf[1] = homepath_env_buf[1]; + homedrive_env_buf[2] = '\0'; + newhomedrive = homedrive_env_buf; + newhomepath = homepath_env_buf + 2; + } + } + + if (newhomedrive && newhomedrive != homedrive) + cfree_and_set (homedrive, (newhomedrive == almost_null) + ? almost_null : cstrdup (newhomedrive)); + + if (newhomepath && newhomepath != homepath) + cfree_and_set (homepath, cstrdup (newhomepath)); + + switch (what) + { + case CH_HOMEDRIVE: + return homedrive; + case CH_HOMEPATH: + return homepath; + default: + return homepath; + } +} + +const char * +cygheap_user::test_uid (char *&what, const char *name, size_t namelen) +{ + if (!what && !issetuid ()) + what = getwinenveq (name, namelen, HEAP_STR); + return what; +} + +const char * +cygheap_user::env_logsrv (const char *name, size_t namelen) +{ + if (test_uid (plogsrv, name, namelen)) + return plogsrv; + + const char *mydomain = domain (); + const char *myname = winname (); + if (!mydomain || strcasematch (myname, "SYSTEM")) + return almost_null; + + char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3]; + cfree_and_set (plogsrv, almost_null); + if (get_logon_server (mydomain, logsrv, NULL, false)) + plogsrv = cstrdup (logsrv); + return plogsrv; +} + +const char * +cygheap_user::env_domain (const char *name, size_t namelen) +{ + if (pwinname && test_uid (pdomain, name, namelen)) + return pdomain; + + char username[UNLEN + 1]; + DWORD ulen = sizeof (username); + char userdomain[DNLEN + 1]; + DWORD dlen = sizeof (userdomain); + SID_NAME_USE use; + + cfree_and_set (pwinname, almost_null); + cfree_and_set (pdomain, almost_null); + if (!LookupAccountSid (NULL, sid (), username, &ulen, + userdomain, &dlen, &use)) + __seterrno (); + else + { + pwinname = cstrdup (username); + pdomain = cstrdup (userdomain); + } + return pdomain; +} + +const char * +cygheap_user::env_userprofile (const char *name, size_t namelen) +{ + if (test_uid (puserprof, name, namelen)) + return puserprof; + + char userprofile_env_buf[CYG_MAX_PATH]; + char win_id[UNLEN + 1]; /* Large enough for SID */ + + cfree_and_set (puserprof, almost_null); + if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf)) + puserprof = cstrdup (userprofile_env_buf); + + return puserprof; +} + +const char * +cygheap_user::env_homepath (const char *name, size_t namelen) +{ + return ontherange (CH_HOMEPATH); +} + +const char * +cygheap_user::env_homedrive (const char *name, size_t namelen) +{ + return ontherange (CH_HOMEDRIVE); +} + +const char * +cygheap_user::env_name (const char *name, size_t namelen) +{ + if (!test_uid (pwinname, name, namelen)) + domain (); + return pwinname; +} + +const char * +cygheap_user::env_systemroot (const char *name, size_t namelen) +{ + if (!psystemroot) + { + int size = GetWindowsDirectory (NULL, 0); + if (size > 0) + { + psystemroot = (char *) cmalloc (HEAP_STR, ++size); + size = GetWindowsDirectory (psystemroot, size); + if (size <= 0) + { + cfree (psystemroot); + psystemroot = NULL; + } + } + if (size <= 0) + debug_printf ("GetWindowsDirectory(), %E"); + } + return psystemroot; +} + +char * +pwdgrp::next_str (char c) +{ + char *res = lptr; + lptr = strechr (lptr, c); + if (*lptr) + *lptr++ = '\0'; + return res; +} + +bool +pwdgrp::next_num (unsigned long& n) +{ + char *p = next_str (':'); + char *cp; + n = strtoul (p, &cp, 10); + return p != cp && !*cp; +} + +char * +pwdgrp::add_line (char *eptr) +{ + if (eptr) + { + lptr = eptr; + eptr = strchr (lptr, '\n'); + if (eptr) + { + if (eptr > lptr && eptr[-1] == '\r') + eptr[-1] = '\0'; + else + *eptr = '\0'; + eptr++; + } + if (curr_lines >= max_lines) + { + max_lines += 10; + *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size); + } + if ((this->*parse) ()) + curr_lines++; + } + return eptr; +} + +void +pwdgrp::load (const char *posix_fname) +{ + const char *res; + static const char failed[] = "failed"; + static const char succeeded[] = "succeeded"; + + if (buf) + free (buf); + buf = NULL; + curr_lines = 0; + + pc.check (posix_fname); + etc_ix = etc::init (etc_ix, pc); + + paranoid_printf ("%s", posix_fname); + + if (pc.error || !pc.exists () || pc.isdir ()) + { + paranoid_printf ("strange path_conv problem"); + res = failed; + } + else + { + HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (fh == INVALID_HANDLE_VALUE) + { + paranoid_printf ("%s CreateFile failed, %E"); + res = failed; + } + else + { + DWORD size = GetFileSize (fh, NULL), read_bytes; + buf = (char *) malloc (size + 1); + if (!ReadFile (fh, buf, size, &read_bytes, NULL)) + { + paranoid_printf ("ReadFile failed, %E"); + CloseHandle (fh); + if (buf) + free (buf); + buf = NULL; + res = failed; + } + else + { + CloseHandle (fh); + buf[read_bytes] = '\0'; + char *eptr = buf; + while ((eptr = add_line (eptr))) + continue; + debug_printf ("%s curr_lines %d", posix_fname, curr_lines); + res = succeeded; + } + } + } + + debug_printf ("%s load %s", posix_fname, res); + initialized = true; +} |