summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <vinschen@redhat.com>2006-07-06 13:40:58 +0000
committerCorinna Vinschen <vinschen@redhat.com>2006-07-06 13:40:58 +0000
commit9ee064b4bd06b7be50fbc976c46172f83557f084 (patch)
tree60d4c70ba6f61b9046396c77a4fdc51466cb0b5f
parent69a7b5f79888513741e65a54216d7756474b76c2 (diff)
downloadgdb-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/ChangeLog2168
-rw-r--r--winsup/cygwin/autoload.cc572
-rw-r--r--winsup/cygwin/security.cc1893
-rw-r--r--winsup/cygwin/security.h402
-rw-r--r--winsup/cygwin/uinfo.cc572
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, &quota, &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;
+}