Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/ChangeLog1083
-rw-r--r--winsup/cygwin/Makefile.in1
-rw-r--r--winsup/cygwin/autoload.cc34
-rwxr-xr-xwinsup/cygwin/configure50
-rw-r--r--winsup/cygwin/configure.ac16
-rw-r--r--winsup/cygwin/cygerrno.h11
-rw-r--r--winsup/cygwin/cygheap.cc13
-rw-r--r--winsup/cygwin/cygheap.h144
-rw-r--r--winsup/cygwin/cygserver.h1
-rw-r--r--winsup/cygwin/cygserver_pwdgrp.h73
-rw-r--r--winsup/cygwin/cygtls.h11
-rw-r--r--winsup/cygwin/dcrt0.cc7
-rw-r--r--winsup/cygwin/dlfcn.cc4
-rw-r--r--winsup/cygwin/dll_init.sgml11
-rw-r--r--winsup/cygwin/dlmalloc.c3815
-rw-r--r--winsup/cygwin/dlmalloc.h93
-rw-r--r--winsup/cygwin/dtable.sgml20
-rw-r--r--winsup/cygwin/errno.cc17
-rw-r--r--winsup/cygwin/external.cc131
-rw-r--r--winsup/cygwin/external.sgml18
-rw-r--r--winsup/cygwin/fhandler.cc3
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc58
-rw-r--r--winsup/cygwin/fhandler_proc.cc5
-rw-r--r--winsup/cygwin/fhandler_process.cc8
-rw-r--r--winsup/cygwin/fhandler_procnet.cc6
-rw-r--r--winsup/cygwin/fhandler_procsys.cc56
-rw-r--r--winsup/cygwin/fhandler_procsysvipc.cc4
-rw-r--r--winsup/cygwin/fhandler_registry.cc4
-rw-r--r--winsup/cygwin/fhandler_socket.cc145
-rw-r--r--winsup/cygwin/fhandler_virtual.h25
-rw-r--r--winsup/cygwin/globals.cc3
-rw-r--r--winsup/cygwin/grp.cc530
-rw-r--r--winsup/cygwin/import/rexec.c391
-rw-r--r--winsup/cygwin/include/cygwin/acl.h4
-rw-r--r--winsup/cygwin/include/cygwin/version.h5
-rw-r--r--winsup/cygwin/include/sys/cygwin.h14
-rw-r--r--winsup/cygwin/ldap.cc629
-rw-r--r--winsup/cygwin/ldap.h80
-rw-r--r--winsup/cygwin/miscfuncs.cc76
-rw-r--r--winsup/cygwin/miscfuncs.h21
-rw-r--r--winsup/cygwin/mount.cc82
-rw-r--r--winsup/cygwin/passwd.cc674
-rw-r--r--winsup/cygwin/path.cc150
-rw-r--r--winsup/cygwin/path.h17
-rw-r--r--winsup/cygwin/path.sgml178
-rw-r--r--winsup/cygwin/pinfo.cc4
-rw-r--r--winsup/cygwin/poll.cc5
-rw-r--r--winsup/cygwin/posix.sgml1564
-rw-r--r--winsup/cygwin/pwdgrp.h256
-rw-r--r--winsup/cygwin/quotactl.cc1
-rw-r--r--winsup/cygwin/release/1.7.3322
-rw-r--r--winsup/cygwin/sec_acl.cc256
-rw-r--r--winsup/cygwin/sec_auth.cc112
-rw-r--r--winsup/cygwin/sec_helper.cc148
-rw-r--r--winsup/cygwin/security.cc114
-rw-r--r--winsup/cygwin/security.h80
-rw-r--r--winsup/cygwin/security.sgml45
-rw-r--r--winsup/cygwin/select.cc17
-rw-r--r--winsup/cygwin/setlsapwd.cc3
-rw-r--r--winsup/cygwin/shared.cc11
-rw-r--r--winsup/cygwin/shared_info.h2
-rw-r--r--winsup/cygwin/stackdump.sgml13
-rw-r--r--winsup/cygwin/syscalls.cc1
-rw-r--r--winsup/cygwin/tlsoffsets.h216
-rw-r--r--winsup/cygwin/tlsoffsets64.h216
-rw-r--r--winsup/cygwin/uinfo.cc1604
-rw-r--r--winsup/cygwin/uname.cc5
-rw-r--r--winsup/cygwin/wincap.cc7
-rw-r--r--winsup/cygwin/wincap.h4
-rw-r--r--winsup/cygwin/winlean.h2
-rw-r--r--winsup/cygwin/winsup.h23
71 files changed, 7069 insertions, 6383 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index fa5ca1947..51cc4e880 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -39,10 +39,6 @@
* cygheap.cc: Fix formatting.
-2014-10-30 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_user::ontherange): Don't mention /etc/passwd.
-
2014-10-29 Corinna Vinschen <corinna@vinschen.de>
* cygheap.cc (init_cygheap::init_installation_root): Create content of
@@ -67,16 +63,9 @@
2014-10-27 Corinna Vinschen <corinna@vinschen.de>
- * dlfcn.cc (dlopen): Drop patch accommodating SetDllDiretory from
- 2014-10-14.
-
-2014-10-27 Corinna Vinschen <corinna@vinschen.de>
-
- * cygheap.cc (cygheap_fixup_in_child): Drop call to set_dll_dir.
- (init_cygheap::init_installation_root): Set installation_dir_len.
- (setup_cygheap): Drop call to set_dll_dir.
+ * cygheap.cc (init_cygheap::init_installation_root): Set
+ installation_dir_len.
* cygheap.h (struct init_cygheap): Add installation_dir_len member.
- (init_cygheap::set_dll_dir): Remove.
* environ.cc (win_env::add_cache): Use stpcpy for speed.
(posify_maybe): Use tmp_pathbuf buffer instead of stack.
(raise_envblock): New function to resize Windows environment block.
@@ -84,20 +73,6 @@
$PATH exists and is non-empty. If not, add PATH variable with Cygwin
installation directory as content to Windows environment. Explain why.
- * uinfo.cc (cygheap_pwdgrp::_nss_init): Fill UNICODE_STRING members
- on the fly. Drop call to RtlInitUnicodeString.
- (pwdgrp::check_file): Ditto.
-
-2014-10-26 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::af_local_connect): Drop
- setting connect_state to connect_credxchg.
- (fhandler_socket::af_local_accept): Ditto.
- (fhandler_socket::recv_internal): Drop ill-advised connect_state check.
- Add comment so as not to repeat the exercise.
- * fhandler.h (enum conn_state): Drop now unneeded connect_credxchg
- state.
-
2014-10-24 Corinna Vinschen <corinna@vinschen.de>
* fhandler_proc.cc (format_proc_cygdrive): Fix symlink path if cygdrive
@@ -108,12 +83,6 @@
* gendef (sigdelayed): 64 bit only: Fix seh_pushreg statements in
prologue.
-2014-10-24 Kai Tietz <corinna@vinschen.de>
- Corinna Vinschen <corinna@vinschen.de>
-
- * gendef (sigdelayed): 64 bit only: Push CPU flags before aligning
- stack to avoid changing flag values.
-
2014-10-22 Yaakov Selkowitz <yselkowi@redhat.com>
* common.din (stime): Export.
@@ -121,12 +90,6 @@
* include/cygwin/time.h (stime): Declare.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
-2014-10-21 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_auth.cc (get_user_groups): Remove experimental exception handler
- added 2014-09-05.
- (get_user_local_groups): Ditto.
-
2014-10-20 Corinna Vinschen <corinna@vinschen.de>
* fhandler_serial.cc: Revert debug code accidentally checked in on
@@ -139,21 +102,11 @@
2014-10-17 Corinna Vinschen <corinna@vinschen.de>
- * cygheap.cc (cygheap_fixup_in_child): Call set_dll_dir.
- (init_cygheap::init_installation_root): Just memmove contents of
- installation_root instead of calling GetModuleFileNameW again.
- Copy installation_root to installation_dir before stripping of
- "bin" dir. Don't call SetDllDirectory here. Explain what we do.
- (setup_cygheap): New function taking over initial cygheap setup
- from memory_init. Additionally call set_dll_dir.
+ * cygheap.cc (init_cygheap::init_installation_root): Just memmove
+ contents of installation_root instead of calling GetModuleFileNameW
+ again. Copy installation_root to installation_dir before stripping of
+ "bin" dir. Explain what we do.
* cygheap.h (struct init_cygheap): Add installation_dir member.
- (init_cygheap::set_dll_dir): Define.
- (setup_cygheap): Declare.
- * dcrt0.cc: Throughout drop parameter from memory_init call.
- (dll_crt0_0): Call setup_cygheap prior to memory_init.
- * dlfcn.cc (dlopen): Change comment to point to the right function.
- * shared.cc (memory_init): Drop parameter. Drop cygheap setup.
- * shared_info.h (memory_init): Change declaration accordingly.
2014-10-17 Corinna Vinschen <corinna@vinschen.de>
@@ -189,31 +142,6 @@
* fhandler_proc.cc (format_proc_partitions): Extend output to print
the windows mount points the device is mounted on.
-2014-10-14 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::connect): Don't change state
- on WSAEALREADY error. Change comment accordingly.
-
-2014-10-14 Corinna Vinschen <corinna@vinschen.de>
-
- * cygheap.cc (init_cygheap::init_installation_root): Install Cygwin's
- installation dir as DLL search path, instead of ".".
- * cygheap.h (class cwdstuff): Add parameter names in function
- declarations for readability.
- (cwdstuff::get): Add inline implementation fetching the CWD as wide char
- string.
- * dlfcn.cc (dlopen): Add searching for dependent DLLs in DLL
- installation dir or CWD, if all else failed.
- Add comment to explain scenarios this is accommodating.
-
-2014-10-14 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::connect): Init connect_state to
- connect_pending only on unconnected socket. Set connect_state to
- connected on WSAEISCONN error. Set connect_state to connect_failed
- on any other error except WSAEWOULDBLOCK if connect is still pending.
- Add lots of comment to explain why all of the above.
-
2014-10-13 Corinna Vinschen <corinna@vinschen.de>
* net.cc (cygwin_setsockopt): Drop redundant test for AF_LOCAL and
@@ -250,63 +178,12 @@
sockets. Add comment to explain why we need it.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
-2014-10-11 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::af_local_connect): Drop outdated
- comment.
- (fhandler_socket::evaluate_events): Only set connect_state and call
- af_local_connect if connect_state is connect_pending. Explain why.
- Drop redundant test for socket family and type.
- (fhandler_socket::connect): Extend comment.
-
-2014-10-11 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::evaluate_events): Handle
- connect_state and af_local_connect connect call here, once, independent
- of FD_CONNECT being requested. Add comment to explain why.
- (fhandler_socket::connect): Drop connect_state handling and calling
- af_local_connect. Move remaining AF_LOCAL stuff prior to calling
- ::connect and explain why. Simplify error case.
- * poll.cc (poll): Handle connect state independently of POLLOUT being
- requested for the descriptor to allow setting POLLIN if connect failed.
- Add comment.
- * select.cc (set_bits): Drop connect_state and AF_LOCAL handling here.
-
-2014-10-11 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_socket.cc (fhandler_socket::evaluate_events): Slightly
- rearrange code. Rephrase a comment.
-
2014-10-10 Corinna Vinschen <corinna@vinschen.de>
* dlfcn.cc (dlopen): Disable old 32 bit code on 64 bit.
* dcrt0.cc (check_sanity_and_sync): Ditto.
* dll_init.cc (dll_dllcrt0_1): Fix typo in comment.
-2014-10-09 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_procsys.cc (fhandler_procsys::readdir): Just test
- ObjectTypeName for object types rather than calling lstat to avoid
- performance hit.
- * globals.cc (ro_u_natdir): Define.
- (ro_u_natsyml): Define.
- (ro_u_natdev): Define.
-
-2014-10-09 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_disk_file.cc (fhandler_disk_file::readdir_helper): Set d_type
- for virtual directories.
-
-2014-10-09 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler_proc.cc (fhandler_proc::readdir): Set dirent d_type.
- * fhandler_process.cc (fhandler_process::readdir): Ditto.
- * fhandler_procnet.cc (fhandler_procnet::readdir): Ditto.
- * fhandler_procsys.cc (fhandler_procsys::readdir): Ditto.
- * fhandler_procsysvipc.cc (fhandler_procsysvipc::readdir): Ditto.
- * fhandler_virtual.h (virt_ftype_to_dtype): Define new inline function
- to generate dirent d_type from virtual_ftype_t.
-
2014-10-08 Corinna Vinschen <corinna@vinschen.de>
* common.din (ffsl): Export.
@@ -333,68 +210,11 @@
2014-09-05 Corinna Vinschen <corinna@vinschen.de>
* exception.h (class exception): Remove unnecessary #ifdef.
- * uinfo.cc (client_request_pwdgrp::client_request_pwdgrp): Fix length
- counter to include trailing NUL.
-
- * sec_auth.cc (get_user_groups): Add experimental exception handler.
- (get_user_local_groups): Ditto.
2014-09-05 Corinna Vinschen <corinna@vinschen.de>
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Handle APPLICATION
- PACKAGE AUTHORITY SIDs.
* winlean.h (DNLEN): Raise to 31. Explain why.
-2014-09-03 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_acl.cc (aclcheck32): Check for required default entries as well.
- Enable check for missing CLASS_OBJ entries, now that setfacl creates
- them.
-
-2014-09-02 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_acl.cc (aclsort32): Set errno to EINVAL if aclcheck32 failed.
-
-2014-08-31 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Disallow user accounts
- as groups. Add comment.
-
-2014-08-31 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_pwdgrp::init): Fix comment. Rearrange code for
- style.
- (cygheap_pwdgrp::nss_init_line): Disable db_prefix and db_separator
- settings. Add comment.
- (pwdgrp::fetch_account_from_windows): Drop outdated comment. Fix code
- fetching primary group gid of group setting in SAM description field.
- Change comment accordingly.
-
-2014-08-31 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Disallow creating an
- entry for "NULL SID".
-
-2014-08-31 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_acl.cc (setacl): Add comment. Handle NULL ACE for SUID, SGID,
- and VTX bits. Create owner, group, other and NULL entries in the same
- way and in the same order as alloc_sd.
- (getacl): Skip NULL ACE.
-
-2014-08-28 Corinna Vinschen <corinna@vinschen.de>
-
- * fhandler.cc (fhandler_base::facl): Drop CLASS_OBJ entry.
- * fhandler_disk_file.cc (fhandler_disk_file::facl): Ditto in noacl case.
- * sec_acl.cc (getacl): Compute useful fake CLASS_OBJ and DEF_CLASS_OBJ
- permission bits based on how these values are generated on Linux.
- Add comments to explain what the code is doing.
- * security.cc (get_attribute_from_acl): Compute group permission based
- on the actual primary group permissions and all secondary user and group
- ACCESS_ALLOWED_ACEs to emulate Linux' behaviour more closely.
- (check_access): Fix typos im comment.
- * include/cygwin/acl.h (MIN_ACL_ENTRIES): Redefine as 3.
-
2014-08-28 Corinna Vinschen <corinna@vinschen.de>
* fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Try the
@@ -552,17 +372,6 @@
2014-08-19 Corinna Vinschen <corinna@vinschen.de>
- * fhandler.h (enum conn_state): Add "connect_credxchg" state.
- (class fhandler_socket): Grant another bit to connect_state flag.
- * fhandler_socket.cc (fhandler_socket::af_local_connect): Rearrange
- variable definition. Set connect_state to connect_credxchg.
- (fhandler_socket::af_local_accept): Ditto.
- (fhandler_socket::recv_internal): Accept connect_credxchg on connection
- oriented AF_LOCAL sockets as well to allow the credential exchange.
- Extend comment to explain.
-
-2014-08-19 Corinna Vinschen <corinna@vinschen.de>
-
* autoload.cc: Replace WNet[...]A with WNet[...]W imports.
* dcrt0.cc (initial_env): Drop strlwr calls. Call strcasestr instead.
* fhandler_netdrive.cc: Throughout, convert to calling WNet UNICODE
@@ -594,36 +403,11 @@
listener. Add comment.
(fhandler_socket::accept4): Explicitely check if the socket is listening
and fail with EINVAL, if not. Explain why we have to do that.
- (fhandler_socket::recv_internal): Explicitely check if the socket is
- connected if it's a stream socket. Explain why we have to do that.
(fhandler_socket::getpeereid): Drop now redundant test.
2014-08-15 Corinna Vinschen <corinna@vinschen.de>
* winsup.h (_GNU_SOURCE): Define. Explain why.
- * configure.ac: Convert to new AC_INIT style.
- * configure: Regenerate.
-
-2014-08-15 Corinna Vinschen <corinna@vinschen.de>
-
- * cygerrno.h (seterrno): Define as (always) inline function.
- * errno.cc (seterrno): Remove.
-
-2014-08-14 Corinna Vinschen <corinna@vinschen.de>
-
- * dll_init.sgml: Remove.
- * dtable.sgml: Move into ../doc/misc-funcs.xml.
- * external.sgml: Ditto.
- * stackdump.sgml: Ditto.
-
-2014-08-14 Corinna Vinschen <corinna@vinschen.de>
-
- * security.sgml: Move to ../doc dir and rename to logon-funcs.xml.
-
-2014-08-14 Corinna Vinschen <corinna@vinschen.de>
-
- * path.sgml: Move to ../doc dir and rename to path.xml.
- * posix.sgml: Move to ../doc dir and rename to posix.xml.
2014-08-14 Corinna Vinschen <corinna@vinschen.de>
@@ -667,14 +451,6 @@
* common.din (__cxa_atexit): Export.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump to 274.
-2014-08-04 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Drop "plus_prepended"
- as naming style. Drop enum name_style_t, use a boolean
- "fully_qualified_name" value instead. Rework function to drop
- "plus_prepended" handling througout and default to "name only" style
- as replacement.
-
2014-07-31 Eric Blake <eblake@redhat.com>
* include/pthread.h: Decorate attribute names with __, for
@@ -684,27 +460,6 @@
* include/sys/cygwin.h: Likewise.
* include/sys/strace.h: Likewise.
-2014-07-30 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Fix comment.
-
-2014-07-29 Corinna Vinschen <corinna@vinschen.de>
-
- * cygheap.h (class cygheap_domain_info): Remove lowest_tdo_posix_offset.
- * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): Return UINT32_MAX
- in case of error.
- * security.h (PRIMARY_POSIX_OFFSET): Define.
- (NOACCESS_POSIX_OFFSET): Define.
- (UNUSABLE_POSIX_OFFSET): Define.
- * uinfo.cc (cygheap_domain_info::init): Drop initializing
- lowest_tdo_posix_offset.
- (pwdgrp::fetch_account_from_file): Set PosixOffset to either
- UNUSABLE_POSIX_OFFSET or NOACCESS_POSIX_OFFSET in case we don't get a
- sensible offset from AD. Explain why. Drop setting ch
- lowest_tdo_posix_offset.
- (pwdgrp::fetch_account_from_windows): Replace constant 0x100000 with
- PRIMARY_POSIX_OFFSET throughout.
-
2014-07-24 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::send_internal): Fix value of
@@ -720,10 +475,6 @@
* include/cygwin/version.h (CYGWIN_VERSION_DLL_MINOR): Bump to 32.
-2014-07-21 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc: Fix typo in comment.
-
2014-07-16 Corinna Vinschen <corinna@vinschen.de>
* thread.cc (pthread::create): Handle stackaddr as upper bound address.
@@ -757,13 +508,6 @@
* sigproc.cc (send_sig): Fix bad format in diagnostic output.
-2014-07-14 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_domain_info::init): Correctly set
- lowest_tdo_posix_offset to UNIX_POSIX_OFFSET.
- (fetch_posix_offset): Redesign to fake a POSIX offset in all cases
- where we can't fetch a non-0 POSIX offset from our primary domain.
-
2014-07-14 Yaakov Selkowitz <yselkowitz@cygwin.com>
* thread.cc (pthread_mutex::pthread_mutex): Change default type
@@ -809,11 +553,6 @@
writing small buffers. Rename variables and add comments to help
understanding the code in years to come.
-2014-07-07 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (pg_ent::enumerate_ad): Revert to simply skipping a domain
- if opening the connection to the domain fails.
-
2014-07-07 Pierre Humblet <Pierre.Humblet@ieee.org>
Corinna Vinschen <corinna@vinschen.de>
@@ -827,73 +566,6 @@
* fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Add debug
output.
-2014-06-25 Corinna Vinschen <corinna@vinschen.de>
-
- * errno.cc (errmap): Fix order of SERVICE_REQUEST_TIMEOUT.
-
-2014-06-25 Corinna Vinschen <corinna@vinschen.de>
-
- * errno.cc (errmap): Handle Windows error codes ERROR_CANCELLED,
- ERROR_CONNECTION_REFUSED, ERROR_DEV_NOT_EXIST, ERROR_DS_GENERIC_ERROR,
- ERROR_NOT_ENOUGH_QUOTA, ERROR_SERVICE_REQUEST_TIMEOUT, ERROR_TIMEOUT,
- ERROR_UNEXP_NET_ERR.
- * ldap.cc (cyg_ldap::map_ldaperr_to_errno): Drop explicit LDAP_TIMEOUT
- handling.
-
-2014-06-25 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (cyg_ldap::map_ldaperr_to_errno): Explicitely map LDAP_TIMEOUT
- to EIO.
-
-2014-06-25 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (ldap_search_sW): Replace ldap_search_stW.
- (LdapMapErrorToWin32): Import.
- * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Accommodate
- change to cyg_ldap::open.
- * ldap.cc (CYG_LDAP_TIMEOUT): Remove.
- (CYG_LDAP_ENUM_TIMEOUT): Remove.
- (def_tv): Remove.
- (enum_tv): Remove.
- (cyg_ldap::map_ldaperr_to_errno): New method to map LDAP error codes to
- POSIX errno codes. Explicitly map LDAP_NO_RESULTS_RETURNED to ENMFILE.
- (cyg_ldap::wait): Ditto.
- (struct cyg_ldap_init): New struct.
- (cyg_ldap::connect_ssl): Return ULONG. Drop setting LDAP_OPT_TIMELIMIT.
- Add call to ldap_search_sW to fetch root DSE.
- (cyg_ldap::connect_non_ssl): Ditto.
- (ldap_init_thr): New static thread function.
- (cyg_ldap::connect): New method to call connect_ssl/connect_non_ssl in
- an interruptible cygthread.
- (struct cyg_ldap_search): New struct.
- (cyg_ldap::search_s): New method to perform generic synchronous search.
- (ldap_search_thr): New static thread function.
- (cyg_ldap::search): New method to call search_s in an interruptible
- cygthread.
- (struct cyg_ldap_next_page): New struct.
- (cyg_ldap::next_page_s): New method to perform generic synchronous
- paged search.
- (ldap_next_page_thr): New static thread function.
- (cyg_ldap::next_page): New method to call next_page_s in an
- interruptible cygthread.
- (cyg_ldap::open): Return POSIX errno. Call connect method.
- (cyg_ldap::fetch_ad_account): Call search method rather than
- ldap_search_stW.
- (cyg_ldap::enumerate_ad_accounts): Return POSIX errno. Use infinite
- timeout in call to ldap_search_init_pageW.
- (cyg_ldap::next_account): Return POSIX errno. Call next_page method
- rather than ldap_get_next_page_s.
- (cyg_ldap::fetch_posix_offset_for_domain): Call search method rather
- than ldap_search_stW.
- (cyg_ldap::fetch_unix_sid_from_ad): Ditto.
- (cyg_ldap::fetch_unix_name_from_rfc2307): Ditto.
- * ldap.h (class cyg_ldap): Accommodate aforementioned changes.
- * passwd.cc (pg_ent::enumerate_ad): Ditto. Break search if one of
- cyg_ldap::enumerate_ad_accounts or cldap.next_account returns with
- an error code other than ENMFILE.
- * sec_helper.cc (cygpsid::get_id): Accommodate change to cyg_ldap::open.
- * uinfo.cc (fetch_posix_offset): Ditto.
-
2014-06-23 Corinna Vinschen <corinna@vinschen.de>
* spawn.cc (find_exec): Initialize err (CID 60111).
@@ -951,24 +623,6 @@
* dcrt0.cc (insert_file): Fix resource leaks (CIDs 59987, 59988).
-2014-06-23 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (CYG_LDAP_TIMEOUT): Set to 5 secs.
- (CYG_LDAP_ENUM_TIMEOUT): New timeout value for enumeration only. Set
- to 60 secs.
- (CYG_LDAP_ENUM_PAGESIZE): Define as number of entries per single
- search page. Set to 100. Use throughout.
- (def_tv): Rename from tv. Use throughout.
- (enum_tv): New variable. Use in call to ldap_get_next_page_s.
-
-2014-06-17 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (CYG_LDAP_TIMEOUT): Define as timeout value. Set to 30 secs
- for now. Use throughout.
- * uinfo.cc (colon_to_semicolon): New local function.
- (pwdgrp::fetch_account_from_windows): Convert all colons in AD gecos
- entry to semicolons.
-
2014-06-17 David Stacey <drstacey@tiscali.co.uk>
* libc/rexec.cc (cygwin_rexec): Make ahostbuf static to avoid returning
@@ -989,62 +643,12 @@
* timer.cc (timer_tracker::cancel): Demote api_fatal to system_printf,
printing more details about odd failure condition.
-2014-05-23 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (ldap_memfreeW): Remove.
- (ldap_msgfree): Import.
- * ldap.cc: Throughout, use ldap_msgfree to free LDAPMessage memory,
- rather than ldap_memfreeW.
- (cyg_ldap::next_account): Immediately abandon search when quiting from
- search.
-
-2014-05-22 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (ldap_abandon): Remove.
- (ldap_count_entries): Import.
- (ldap_get_next_page_s): Import.
- (ldap_result): Remove.
- (ldap_searchW): Remove.
- (ldap_search_abandon_page): Import.
- (ldap_search_init_pageW): Import.
- * ldap.cc (cyg_ldap::close): Use ldap_search_abandon_page to abandon
- search. Reset srch_id, srch_msg and srch_entry.
- (cyg_ldap::enumerate_ad_accounts): Use paged search to overcome server
- side search result set restriction.
- (cyg_ldap::next_account): Ditto.
- * ldap.h (class cyg_ldap): Add members srch_id, srch_msg and srch_entry.
- Remove member msg_id.
- (cyg_ldap::cyg_ldap): Change initialization accordingly.
-
-2014-05-22 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_auth.cc (get_server_groups): Call get_user_local_groups only if
- get_logon_server succeeded.
-
-2014-05-22 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (cyg_ldap::fetch_ad_account): Take additional domain string
- parameter. Convert into likely rootDSE string if not NULL, and use in
- subsequent call to ldap_search_stW. Add comment to explain that this
- is not the exactly correct solution.
- * ldap.h (cyg_ldap::fetch_ad_account): Change prototype accordingly.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Always use loc_ldap
- in call to fetch_posix_offset to make sure we're fetchoinmg the posix
- offsets from *our* domain controller. Only set domain variable to
- non-NULL if the account is from a trusted domain. Use domain in call
- to cyg_ldap::fetch_ad_account.
-
2014-05-22 Corinna Vinschen <corinna@vinschen.de>
* gmon.h: Pull in profile.h. Explain why.
2014-05-22 Corinna Vinschen <corinna@vinschen.de>
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Fix potential SEGV
- referencing NULL pointer.
-
-2014-05-22 Corinna Vinschen <corinna@vinschen.de>
-
* libc/bsdlib.cc (forkpty): Close master and slave if fork fails to
avoid resource leak (CID 59997).
* libc/fts.c: Update to FreeBSD version 1.39 (CID 59947).
@@ -1128,30 +732,6 @@
* syscalls.cc (getusershell): Fix buffer overrun (Coverity ID 59932).
-2014-05-15 Corinna Vinschen <corinna@vinschen.de>
-
- * external.cc (cygwin_internal): Use local name buffer instead of
- allocated one in CW_CYGNAME_FROM_WINNAME.
-
-2014-05-15 Corinna Vinschen <corinna@vinschen.de>
-
- * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump to 273.
-
-2014-05-15 Corinna Vinschen <corinna@vinschen.de>
-
- * external.cc (cygwin_internal): Implement CW_CYGNAME_FROM_WINNAME.
- Add lengthy comment to explain what we do and why.
- * include/sys/cygwin.h (cygwin_getinfo_types): Add
- CW_CYGNAME_FROM_WINNAME.
-
-2014-05-14 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_auth.cc (get_server_groups): Call get_logon_server only for
- non-builtin accounts.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Check incoming
- account name for validity in terms of the current name prefixing rules
- and refuse invalid names.
-
2014-05-13 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::ioctl): Handle the different
@@ -1165,72 +745,8 @@
* fhandler_console.cc (dev_console::save_restore): Only save current
dwEnd line rather than the one after that.
-2014-05-08 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_user::init): Fix formatting in debug output.
- (struct cyg_USER_INFO_24): Define temporarily. Explain why.
- (pwdgrp::fetch_account_from_windows): Handle sane primary group
- setting for Microsoft Accounts. Explain why.
- * wincap.h (wincaps::has_microsoft_accounts): New element.
- * wincap.cc: Implement above element throughout.
-
-2014-05-08 Corinna Vinschen <corinna@vinschen.de>
-
- * grp.cc (gr_ent::enumerate_caches): Fix copy/paste bug introducing
- an endless loop.
-
-2014-05-07 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (pwdgrp::parse_passwd): Fix an off by one computing the
- buffer len. Add comment.
- * uinfo.cc (internal_getlogin): Fix typo in comment.
-
-2014-05-07 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Tweak SID<->uid
- conversion to cover S-1-5-113, S-1-5-114, and S-1-5-1000 groups.
-
-2014-05-07 Corinna Vinschen <corinna@vinschen.de>
-
- * grp.cc (pwdgrp::parse_group): Set grp.len. Drop generating any
- gr_mem entries.
- (getgrgid_r): Don't try to copy gr_mem entries. Always set gr_mem
- to an empty list.
- (getgrnam_r): Ditto.
- (app_gr): New static struct to store group data propagated to the
- calling application via getgrgid/getgrnam.
- (getgr_cp): Fill app_gr and return pointer to app_gr.g.
- (getgrgid32): Call getgr_cp.
- (getgrnam32): Ditto.
- * passwd.cc (pwdgrp::parse_passwd): Set res.len.
- (app_pw): New static struct to store passwd data propagated to the
- calling application via getpwuid/getpwnam.
- (getpw_cp): Fill app_pw and return pointer to app_pw.p.
- (getpwuid32): Cal getpw_cp.
- (getpwnam): Ditto.
- * pwdgrp.h (struct pg_pwd): Add len member.
- (struct pg_grp): Ditto.
-
-2014-05-06 Corinna Vinschen <corinna@vinschen.de>
-
- * security.h (MAX_SUBAUTH_CNT): Drop. Use SID_MAX_SUB_AUTHORITIES
- instead throughout.
- (MAX_SID_LEN): Drop. Use SECURITY_MAX_SID_SIZE instead throughout.
-
2014-05-06 Corinna Vinschen <corinna@vinschen.de>
- * grp.cc (internal_getgroups): Drop unused cygsid variable.
- * sec_helper.cc (cygpsid::pstring): Use sid_sub_auth_count macro.
- (cygsid::get_sid): Use MAX_SUBAUTH_CNT rather than wrong constant 8.
- Don't call memcpy to copy subauthorities into SID, use assignment.
- (cygsid::getfromstr): Use MAX_SUBAUTH_CNT rather than wrong constant 8.
- * security.h (MAX_SUBAUTH_CNT): New definition. Set to 11 to cover
- Microsoft Accounts.
- (MAX_SID_LEN): Define in terms of SID member sizes and MAX_SUBAUTH_CNT.
- (DBGSID): Use MAX_SUBAUTH_CNT to define size of SubAuthority array.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Handle Micosoft
- Accounts. Handle them as well known group. Compare domain names
- case-insensitive.
* winlean.h (PIPE_REJECT_REMOTE_CLIENTS): Drop temporary definition
since Mingw64 catched up.
(DNLEN): Redefine as 16. Explain why.
@@ -1278,16 +794,6 @@
* miscfuncs.cc (check_iovec): Allow 0 as valid iovcnt value.
-2014-04-22 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (user_attr): Remove "uid" attribute.
- * ldap.h (LDAP_USER_NAME_ATTR): Remove. Change other attribute index
- values as required.
- (cyg_ldap::get_user_name): Remove inline function.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Remove code to handle
- Cygwin username different from Windows username.
- (pwdgrp::add_account_from_cygserver): Remove unnecessary cast.
-
2014-04-18 Corinna Vinschen <corinna@vinschen.de>
* winf.cc (linebuf::fromargv): Temporarily revert patch from 2014-01-24.
@@ -1318,11 +824,6 @@
* net.cc (cygwin_setsockopt): Ignore IPV6_TCLASS the same way as IP_TOS.
-2014-04-12 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Fix gid evaluation
- for local accounts.
-
2014-04-10 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/version.h (CYGWIN_VERSION_DLL_MINOR): Bump to 30.
@@ -1433,12 +934,6 @@
(exception::exception): Install unhandled exception filter.
* exceptions.cc (exception::handle_while_being_debugged): New method.
-2014-03-19 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (pg_ent::enumerate_ad): Ignore primary domain in list of
- trusted domains only if all trusted domains are enumerated anyway.
- Explain why.
-
2014-03-18 Christopher Faylor <me.cygwin2014@cgf.cx>
* fhandler_dsp.cc (fhandler_dev_dsp::fixup_after_fork): Actually call
@@ -1485,58 +980,6 @@
2014-03-12 Corinna Vinschen <corinna@vinschen.de>
- * cygheap.h (enum cygheap_pwdgrp::cache_t): Remove.
- (cygheap_pwdgrp::caching): Convert to bool.
- (cygheap_pwdgrp::pwd_cache): Add cygserver member.
- (cygheap_pwdgrp::grp_cache): Ditto.
- (cygheap_pwdgrp::nss_db_caching): Drop.
- (cygheap_pwdgrp::nss_db_full_caching): Drop.
- (cygheap_pwdgrp::nss_cygserver_caching): New method.
- (cygheap_pwdgrp::nss_disable_cygserver_caching): New method.
- * cygserver.h (client_request::request_code_t): Add
- CYGSERVER_REQUEST_PWDGRP.
- * cygserver_pwdgrp.h: New file.
- * cygtls.h (struct _local_storage): Remove pwbuf and grbuf members.
- * grp.cc (pwdgrp::prep_tls_grbuf): Drop.
- (internal_getgrsid): Handle cygserver caching and rearrange to check
- the caches first.
- (internal_getgrnam): Ditto.
- (internal_getgrgid): Ditto.
- (gr_ent::enumerate_caches): Handle cygserver cache.
- * passwd.cc (pwdgrp::prep_tls_pwbuf): Drop.
- (internal_getpwsid): Handle cygserver caching and rearrange to check
- the caches first.
- (internal_getpwnam): Ditto.
- (internal_getpwuid): Ditto.
- (pw_ent::enumerate_caches): Handle cygserver cache.
- * pwdgrp.h (pwdgrp::add_account_from_cygserver): New method declaration.
- (pwdgrp::fetch_account_from_cygserver): New method declaration.
- (pwdgrp::prep_tls_pwbuf): Drop declaration.
- (pwdgrp::prep_tls_grbuf): Drop declaration.
- (pwdgrp::add_user_from_cygserver): New inline methods.
- (pwdgrp::add_group_from_cygserver): New inline methods.
- * tlsoffsets.h: Regenerate.
- * tlsoffsets64.h: Regenerate.
- * uinfo.cc (internal_getlogin): Call internal_getgroups if cygserver
- caching is not available.
- (cygheap_pwdgrp::init): Initialize pwd_cache.cygserver and
- grp_cache.cygserver. Set caching to true.
- (cygheap_pwdgrp::nss_init_line): Drop db_cache handling entirely.
- (pwdgrp::add_account_from_windows): Drop no caching handling.
- (client_request_pwdgrp::client_request_pwdgrp): New method.
- (pwdgrp::fetch_account_from_cygserver): New method.
- (pwdgrp::add_account_from_cygserver): New method.
-
- * fhandler_disk_file.cc (fhandler_base::fstat_helper): Fix formatting.
- * include/sys/cygwin.h: Ditto.
-
-2014-03-12 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Avoid crash on
- non-domain member machines if an unknown SID comes in.
-
-2014-03-12 Corinna Vinschen <corinna@vinschen.de>
-
* include/cygwin/socket.h (IPV6_JOIN_GROUP): Revert.
(IPV6_LEAVE_GROUP): Ditto.
@@ -1596,38 +1039,6 @@
* dir.cc (opendir): Propagate any errno from build_fh_name.
-2014-03-07 Corinna Vinschen <corinna@vinschen.de>
-
- * pwdgrp.h (pwdgrp::is_passwd): New inline method.
- (pwdgrp::is_group): New inline method.
- (add_account_from_windows): Drop group argument from declaration.
- (fetch_account_from_windows): Ditto.
- (check_file): Ditto.
- (add_user_from_windows): Call add_account_from_windows accordingly.
- (add_group_from_windows): Ditto.
- * uinfo.cc (pwdgrp::add_account_from_windows): Drop group argument.
- Use is_group method instead.
- (pwdgrp::check_file): Ditto.
- (pwdgrp::fetch_account_from_windows): Ditto.
- * grp.cc: Accommodate aforementioned changes.
- * passwd.cc: Ditto.
-
-2014-03-06 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (pg_ent::enumerate_builtin): Convert pwd_builtins and
- grp_builtins to array of cygpsid pointers. Replace SID strings with
- pointers to well known SIDs.
- * sec_helper.cc (well_known_local_service_sid): Define.
- (well_known_network_service_sid): Define.
- (trusted_installer_sid): Define.
- * security.h (well_known_local_service_sid): Declare.
- (well_known_network_service_sid): Declare.
- (trusted_installer_sid): Declare.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Throughout set acc_type
- to SidTypeUnknown if LookupAccountXXX function failed. Create
- simplified passwd entry for non-user accounts, except for LocalSystem.
- Add comment.
-
2014-03-06 Corinna Vinschen <corinna@vinschen.de>
* setlsapwd.cc (setlsapwd): Use RtlSecureZeroMemory to delete password
@@ -1635,18 +1046,6 @@
2014-03-05 Corinna Vinschen <corinna@vinschen.de>
- * ldap.cc (rediscover_thread): Remove.
- (cyg_ldap::open): Remove code to rediscover DC. It just won't do the
- right thing.
- (cyg_ldap::enumerate_ad_accounts): Change to be self-sufficient (no
- explicit open call required). Enumerate on a DC of the domain itself
- instead of relying on delegation. Remove ill-advised code trying to
- generate rootdse from domain name.
- * passwd.cc (pg_ent::enumerate_ad): Drop explicit call to
- cyg_ldap::open.
-
-2014-03-05 Corinna Vinschen <corinna@vinschen.de>
-
* include/cygwin/config.h (__TM_GMTOFF): Define.
(__TM_ZONE): Define.
@@ -1673,115 +1072,6 @@
* exception.h (exception::exception): Install vectored exception
handler rather than vectored continue handler.
-2014-03-03 Corinna Vinschen <corinna@vinschen.de>
-
- * sec_helper.cc (cygpsid::get_id): Move Samba SID->uid/gid mapping
- from get_sids_info here.
- (get_sids_info): Vice versa.
- * security.cc (convert_samba_sd): New static function to map a Samba
- security descriptor to a security descriptor with UNIX users and groups
- converted to Windows SIDs per RFC 2307 mapping.
- (check_file_access): Call convert_samba_sd on Samba security
- descriptors.
-
-2014-02-28 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Only fetch extended
- user info if we're creating a passwd entry. Add comment.
-
-2014-02-28 Corinna Vinschen <corinna@vinschen.de>
-
- * cygheap.h (cygheap_user::sid): Return reference to cygpsid rather
- than PSID.
- (cygheap_user::saved_sid): Ditto.
- (cygheap_pwdgrp::cache_t): New type.
- (cygheap_pwdgrp::caching): Convert to cache_t.
- (cygheap_pwdgrp::nss_db_caching): Change accordingly.
- (cygheap_pwdgrp::nss_db_full_caching): New inline method.
- * grp.cc (internal_getgroups): Reinvent. Take cyg_ldap pointer as
- third parameter and use throughout.
- (getgroups32): Call internal_getgroups.
- * pwdgrp.h (internal_getgroups): Declare.
- * uinfo.cc (internal_getlogin): Partial rewrite to accommodate having
- no connection to the DC. Give primary group from user token more
- weight. Generate group entries for all groups in the user token if
- caching is set to NSS_FULL_CACHING.
- (cygheap_pwdgrp::init): Initialize caching to NSS_FULL_CACHING.
- (cygheap_pwdgrp::nss_init_line): Handle "db_cache: full".
- (pwdgrp::add_account_from_windows): Fix group handling in non-caching
- mode.
- (pwdgrp::fetch_account_from_windows): Default primary group for the
- current user to primary group from user token. Check for primary
- domain first after LookupAccountSid failed.
-
-2014-02-27 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (CheckTokenMembership): Import.
- * external.cc (cygwin_internal): Call get_uid/get_gid instead of get_id.
- * grp.cc (internal_getgrsid): Take additional cyg_ldap pointer.
- Forward to pwdgrp::add_group_from_windows.
- (internal_getgrnam): Ditto.
- (internal_getgrgid): Ditto.
- (gr_ent::enumerate_local): Drop ugid_caching bool from call to
- pwdgrp::fetch_account_from_windows.
- (getgroups32): Rename from internal_getgroups and drop getgroups32 stub.
- Drop srchsid parameter and code handling it. Add local cyg_ldap
- instance and forward to internal_getgrXXX.
- (getgroups): Call getgroups32.
- (get_groups): Add local cyg_ldap instance and forward to
- internal_getgrXXX.
- (getgrouplist): Ditto.
- (setgroups32): Ditto.
- * ldap.cc (cyg_ldap::open): Don't call close. Return true if connection
- is already open.
- (cyg_ldap::remap_uid): Forward this to internal_getpwsid.
- (cyg_ldap::remap_gid): Forward this to internal_getgrsid.
- * passwd.cc (internal_getpwsid): Take additional cyg_ldap pointer.
- Forward to pwdgrp::add_user_from_windows.
- (internal_getpwnam): Ditto.
- (internal_getpwuid): Ditto.
- (pg_ent::enumerate_builtin): Drop ugid_caching bool from call to
- pwdgrp::fetch_account_from_windows.
- (pg_ent::enumerate_sam): Ditto.
- (pg_ent::enumerate_ad): Ditto. Forward local cldap instead.
- * pwdgrp.h (internal_getpwsid): Align declaration to above change.
- (internal_getpwnam): Ditto.
- (internal_getpwuid): Ditto.
- (internal_getgrsid): Ditto.
- (internal_getgrgid): Ditto.
- (internal_getgrnam): Ditto.
- (internal_getgroups): Drop declaration.
- (pwdgrp::add_account_from_windows): Align declaration to below change.
- (pwdgrp::add_user_from_windows): Ditto.
- (pwdgrp::add_group_from_windows): Ditto.
- * sec_acl.cc (setacl): Add local cyg_ldap instance and forward to
- internal_getpwuid and internal_getgrgid.
- (getacl): Add local cyg_ldap instance and forward to cygpsid::get_id.
- (aclfromtext32): Add local cyg_ldap instance and forward to
- internal_getpwnam and internal_getgrnam.
- * sec_helper.cc (cygpsid::get_id): Take additional cyg_ldap pointer.
- Forward to internal_getgrsid and internal_getpwsid.
- (get_sids_info): Drop ldap_open. Forward local cldap to
- internal_getpwsid and internal_getgrXXX. Call CheckTokenMembership
- rather than internal_getgroups.
- * security.h (cygpsid::get_id): Add cyg_ldap pointer, drop default
- parameter.
- (cygpsid::get_uid): Add cyg_ldap pointer. Call get_id accordingly.
- (cygpsid::get_gid): Ditto.
- * uinfo.cc (internal_getlogin): Add local cyg_ldap instance and forward
- to internal_getpwXXX and internal_getgrXXX calls.
- (pwdgrp::add_account_from_windows): Take additional cyg_ldap pointer.
- Forward to pwdgrp::fetch_account_from_windows.
- (fetch_posix_offset): Drop ldap_open argument and handling. Get
- cyg_ldap instance as pointer.
- (pwdgrp::fetch_account_from_windows): Take additional cyg_ldap pointer.
- Use it if it's not NULL, local instance otherwise. Drop ldap_open.
- Drop fetching extended group arguments from AD for speed.
-
-2014-02-27 Corinna Vinschen <corinna@vinschen.de>
-
- * path.cc (find_fast_cwd_pointer): Fix preceeding comment.
-
2014-02-25 Christopher Faylor <me.cygwin2014@cgf.cx>
* fhandler.h (fhandler_console::scroll_buffer_screen): New function.
@@ -1820,32 +1110,10 @@
2014-02-22 Corinna Vinschen <corinna@vinschen.de>
- * external.cc (cygwin_internal): Add cases for CW_GETNSSSEP,
- CW_GETPWSID and CW_GETGRSID.
- * grp.cc (internal_getgrsid_from_db): New function.
- * passwd.cc (internal_getpwsid_from_db): New function.
- (pg_ent::setent): Add special case for call from mkpasswd/mkgroup.
- * pwdgrp.h (internal_getpwsid_from_db): Declare.
- (internal_getgrsid_from_db): Declare.
- (enum nss_enum_t): Move to include/sys/cygwin.h.
- (class pg_ent): Add comment.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Fix typo in comment.
- Change "UNIX" to "Unix" in domain name.
- * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_GETNSSSEP,
- CW_GETPWSID and CW_GETGRSID.
- (enum nss_enum_t): Define here.
-
-2014-02-21 Corinna Vinschen <corinna@vinschen.de>
-
- * pwdgrp.h (pwdgrp::fetch_account_from_windows): Add bool parameter
- to declaration, set to true by default.
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Add bool parameter
- "ugid_caching". Only add account to ugid_cache if set to true.
- * grp.cc (gr_ent::enumerate_local): Call fetch_account_from_windows
- with ugid_caching parameter set to false.
- * passwd.cc (pg_ent::enumerate_builtin): Ditto.
- (pg_ent::enumerate_sam): Ditto.
- (pg_ent::enumerate_ad): Ditto.
+ * external.cc (cygwin_internal): Add cases for CW_GETPWSID and
+ CW_GETGRSID.
+ * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_SETENT, CW_GETENT,
+ CW_ENDENT, CW_GETNSSSEP, CW_GETPWSID and CW_GETGRSID.
2014-02-20 Corinna Vinschen <corinna@vinschen.de>
@@ -1857,115 +1125,11 @@
* grp.cc (get_groups): Don't add gid to list if it's ILLEGAL_GID.
(getgrouplist): Return number of groups, just like glibc.
-2014-02-19 Corinna Vinschen <corinna@vinschen.de>
-
- * passwd.cc (pg_ent::setent): Initialize cygheap domain info.
- * sec_auth.cc (get_logon_server): Ditto.
-
-2014-02-18 Corinna Vinschen <corinna@vinschen.de>
-
- * external.cc (cygwin_internal): Handle new CW_SETENT, CW_GETENT and
- CW_ENDENT info types.
- * grp.cc (setgrent_filtered): New function, called from cygwin_internal.
- (getgrent_filtered): Ditto.
- (endgrent_filtered): Ditto.
- * passwd.cc (pg_ent::setent): Set state explicitely to from_cache.
- (pg_ent::getent): Handle the fact that a DC has no SAM and enumerating
- local accounts is equivalent to enumerating domain accounts.
- (setpwent_filtered): New function, called from cygwin_internal.
- (getpwent_filtered): Ditto.
- (endpwent_filtered): Ditto.
- * pwdgrp.h (setpwent_filtered): Declare.
- (getgrent_filtered): Ditto.
- (endgrent_filtered): Ditto.
- (setpwent_filtered): Ditto.
- (getpwent_filtered): Ditto.
- (endpwent_filtered): Ditto.
- * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_SETENT, CW_GETENT,
- and CW_ENDENT.
-
2014-02-18 Corinna Vinschen <corinna@vinschen.de>
* setlsapwd.cc (setlsapwd): Fix conditional expression after breaking
it on 2014-01-23.
-2014-02-17 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (ldap_abandon): Import.
- (ldap_result): Import.
- (ldap_searchW): Import.
- (NetGroupEnum): Import.
- (NetLocalGroupEnum): Import.
- (NetUserEnum): Import.
- * cygheap.h (class cygheap_pwdgrp): Add members enums and enum_tdoms.
- (cygheap_pwdgrp::nss_db_enums): New inline method.
- (cygheap_pwdgrp::nss_db_enum_tdoms): Ditto.
- * cygtls.h (struct _local_storage): Drop unused members pw_pos and
- grp_pos.
- * grp.cc (grent): New static variable of class gr_ent.
- (gr_ent::enumerate_caches): New method.
- (gr_ent::enumerate_local): New method.
- (gr_ent::getgrent): New method.
- (setgrent): Call gr_ent method.
- (getgrent32): Ditto.
- (endgrent): Ditto.
- * ldap.cc (sid_attr): Rename from nfs_attr.
- (cyg_ldap::close): Abandon still running asynchronous search.
- (cyg_ldap::fetch_ad_account): Reduce filter buffer size.
- (cyg_ldap::enumerate_ad_accounts): New method.
- (cyg_ldap::next_account): New method.
- (cyg_ldap::fetch_posix_offset_for_domain): Reduce filter buffer size.
- (cyg_ldap::fetch_unix_sid_from_ad): Ditto. Fix return value in case
- no value has been read.
- (cyg_ldap::fetch_unix_name_from_rfc2307): Reduce filter buffer size.
- * ldap.h (class cyg_ldap): Add msg_id member.
- (cyg_ldap::enumerate_ad_accounts): Declare.
- (cyg_ldap::next_account): Declare:
- * passwd.cc (pwent): New static variable of class pw_ent.
- (pg_ent::clear_cache): New method.
- (pg_ent::setent): New method.
- (pg_ent::getent): New method.
- (pg_ent::endent): New method.
- (pg_ent::enumerate_file): New method.
- (pg_ent::enumerate_builtin): New method.
- (pg_ent::enumerate_sam): New method.
- (pg_ent::enumerate_ad): New method.
- (pw_ent::enumerate_caches): New method.
- (pw_ent::enumerate_local): New method.
- (pw_ent::getpwent): New method.
- (setpwent): Call pw_ent method.
- (getpwent): Ditto.
- (endpwent): Ditto.
- * pwdgrp.h (class pwdgrp): Define pg_ent, pw_ent and gr_ent as friend
- classes.
- (pwdgrp::add_account_post_fetch): Declare with extra bool parameter.
- (pwdgrp::file_attr): New inline method.
- (enum nss_enum_t): Define.
- (class pg_ent): Define.
- (class pw_ent): Define.
- (class gr_ent): Define.
- * tlsoffsets.h: Regenerate.
- * tlsoffsets64.h: Ditto.
- * uinfo.cc (cygheap_pwdgrp::init): Initialize enums and enum_tdoms.
- (cygheap_pwdgrp::nss_init_line): Fix typo in preceeding comment.
- Handle new "db_enum" keyword.
- (pwdgrp::add_account_post_fetch): Take additional `bool lock' parameter
- and acquire pglock before adding element to array if lock is true.
- (pwdgrp::add_account_from_file): Call add_account_post_fetch with lock
- set to true.
- (pwdgrp::add_account_from_windows): Ditto in case of caching.
- (pwdgrp::fetch_account_from_windows): Handle builtin aliases only
- known to the domain controller. Only call NetLocalGroupGetInfo for
- aliases.
-
-2014-02-16 Corinna Vinschen <corinna@vinschen.de>
-
- * miscfuncs.h (NT_readline::close): New function to close handle.
- (NT_readline::~NT_readline): Call close.
- * sec_auth.cc (verify_token): Use constructor to initialize tok_usersid.
- * security.h (cygsid::cygsid): Add copy constructor taking cygsid as
- source.
-
2014-02-16 Corinna Vinschen <corinna@vinschen.de>
* dcrt0.cc (dll_crt0_1): Call initial_setlocale before fetching
@@ -2006,95 +1170,18 @@
when !winpid. Simplify logic. Don't do duplicate detection for
winpid.
-2014-02-14 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Default to /bin/bash
- as login shell.
-
-2014-02-13 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): If domain name
- has no dot, it's a Netbios name. Change the search filter expression
- accordingly and filter by flatName. Add comment.
- * uinfo.cc (cygheap_domain_info::init): Gracefully handle NULL
- DnsDomainName and DomainSid members in DS_DOMAIN_TRUSTSW structure.
- Add comment. Fix comment preceeding fetching the mapping server
- from registry.
- (pwdgrp::fetch_account_from_file): Convert str to a local array.
- (fetch_posix_offset): New static function.
- (pwdgrp::fetch_account_from_windows): Add debug output in case
- LookupAccountSidW fails. Simplify code by calling fetch_posix_offset
- where appropriate. If LookupAccountSidW fails, check if the SID is
- one of the known trusted domains. If so, create a more informative
- account entry.
-
-2014-02-12 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_pwdgrp::nss_init_line): Explicitely ignore a colon
- as separator char.
-
2014-02-11 Christopher Faylor <me.cygwin2014@cgf.cx>
- * winsup.h: Turn off previous workaround but leave a comment.
-
-2014-02-11 Corinna Vinschen <corinna@vinschen.de>
-
- * ldap.cc (rediscover_thread): Give argument a useful name.
- * miscfuncs.cc (NT_readline::init): It's a really bad idea trying to
- print a pointer to a PUNICODE_STRING as PUNICODE_STRING. Fix it.
- * uinfo.cc (cygheap_domain_info::init): Print status codes as hex
- values in debug output.
-
-2014-02-11 Corinna Vinschen <corinna@vinschen.de>
-
- * autoload.cc (NetLocalGroupGetInfo): Replace NetGroupGetInfo.
- * cygheap.h (class cygheap_ugid_cache): Move ugid_cache_t type here
- and rename.
- (struct init_cygheap): Add cygheap_ugid_cache member "ugid_cache".
- * pwdgrp.h (class ugid_cache_t): Remove here.
- * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Accommodate
- move of ugid_cache to cygheap.
- * sec_helper.cc (get_sids_info): Ditto.
- * uinfo.cc (ugid_cache): Remove.
- (pwdgrp::fetch_account_from_windows): Define id_val globally.
- Move SidTypeAlias handling into SidTypeUser/SidTypeGroup branch since
- aliases are handled like groups in SAM. Accommodate move of ugid_cache
- to cygheap. Consolidate code reading SAM comments into a single branch
- for both, SidTypeUser and SidTypeAlias. For SidTypeAlias, fix thinko
- and call NetLocalGroupGetInfo rather than NetGroupGetInfo. Simplify
- code setting Cygwin primary group for SAM accounts. Add code to handle
- UNIX uid/gid from SAM comment.
-
-2014-02-11 Christopher Faylor <me.cygwin2014@cgf.cx>
-
- * winsup.h (Interlocked*): Use intrinsic versions of Interlocked
- functions.
-
* cygwin.sc.in: More closely emulate default pe/i386 linker script.
2014-02-10 Corinna Vinschen <corinna@vinschen.de>
- * uinfo.cc (cygheap_domain_info::init): Drop accidentally leftover if
- statement.
-
-2014-02-10 Corinna Vinschen <corinna@vinschen.de>
-
- * uinfo.cc (cygheap_domain_info::init): Fix handling of account domain
- on donmain controllers. Explain why.
-
-2014-02-10 Corinna Vinschen <corinna@vinschen.de>
-
* cygheap.cc (cwcsdup): Change parameter to correct PWCSTR.
(cwcsdup1): Ditto.
* cygheap_malloc.h: Change declarations accordingly.
2014-02-10 Corinna Vinschen <corinna@vinschen.de>
- * uinfo.cc (pwdgrp::fetch_account_from_windows): Add code to allow
- setting the primary group from the SAM comment field.
-
-2014-02-10 Corinna Vinschen <corinna@vinschen.de>
-
* dcrt0.cc (child_info_spawn::handle_spawn): Call fixup_lockf_after_exec
with additional argument to specify if the process has been execed
or spawned.
@@ -2112,161 +1199,11 @@
* environ.cc (strbrk): New function.
(parse_options): Use strbrk to parse CYGWIN environment variable.
-2014-02-09 Corinna Vinschen <corinna@vinschen.de>
-
- Introduce reading passwd/group entries from SAM/AD. Introduce
- /etc/nsswitch.conf file to configure it.
- * Makefile.in (DLL_OFILES): Add ldap.o.
- * autoload.cc: Import ldap functions from wldap32.dll.
- (DsEnumerateDomainTrustsW): Import.
- (NetGroupGetInfo): Import.
- * cygheap.h (class cygheap_domain_info): New class to keep global
- domain info.
- (class cygheap_pwdgrp): New class to keep passwd/group caches and
- configuration info from /etc/nssswitch.conf.
- (struct init_cygheap): Add cygheap_domain_info member "dom" and
- cygheap_pwdgrp member "pg".
- * cygtls.h (struct _local_storage): Remove unused member "res".
- Rearrange slightly, Add members pwbuf and grbuf to implement non-caching
- passwd/group fetching from SAM/AD. Make pw_pos and pw_pos unsigned.
- * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Add RFC 2307
- uid/gid mapping.
- * fhandler_process.cc: Drop including pwdgrp.h.
- * fhandler_procsysvipc.cc: Ditto.
- * fhandler_registry.cc (fhandler_registry::fstat): Set key uid/gid
- to ILLEGAL_UID/ILLEGAL_GID rather than UNKNOWN_UID/UNKNOWN_GID.
- * grp.cc (group_buf): Drop.
- (gr): Drop.
- (pwdgrp::parse_group): Fill pg_grp.
- (pwdgrp::read_group): Remove.
- (pwdgrp::init_grp): New method.
- (pwdgrp::prep_tls_grbuf): New method.
- (pwdgrp::find_group): New methods.
- (internal_getgrsid): Convert to call new pwdgrp methods.
- (internal_getgrnam): Ditto.
- (internal_getgrgid): Ditto.
- (getgrgid_r): Drop 2nd parameter from internal_getgrgid call.
- (getgrgid32): Ditto.
- (getgrnam_r): Ditto for internal_getgrnam.
- (getgrnam32): Ditto.
- (getgrent32): Convert to call new pwdgrp methods.
- (internal_getgrent): Remove.
- (internal_getgroups): Simplify, especially drop calls to
- internal_getgrent.
- * ldap.cc: New file implementing cyg_ldap class for LDAP access to AD
- and RFC 2307 server.
- * ldap.h: New header, declaring cyg_ldap class.
- * passwd.cc (passwd_buf): Drop.
- (pr): Drop.
- (pwdgrp::parse_passwd): Fill pg_pwd.
- (pwdgrp::read_passwd): Remove.
- (pwdgrp::init_pwd): New method.
- (pwdgrp::prep_tls_pwbuf): New method.
- (find_user): New methods.
- (internal_getpwsid): Convert to call new pwdgrp methods.
- (internal_getpwnam): Ditto.
- (internal_getpwuid): Ditto.
- (getpwuid32): Drop 2nd parameter from internal_getpwuid call.
- (getpwuid_r): Ditto.
- (getpwnam): Ditto for internal_getpwnam.
- (getpwnam_r): Ditto.
- (getpwent): Convert to call new pwdgrp methods.
- * path.cc (class etc): Remove all methods.
- * path.h (class etc): Drop.
- * pinfo.cc (pinfo_basic::pinfo_basic): Set gid to ILLEGAL_GID rather
- than UNKNOWN_GID.
- (pinfo_init): Ditto.
- * pwdgrp.h (internal_getpwnam): Drop 2nd parameter from declaration.
- (internal_getpwuid): Ditto.
- (internal_getgrgid): Ditto.
- (internal_getgrnam): Ditto.
- (internal_getgrent): Drop declaration.
- (enum fetch_user_arg_type_t): New type.
- (struct fetch_user_arg_t): New type.
- (struct pg_pwd): New type.
- (struct pg_grp): New type.
- (class pwdgrp): Rework to provide functions for file and db requests
- and caching.
- (class ugid_cache_t): New class to provide RFC 2307 uid map caching.
- (ugid_cache): Declare.
- * sec_acl.cc: Drop including pwdgrp.h.
- * sec_auth.cc: Drop including dsgetdc.h and pwdgrp.h.
- (get_logon_server): Convert third parameter to ULONG flags argument
- to allow arbitrary flags values in DsGetDcNameW call and change calls
- to this function throughout. Use cached account domain name rather
- than calling GetComputerNameW.
- (get_unix_group_sidlist): Remove.
- (get_server_groups): Drop call to get_unix_group_sidlist.
- (verify_token): Rework token group check without calling
- internal_getgrent.
- * sec_helper.cc (cygpsid::pstring): New methods, like string() but
- return pointer to end of string.
- (cygsid::getfromstr): Add wide character implementation.
- (get_sids_info): Add RFC 2307 uid/gid mapping for Samba shares.
- * security.cc: Drop including pwdgrp.h.
- * security.h (DEFAULT_UID): Remove.
- (UNKNOWN_UID): Remove.
- (UNKNOWN_GID): Remove.
- (uinfo_init): Move here from winsup.h.
- (ILLEGAL_UID): Ditto.
- (ILLEGAL_GID): Ditto.
- (UNIX_POSIX_OFFSET): Define. Add lengthy comment.
- (UNIX_POSIX_MASK): Ditto.
- (MAP_UNIX_TO_CYGWIN_ID): Ditto.
- (ILLEGAL_UID16): Move here from winsup.h.
- (ILLEGAL_GID16): Ditto.
- (uid16touid32): Ditto.
- (gid16togid32): Ditto.
- (sid_id_auth): New convenience macro for SID component access.
- (sid_sub_auth_count): Ditto.
- (sid_sub_auth): Ditto.
- (sid_sub_auth_rid): Ditto.
- (cygpsid::pstring): Declare.
- (cygsid::getfromstr): Declare wide character variant.
- (cygsid::operator=): Ditto.
- (cygsid::operator*=): Ditto.
- (get_logon_server): Change declaration according to source code.
- * setlsapwd.cc (setlsapwd): Drop 2nd parameter from internal_getpwnam
- call.
- * shared.cc (memory_init): Call cygheap->pg.init in first process.
- * syscalls.cc: Drop including pwdgrp.h.
- * tlsoffsets.h: Regenerate.
- * tlsoffsets64.h: Ditto.
- * uinfo.cc (internal_getlogin): Drop gratuitious internal_getpwuid
- call. Fix debug output. Overwrite user gid in border case of a
- missing passwd file while a group file exists.
- (pwdgrp::add_line): Allocate memory on cygheap.
- (pwdgrp::load): Remove.
- (ugid_cache): Define.
- (cygheap_pwdgrp::init): New method.
- (cygheap_pwdgrp::nss_init_line): New method.
- (cygheap_pwdgrp::_nss_init): New method.
- (cygheap_domain_info::init): New method.
- (logon_sid): Define.
- (get_logon_sid): New function.
- (pwdgrp::add_account_post_fetch): New method.
- (pwdgrp::add_account_from_file): New methods.
- (pwdgrp::add_account_from_windows): New methods.
- (pwdgrp::check_file): New method.
- (pwdgrp::fetch_account_from_line): New method.
- (pwdgrp::fetch_account_from_file): New method.
- (pwdgrp::fetch_account_from_windows): New method.
- * winsup.h: Move aforementioned macros and declarations to security.h.
-
2014-02-09 Christopher Faylor <me.cygwin2014@cgf.cx>
* sigproc.cc (sig_send): Don't bother with an error message if we are
exiting.
-2014-02-08 Corinna Vinschen <corinna@vinschen.de>
-
- * miscfuncs.h (class NT_readline): New class to implement line-wise
- reading from file using native NT functions.
- * miscfuncs.cc (NT_readline::init): New method.
- (NT_readline::fgets): New method.
- * mount.cc (mount_info::from_fstab): Utilize NT_readline to read
- fstab files.
-
2014-02-06 Corinna Vinschen <corinna@vinschen.de>
* fhandler_disk_file.cc (fhandler_disk_file::fchown): Fix typo in
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 6f603d887..7daad7b54 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -226,7 +226,6 @@ DLL_OFILES:= \
ioctl.o \
ipc.o \
kernel32.o \
- ldap.o \
libstdcxx_wrapper.o \
localtime.o \
lsearch.o \
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 659898ba6..4351173be 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -1,7 +1,7 @@
/* autoload.cc: all dynamic load stuff.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -536,7 +536,6 @@ wsock_init ()
LoadDLLprime (ws2_32, _wsock_init, 0)
-LoadDLLfunc (CheckTokenMembership, 12, advapi32)
LoadDLLfunc (CreateProcessAsUserW, 44, advapi32)
LoadDLLfunc (DeregisterEventSource, 4, advapi32)
LoadDLLfunc (LogonUserW, 24, advapi32)
@@ -581,46 +580,15 @@ LoadDLLfuncEx2 (IdnToAscii, 20, kernel32, 1, 0)
LoadDLLfuncEx2 (IdnToUnicode, 20, kernel32, 1, 0)
LoadDLLfunc (LocaleNameToLCID, 8, kernel32)
-/* ldap functions are cdecl! */
-#pragma push_macro ("mangle")
-#undef mangle
-#define mangle(name, n) #name
-LoadDLLfunc (ldap_bind_s, 0, wldap32)
-LoadDLLfunc (ldap_count_entries, 0, wldap32)
-LoadDLLfunc (ldap_count_valuesW, 0, wldap32)
-LoadDLLfunc (ldap_first_entry, 0, wldap32)
-LoadDLLfunc (ldap_get_next_page_s, 0, wldap32)
-LoadDLLfunc (ldap_get_valuesW, 0, wldap32)
-LoadDLLfunc (ldap_get_values_lenW, 0, wldap32)
-LoadDLLfunc (ldap_initW, 0, wldap32)
-LoadDLLfunc (ldap_msgfree, 0, wldap32)
-LoadDLLfunc (ldap_next_entry, 0, wldap32)
-LoadDLLfunc (ldap_search_abandon_page, 0, wldap32)
-LoadDLLfunc (ldap_search_init_pageW, 0, wldap32)
-LoadDLLfunc (ldap_search_sW, 0, wldap32)
-LoadDLLfunc (ldap_set_option, 0, wldap32)
-LoadDLLfunc (ldap_sslinitW, 0, wldap32)
-LoadDLLfunc (ldap_unbind, 0, wldap32)
-LoadDLLfunc (ldap_value_freeW, 0, wldap32)
-LoadDLLfunc (ldap_value_free_len, 0, wldap32)
-LoadDLLfunc (LdapGetLastError, 0, wldap32)
-LoadDLLfunc (LdapMapErrorToWin32, 0, wldap32)
-#pragma pop_macro ("mangle")
-
LoadDLLfunc (WNetCloseEnum, 4, mpr)
LoadDLLfunc (WNetEnumResourceW, 16, mpr)
LoadDLLfunc (WNetGetProviderNameW, 12, mpr)
LoadDLLfunc (WNetGetResourceInformationW, 16, mpr)
LoadDLLfunc (WNetOpenEnumW, 20, mpr)
-LoadDLLfunc (DsEnumerateDomainTrustsW, 16, netapi32)
LoadDLLfunc (DsGetDcNameW, 24, netapi32)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
-LoadDLLfunc (NetGroupEnum, 28, netapi32)
-LoadDLLfunc (NetLocalGroupEnum, 28, netapi32)
-LoadDLLfunc (NetLocalGroupGetInfo, 16, netapi32)
LoadDLLfunc (NetUseGetInfo, 16, netapi32)
-LoadDLLfunc (NetUserEnum, 32, netapi32)
LoadDLLfunc (NetUserGetGroups, 28, netapi32)
LoadDLLfunc (NetUserGetInfo, 16, netapi32)
LoadDLLfunc (NetUserGetLocalGroups, 32, netapi32)
diff --git a/winsup/cygwin/configure b/winsup/cygwin/configure
index 522fae6df..6dc655e30 100755
--- a/winsup/cygwin/configure
+++ b/winsup/cygwin/configure
@@ -1,8 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for Cygwin DLL 0.
-#
-# Report bugs to <cygwin@cygwin.com>.
+# Generated by GNU Autoconf 2.69.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -265,11 +263,10 @@ fi
$as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
else
- $as_echo "$0: Please tell bug-autoconf@gnu.org and cygwin@cygwin.com
-$0: about your system, including any error possibly output
-$0: before this message. Then install a modern shell, or
-$0: manually run the script under such a shell if you do
-$0: have one."
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
fi
exit 1
fi
@@ -577,12 +574,12 @@ MFLAGS=
MAKEFLAGS=
# Identity of this package.
-PACKAGE_NAME='Cygwin DLL'
-PACKAGE_TARNAME='cygwin'
-PACKAGE_VERSION='0'
-PACKAGE_STRING='Cygwin DLL 0'
-PACKAGE_BUGREPORT='cygwin@cygwin.com'
-PACKAGE_URL='https://cygwin.com'
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
ac_unique_file="Makefile.in"
ac_no_link=no
@@ -737,7 +734,7 @@ sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
includedir='${prefix}/include'
oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+docdir='${datarootdir}/doc/${PACKAGE}'
infodir='${datarootdir}/info'
htmldir='${docdir}'
dvidir='${docdir}'
@@ -1237,7 +1234,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures Cygwin DLL 0 to adapt to many kinds of systems.
+\`configure' configures this package to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1285,7 +1282,7 @@ Fine tuning of the installation directories:
--infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man]
- --docdir=DIR documentation root [DATAROOTDIR/doc/cygwin]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
--htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR]
@@ -1302,9 +1299,7 @@ _ACEOF
fi
if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of Cygwin DLL 0:";;
- esac
+
cat <<\_ACEOF
Optional Features:
@@ -1335,8 +1330,7 @@ Some influential environment variables:
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
-Report bugs to <cygwin@cygwin.com>.
-Cygwin DLL home page: <https://cygwin.com>.
+Report bugs to the package provider.
_ACEOF
ac_status=$?
fi
@@ -1399,7 +1393,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-Cygwin DLL configure 0
+configure
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1529,7 +1523,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by Cygwin DLL $as_me 0, which was
+It was created by $as_me, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -1877,7 +1871,6 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
ac_config_headers="$ac_config_headers config.h"
ac_aux_dir=
@@ -4981,7 +4974,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by Cygwin DLL $as_me 0, which was
+This file was extended by $as_me, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -5037,14 +5030,13 @@ $config_files
Configuration headers:
$config_headers
-Report bugs to <cygwin@cygwin.com>.
-Cygwin DLL home page: <https://cygwin.com>."
+Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-Cygwin DLL config.status 0
+config.status
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/winsup/cygwin/configure.ac b/winsup/cygwin/configure.ac
index fc7697b3b..9d16e4edd 100644
--- a/winsup/cygwin/configure.ac
+++ b/winsup/cygwin/configure.ac
@@ -1,19 +1,5 @@
-dnl Autoconf configure script for Cygwin.
-dnl Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-dnl 2006, 2008, 2009, 2011, 2012, 2013, 2014 Red Hat, Inc.
-dnl
-dnl This file is part of Cygwin.
-dnl
-dnl This software is a copyrighted work licensed under the terms of the
-dnl Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-dnl details.
-dnl
-dnl Process this file with autoconf to produce a configure script.
-
AC_PREREQ(2.59)dnl
-AC_INIT([Cygwin DLL], 0,
- cygwin@cygwin.com, cygwin, https://cygwin.com)
-AC_CONFIG_SRCDIR(Makefile.in)
+AC_INIT(Makefile.in)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_AUX_DIR(..)
diff --git a/winsup/cygwin/cygerrno.h b/winsup/cygwin/cygerrno.h
index b9ec7b61d..337dd75fc 100644
--- a/winsup/cygwin/cygerrno.h
+++ b/winsup/cygwin/cygerrno.h
@@ -1,7 +1,7 @@
/* cygerrno.h: main Cygwin header file.
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2009, 2010, 2011, 2012, 2013,
- 2014 Red Hat, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2009, 2010, 2011, 2012, 2013
+ Red Hat, Inc.
This file is part of Cygwin.
@@ -16,15 +16,10 @@ details. */
void __reg3 seterrno_from_win_error (const char *file, int line, DWORD code);
void __reg3 seterrno_from_nt_status (const char *file, int line, NTSTATUS status);
+void __reg2 seterrno (const char *, int line);
int __reg2 geterrno_from_win_error (DWORD code = GetLastError (), int deferrno = 13 /*EACCESS*/);
int __reg2 geterrno_from_nt_status (NTSTATUS status, int deferrno = 13 /*EACCESS*/);
-inline void __attribute__ ((always_inline))
-seterrno (const char *file, int line)
-{
- seterrno_from_win_error (file, line, GetLastError ());
-}
-
#define __seterrno() seterrno (__FILE__, __LINE__)
#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val)
#define __seterrno_from_nt_status(status) seterrno_from_nt_status (__FILE__, __LINE__, status)
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index ce7b02a86..26564ad9c 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -130,7 +130,7 @@ init_cygheap::close_ctty ()
cygcheck can print the paths into which the Cygwin DLL has been
installed for debugging purposes.
- Last but not least, the new cygwin properties datastructure is checked
+ Last but not least, the new cygwin properties datastrcuture is checked
for the "disabled_key" value, which is used to determine whether the
installation key is actually added to all object names or not. This is
used as a last resort for debugging purposes, usually. However, there
@@ -267,17 +267,6 @@ cygheap_init ()
cygheap->init_tls_list ();
}
-/* Initial Cygwin heap setup.
- Called by root process of a Cygwin process tree. */
-void
-setup_cygheap ()
-{
- cygheap_init ();
- cygheap->user.init ();
- cygheap->init_installation_root (); /* Requires user.init! */
- cygheap->pg.init ();
-}
-
#define nextpage(x) ((char *) roundup2 ((uintptr_t) (x), \
wincap.allocation_granularity ()))
#define allocsize(x) ((SIZE_T) nextpage (x))
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index ff86d5ef3..a83b3d7c7 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -11,7 +11,6 @@ details. */
#include "hires.h"
#include "cygheap_malloc.h"
-#include "pwdgrp.h"
#define incygheap(s) (cygheap && ((char *) (s) >= (char *) cygheap) && ((char *) (s) <= ((char *) cygheap_max)))
@@ -156,8 +155,8 @@ public:
}
void set_sid (PSID new_sid) { effec_cygsid = new_sid;}
void set_saved_sid () { saved_cygsid = effec_cygsid; }
- cygpsid &sid () { return effec_cygsid; }
- cygpsid &saved_sid () { return saved_cygsid; }
+ PSID sid () { return effec_cygsid; }
+ PSID saved_sid () { return saved_cygsid; }
const char *ontherange (homebodies what, struct passwd * = NULL);
#define NO_IMPERSONATION NULL
bool issetuid () const { return curr_imp_token != NO_IMPERSONATION; }
@@ -308,23 +307,14 @@ private:
available in shared memory avoids to test for the version every time
around. Default to new version. */
fcwd_version_t fast_cwd_version;
- void override_win32_cwd (bool init, ULONG old_dismount_count);
+ void override_win32_cwd (bool, ULONG);
public:
UNICODE_STRING win32;
static muto cwd_lock;
const char *get_posix () const { return posix; };
- void reset_posix (wchar_t *w_cwd);
- char *get (char *buf, int need_posix = 1, int with_chroot = 0,
- unsigned ulen = NT_MAX_PATH);
- PWCHAR get (PWCHAR buf, unsigned buflen = NT_MAX_PATH)
- {
- cwd_lock.acquire ();
- buf[0] = L'\0';
- wcsncat (buf, win32.Buffer, buflen - 1);
- cwd_lock.release ();
- return buf;
- }
+ void reset_posix (wchar_t *);
+ char *get (char *, int = 1, int = 0, unsigned = NT_MAX_PATH);
HANDLE get_handle () { return dir; }
DWORD get_drive (char * dst)
{
@@ -365,126 +355,6 @@ struct user_heap_info
void __reg1 init ();
};
-class cygheap_domain_info
-{
- PWCHAR pdom_name;
- PWCHAR pdom_dns_name;
- cygsid pdom_sid;
-
- PWCHAR adom_name;
- cygsid adom_sid;
-
- PDS_DOMAIN_TRUSTSW tdom;
- ULONG tdom_count;
-
- PWCHAR rfc2307_domain_buf;
-
-public:
- bool init ();
-
- inline PCWSTR primary_flat_name () const { return pdom_name; }
- inline PCWSTR primary_dns_name () const { return pdom_dns_name; }
- inline cygsid &primary_sid () { return pdom_sid; }
-
- inline bool member_machine () const { return pdom_sid != NO_SID; }
-
- inline PCWSTR account_flat_name () const { return adom_name; }
- inline cygsid &account_sid () { return adom_sid; }
-
- inline PDS_DOMAIN_TRUSTSW trusted_domain (ULONG idx) const
- { return (idx < tdom_count) ? tdom + idx : NULL; }
-
- inline PWCHAR get_rfc2307_domain () const
- { return rfc2307_domain_buf ?: NULL; }
-};
-
-class cygheap_pwdgrp
-{
- static const int NSS_FILES = 1;
- static const int NSS_DB = 2;
- enum pfx_t {
- NSS_AUTO = 0,
- NSS_PRIMARY,
- NSS_ALWAYS
- };
- bool nss_inited;
- int pwd_src;
- int grp_src;
- pfx_t prefix;
- WCHAR separator[2];
- bool caching;
- int enums;
- PWCHAR enum_tdoms;
-
- void nss_init_line (const char *line);
- void _nss_init ();
-
-public:
- struct {
- pwdgrp cygserver;
- pwdgrp file;
- pwdgrp win;
- } pwd_cache;
- struct {
- pwdgrp cygserver;
- pwdgrp file;
- pwdgrp win;
- } grp_cache;
-
- void init ();
-
- inline void nss_init () { if (!nss_inited) _nss_init (); }
- inline bool nss_pwd_files () const { return !!(pwd_src & NSS_FILES); }
- inline bool nss_pwd_db () const { return !!(pwd_src & NSS_DB); }
- inline bool nss_grp_files () const { return !!(grp_src & NSS_FILES); }
- inline bool nss_grp_db () const { return !!(grp_src & NSS_DB); }
- inline bool nss_prefix_auto () const { return prefix == NSS_AUTO; }
- inline bool nss_prefix_primary () const { return prefix == NSS_PRIMARY; }
- inline bool nss_prefix_always () const { return prefix == NSS_ALWAYS; }
- inline PCWSTR nss_separator () const { return separator; }
- inline bool nss_cygserver_caching () const { return caching; }
- inline void nss_disable_cygserver_caching () { caching = false; }
- inline int nss_db_enums () const { return enums; }
- inline PCWSTR nss_db_enum_tdoms () const { return enum_tdoms; }
-};
-
-class cygheap_ugid_cache
-{
- struct idmap {
- uint32_t nfs_id;
- uint32_t cyg_id;
- };
- class idmaps {
- uint32_t _cnt;
- uint32_t _max;
- idmap *_map;
- public:
- uint32_t get (uint32_t id) const
- {
- for (uint32_t i = 0; i < _cnt; ++i)
- if (_map[i].nfs_id == id)
- return _map[i].cyg_id;
- return (uint32_t) -1;
- }
- void add (uint32_t nfs_id, uint32_t cyg_id)
- {
- if (_cnt >= _max)
- _map = (idmap *) crealloc (_map, (_max += 10) * sizeof (*_map));
- _map[_cnt].nfs_id = nfs_id;
- _map[_cnt].cyg_id = cyg_id;
- ++_cnt;
- }
- };
- idmaps uids;
- idmaps gids;
-
-public:
- uid_t get_uid (uid_t uid) const { return uids.get (uid); }
- gid_t get_gid (gid_t gid) const { return gids.get (gid); }
- void add_uid (uid_t nfs_uid, uid_t cyg_uid) { uids.add (nfs_uid, cyg_uid); }
- void add_gid (gid_t nfs_gid, gid_t cyg_gid) { gids.add (nfs_gid, cyg_gid); }
-};
-
struct hook_chain
{
void **loc;
@@ -510,9 +380,6 @@ struct init_cygheap: public mini_cygheap
UNICODE_STRING installation_key;
WCHAR installation_key_buf[18];
cygheap_root root;
- cygheap_domain_info dom;
- cygheap_pwdgrp pg;
- cygheap_ugid_cache ugid_cache;
cygheap_user user;
user_heap_info user_heap;
mode_t umask;
@@ -668,5 +535,4 @@ class cygheap_fdenum : public cygheap_fdmanip
void __stdcall cygheap_fixup_in_child (bool);
void __stdcall cygheap_init ();
-void setup_cygheap ();
extern char _cygheap_start[] __attribute__((section(".idata")));
diff --git a/winsup/cygwin/cygserver.h b/winsup/cygwin/cygserver.h
index 1313d3c1e..8bcc271f3 100644
--- a/winsup/cygwin/cygserver.h
+++ b/winsup/cygwin/cygserver.h
@@ -52,7 +52,6 @@ protected:
CYGSERVER_REQUEST_SEM,
CYGSERVER_REQUEST_SHM,
CYGSERVER_REQUEST_SETPWD,
- CYGSERVER_REQUEST_PWDGRP,
CYGSERVER_REQUEST_LAST
} request_code_t;
diff --git a/winsup/cygwin/cygserver_pwdgrp.h b/winsup/cygwin/cygserver_pwdgrp.h
deleted file mode 100644
index 52b9b42ba..000000000
--- a/winsup/cygwin/cygserver_pwdgrp.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* cygserver_pwdgrp.h: Request account information
-
- Copyright 2014 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 __CYGSERVER_PWDGRP_H__
-#define __CYGSERVER_PWDGRP_H__
-
-#include <sys/types.h>
-#include "cygserver.h"
-
-class transport_layer_base;
-class process_cache;
-
-#ifdef __INSIDE_CYGWIN__
-#include "pwdgrp.h"
-#else
-/* Don't include pwdgrp.h, but keep this in sync. */
-enum fetch_user_arg_type_t {
- SID_arg,
- NAME_arg,
- ID_arg
-};
-#endif
-
-class client_request_pwdgrp : public client_request
-{
- friend class client_request;
-
-private:
- union _pwdgrp_param_t
- {
- struct _pwdgrp_in_t
- {
- bool group;
- fetch_user_arg_type_t type;
- union
- {
- BYTE sid[40];
- char name[UNLEN + 1];
- uint32_t id;
- } arg;
- } in;
-
- struct
- {
- char line[1024];
- } out;
- } _parameters;
-
-#ifndef __INSIDE_CYGWIN__
- client_request_pwdgrp ();
- virtual void serve (transport_layer_base *, process_cache *);
- void pwd_serve ();
- void grp_serve ();
-#endif
-
-public:
-
-#ifdef __INSIDE_CYGWIN__
- client_request_pwdgrp (fetch_user_arg_t &arg, bool group);
-#endif
-
- const char *line () const { return (msglen () > 0) ? _parameters.out.line
- : NULL; }
-};
-
-#endif /* __CYGSERVER_PWDGRP_H__ */
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index 91533f2a0..366d7da4d 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -89,13 +89,20 @@ public:
struct _local_storage
{
- /* passwd.cc */
- char pass[_PASSWORD_LEN];
+ /*
+ Needed for the group functions
+ */
+ int grp_pos;
/* dlfcn.cc */
int dl_error;
char dl_buffer[256];
+ /* passwd.cc */
+ struct passwd res;
+ char pass[_PASSWORD_LEN];
+ int pw_pos;
+
/* path.cc */
struct mntent mntbuf;
int iteration;
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 738860d0e..8d059144d 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -609,7 +609,7 @@ void
child_info_fork::handle_fork ()
{
cygheap_fixup_in_child (false);
- memory_init ();
+ memory_init (false);
myself.thisproc (NULL);
myself->uid = cygheap->user.real_uid;
myself->gid = cygheap->user.real_gid;
@@ -663,7 +663,7 @@ child_info_spawn::handle_spawn ()
if (!dynamically_loaded || get_parent_handle ())
{
cygheap_fixup_in_child (true);
- memory_init ();
+ memory_init (false);
}
if (!moreinfo->myself_pinfo ||
!DuplicateHandle (GetCurrentProcess (), moreinfo->myself_pinfo,
@@ -769,8 +769,7 @@ dll_crt0_0 ()
if (!child_proc_info)
{
- setup_cygheap ();
- memory_init ();
+ memory_init (true);
#ifndef __x86_64__
/* WOW64 process on XP/64 or Server 2003/64? Check if we have been
started from 64 bit process and if our stack is at an unusual
diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
index 658551b70..46d654f0b 100644
--- a/winsup/cygwin/dlfcn.cc
+++ b/winsup/cygwin/dlfcn.cc
@@ -13,11 +13,7 @@ details. */
#include <psapi.h>
#include <stdlib.h>
#include <ctype.h>
-#include <wctype.h>
#include "path.h"
-#include "fhandler.h"
-#include "dtable.h"
-#include "cygheap.h"
#include "perprocess.h"
#include "dlfcn.h"
#include "cygtls.h"
diff --git a/winsup/cygwin/dll_init.sgml b/winsup/cygwin/dll_init.sgml
new file mode 100644
index 000000000..a66c43cb6
--- /dev/null
+++ b/winsup/cygwin/dll_init.sgml
@@ -0,0 +1,11 @@
+
+<sect1 id="func-cygwin-detach-dll">
+<title>cygwin_detach_dll</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" void
+<function>cygwin_detach_dll</function></funcdef>
+<paramdef>int <parameter>dll_index</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+</sect1>
diff --git a/winsup/cygwin/dlmalloc.c b/winsup/cygwin/dlmalloc.c
new file mode 100644
index 000000000..b64bed8eb
--- /dev/null
+++ b/winsup/cygwin/dlmalloc.c
@@ -0,0 +1,3815 @@
+/*
+ * To do:
+ * - strdup? maybe shouldn't bother yet, it seems difficult to get includes
+ * right using dlmalloc.h
+ * - add STD_C prototyping
+ * - adhere to comment conventions
+ * - maybe fix ALLOCFILL vs. MOATFILL in do_init_realloced_chunk()
+ * - keep a list of mmaped regions for checking in malloc_update_mallinfo()
+ * - I think memalign() is wrong: it aligns the chunk rather than the memory
+ * portion of the chunk.
+ * - "& -alignment" in memalign() is suspect: should use "& ~alignment"
+ * instead?
+ * - malloc.h doesn't need malloc_COPY or probably a bunch of other stuff
+ * - add mallopt options for e.g. fill?
+ * - come up with a non-BBC version of M_C
+ * - document necessity of checking chunk address in do_check_chunk prior to
+ * accessing any of its fields
+ * Done:
+ * minor speedup due to extend check before mremap
+ * minor speedup due to returning malloc() result in memalign() if aligned
+ * made malloc_update_mallinfo() check alloced regions at start of sbrk area
+ * fixed bug: After discovering foreign sbrk, if old_top was MINSIZE, would
+ * reduce old_top_size to 0, thus making inuse(old_top) return 0; other
+ * functions would consequently attempt to access old_top->{fd,bk}, which
+ * were invalid. This is in malloc_extend_top(), in the "double
+ * fencepost" section.
+ * Documentation:
+ * malloc_usable_size(P) is equivalent to realloc(P, malloc_usable_size(P))
+ *
+ * $Log$
+ * Revision 1.9 2004/05/12 16:21:18 cgf
+ * remove keyword stuff
+ *
+ * Revision 1.1 1997/12/24 18:34:47 nsd
+ * Initial revision
+ *
+ */
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+ A version of malloc/free/realloc written by Doug Lea and released to the
+ public domain. Send questions/comments/complaints/performance data
+ to dl@cs.oswego.edu
+
+* VERSION 2.6.4 Thu Nov 28 07:54:55 1996 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://g.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Why use this malloc?
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and tunable.
+ Consistent balance across these factors results in a good general-purpose
+ allocator. For a high-level description, see
+ http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+ (Much fuller descriptions are contained in the program documentation below.)
+
+ malloc(size_t n);
+ Return a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available.
+ free(Void_t* p);
+ Release the chunk of memory pointed to by p, or no effect if p is null.
+ realloc(Void_t* p, size_t n);
+ Return a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available. The returned pointer may or may not be
+ the same as p. If p is null, equivalent to malloc. Unless the
+ #define realloc_ZERO_BYTES_FREES below is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+ memalign(size_t alignment, size_t n);
+ Return a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument, which must be a power of
+ two.
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system (or as near to this as can be figured out from
+ all the includes/defines below.)
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ calloc(size_t unit, size_t quantity);
+ Returns a pointer to quantity * unit bytes, with all locations
+ set to zero.
+ cfree(Void_t* p);
+ Equivalent to free(p).
+ malloc_trim(size_t pad);
+ Release all but pad bytes of freed top-most memory back
+ to the system. Return 1 if successful, else 0.
+ malloc_usable_size(Void_t* p);
+ Report the number usable allocated bytes associated with allocated
+ chunk p. This may or may not report more bytes than were requested,
+ due to alignment and minimum size constraints.
+ malloc_stats();
+ Prints brief summary statistics on stderr.
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics.
+ mallopt(int parameter_number, int parameter_value)
+ Changes one of the tunable parameters described below. Returns
+ 1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+ Alignment: 8-byte
+ 8 byte alignment is currently hardwired into the design. This
+ seems to suffice for all current machines and C compilers.
+
+ Assumed pointer representation: 4 or 8 bytes
+ Code for 8-byte pointers is untested by me but has worked
+ reliably by Wolfram Gloger, who contributed most of the
+ changes supporting this.
+
+ Assumed size_t representation: 4 or 8 bytes
+ Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes
+ Each malloced chunk has a hidden overhead of 4 bytes holding size
+ and status information.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
+ 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
+
+ When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+ ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+ needed; 4 (8) for a trailing size field
+ and 8 (16) bytes for free list pointers. Thus, the minimum
+ allocatable size is 16/24/32 bytes.
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+
+ Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
+ 8-byte size_t: 2^63 - 16 bytes
+
+ It is assumed that (possibly signed) size_t bit values suffice to
+ represent chunk sizes. `Possibly signed' is due to the fact
+ that `size_t' may be defined on a system as either a signed or
+ an unsigned type. To be conservative, values that would appear
+ as negative numbers are avoided.
+ Requests for sizes with a negative sign bit will return a
+ minimum-sized chunk.
+
+ Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+ Alignnment demands, plus the minimum allocatable size restriction
+ make the normal worst-case wastage 15 bytes (i.e., up to 15
+ more bytes will be allocated than were requested in malloc), with
+ two exceptions:
+ 1. Because requests for zero bytes allocate non-zero space,
+ the worst case wastage for a request of zero bytes is 24 bytes.
+ 2. For requests >= mmap_threshold that are serviced via
+ mmap(), the worst case wastage is 8 bytes plus the remainder
+ from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+ Here are some features that are NOT currently supported
+
+ * No user-definable hooks for callbacks and the like.
+ * No automated mechanism for fully checking that all accesses
+ to malloced memory stay within their bounds.
+ * No support for compaction.
+
+* Synopsis of compile-time options:
+
+ People have reported using previous versions of this malloc on all
+ versions of Unix, sometimes by tweaking some of the defines
+ below. It has been tested most extensively on Solaris and
+ Linux. It is also reported to work on WIN32 platforms.
+ People have also reported adapting this malloc for use in
+ stand-alone embedded systems.
+
+ The implementation is in straight, hand-tuned ANSI C. Among other
+ consequences, it uses a lot of macros. Because of this, to be at
+ all usable, this code should be compiled using an optimizing compiler
+ (for example gcc -O2) that can simplify expressions and control
+ paths.
+
+ __STD_C (default: derived from C compiler defines)
+ Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+ a C compiler sufficiently close to ANSI to get away with it.
+ DEBUG (default: NOT defined)
+ Define to enable debugging. Adds fairly extensive assertion-based
+ checking to help track down memory errors, but noticeably slows down
+ execution.
+ realloc_ZERO_BYTES_FREES (default: NOT defined)
+ Define this if you think that realloc(p, 0) should be equivalent
+ to free(p). Otherwise, since malloc returns a unique pointer for
+ malloc(0), so does realloc(p, 0).
+ HAVE_memcpy (default: defined)
+ Define if you are not otherwise using ANSI STD C, but still
+ have memcpy and memset in your C library and want to use them.
+ Otherwise, simple internal versions are supplied.
+ USE_memcpy (default: 1 if HAVE_memcpy is defined, 0 otherwise)
+ Define as 1 if you want the C library versions of memset and
+ memcpy called in realloc and calloc (otherwise macro versions are used).
+ At least on some platforms, the simple macro versions usually
+ outperform libc versions.
+ HAVE_MMAP (default: defined as 1)
+ Define to non-zero to optionally make malloc() use mmap() to
+ allocate very large blocks.
+ HAVE_MREMAP (default: defined as 0 unless Linux libc set)
+ Define to non-zero to optionally make realloc() use mremap() to
+ reallocate very large blocks.
+ malloc_getpagesize (default: derived from system #includes)
+ Either a constant or routine call returning the system page size.
+ HAVE_USR_INCLUDE_malloc_H (default: NOT defined)
+ Optionally define if you are on a system with a /usr/include/malloc.h
+ that declares struct mallinfo. It is not at all necessary to
+ define this even if you do, but will ensure consistency.
+ INTERNAL_SIZE_T (default: size_t)
+ Define to a 32-bit type (probably `unsigned int') if you are on a
+ 64-bit machine, yet do not want or need to allow malloc requests of
+ greater than 2^31 to be handled. This saves space, especially for
+ very small chunks.
+ INTERNAL_LINUX_C_LIB (default: NOT defined)
+ Defined only when compiled as part of Linux libc.
+ Also note that there is some odd internal name-mangling via defines
+ (for example, internally, `malloc' is named `mALLOc') needed
+ when compiling in this case. These look funny but don't otherwise
+ affect anything.
+ WIN32 (default: undefined)
+ Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+ LACKS_UNISTD_H (default: undefined)
+ Define this if your system does not have a <unistd.h>.
+ MORECORE (default: sbrk)
+ The name of the routine to call to obtain more memory from the system.
+ MORECORE_FAILURE (default: -1)
+ The value returned upon failure of MORECORE.
+ MORECORE_CLEARS (default 0)
+ True (1) if the routine mapped to MORECORE zeroes out memory (which
+ holds for sbrk).
+ DEFAULT_TRIM_THRESHOLD
+ DEFAULT_TOP_PAD
+ DEFAULT_MMAP_THRESHOLD
+ DEFAULT_MMAP_MAX
+ Default values of tunable parameters (described in detail below)
+ controlling interaction with host system routines (sbrk, mmap, etc).
+ These values may also be changed dynamically via mallopt(). The
+ preset defaults are those that give best performance for typical
+ programs/systems.
+
+
+*/
+
+
+
+
+/* Preliminaries */
+
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C 1
+#else
+#if __cplusplus
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if __STD_C
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#define __MALLOC_H_INCLUDED
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include "cygmalloc.h"
+#define __INSIDE_CYGWIN__
+#include <stdio.h> /* needed for malloc_stats */
+#include <string.h>
+
+/*
+ Compile-time options
+*/
+
+
+/*
+ Debugging:
+
+ Because freed chunks may be overwritten with link fields, this
+ malloc will often die when freed memory is overwritten by user
+ programs. This can be very effective (albeit in an annoying way)
+ in helping track down dangling pointers.
+
+ If you compile with -DDEBUG, a number of assertion checks are
+ enabled that will catch more memory errors. You probably won't be
+ able to make much sense of the actual assertion errors, but they
+ should help you locate incorrectly overwritten memory. The
+ checking is fairly extensive, and will slow down execution
+ noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+ attempt to check every non-mmapped allocated and free chunk in the
+ course of computing the summmaries. (By nature, mmapped regions
+ cannot be checked very much automatically.)
+
+ Setting DEBUG may also be helpful if you are trying to modify
+ this code. The assertions in the check routines spell out in more
+ detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+#ifdef MALLOC_DEBUG
+#define DEBUG 1
+#define DEBUG1 1
+#define DEBUG2 1
+#define DEBUG3 1
+#endif
+
+#if DEBUG
+#include <assert.h>
+#else
+#define assert(x) ((void)0)
+#endif
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes. On a 64-bit machine, you can reduce malloc
+ overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+ at the expense of not being able to handle requests greater than
+ 2^31. This limitation is hardly ever a concern; you are encouraged
+ to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+ realloc_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/* #define realloc_ZERO_BYTES_FREES */
+
+
+/*
+ WIN32 causes an emulation of sbrk to be compiled in
+ mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+#endif
+
+
+/*
+ HAVE_memcpy should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined here.
+
+ USE_memcpy should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are often enough faster than libc versions on many
+ systems that it is better to use them.
+
+*/
+
+#define HAVE_memcpy
+
+#ifndef USE_memcpy
+#ifdef HAVE_memcpy
+#define USE_memcpy 1
+#else
+#define USE_memcpy 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_memcpy))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+
+#ifndef DEBUG3
+
+#if USE_memcpy
+
+/* The following macros are only invoked with (2n+1)-multiples of
+ INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+ for fast inline execution when n is small. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T mzsz = (nbytes); \
+ if(mzsz <= 9*sizeof(mzsz)) { \
+ INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
+ if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; \
+ if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
+ *mz++ = 0; }}} \
+ *mz++ = 0; \
+ *mz++ = 0; \
+ *mz = 0; \
+ } else memset((charp), 0, mzsz); \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T mcsz = (nbytes); \
+ if(mcsz <= 9*sizeof(mcsz)) { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
+ if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; }}} \
+ *mcdst++ = *mcsrc++; \
+ *mcdst++ = *mcsrc++; \
+ *mcdst = *mcsrc ; \
+ } else memcpy(dest, src, mcsz); \
+} while(0)
+
+#else /* !USE_memcpy */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+#else /* DEBUG3 */
+
+/* The trailing moat invalidates the above prediction about the nbytes
+ parameter to malloc_ZERO and malloc_COPY. */
+
+#define malloc_ZERO(charp, nbytes) \
+do { \
+ char *mzp = (char *)(charp); \
+ long mzn = (nbytes); \
+ while (mzn--) \
+ *mzp++ = '\0'; \
+} while(0)
+
+#define malloc_COPY(dest,src,nbytes) \
+do { \
+ char *mcsrc = (char *)(src); \
+ char *mcdst = (char *)(dest); \
+ long mcn = (nbytes); \
+ while (mcn--) \
+ *mcdst++ = *mcsrc++; \
+} while(0)
+
+#endif /* DEBUG3 */
+
+/*
+ Define HAVE_MMAP to optionally make malloc() use mmap() to
+ allocate very large blocks. These will be returned to the
+ operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+ Access to system page size. To the extent possible, this malloc
+ manages memory from the system in page-size units.
+
+ The following mechanics for getpagesize were adapted from
+ bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+# if __STD_C
+ extern size_t getpagesize(void);
+# else
+ extern size_t getpagesize();
+# endif
+# define malloc_getpagesize getpagesize()
+# else
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else
+# define malloc_getpagesize (4096) /* just guess */
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+
+/*
+
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing the same kind of
+ information you can get from malloc_stats. It should work on
+ any SVID/XPG compliant system that has a /usr/include/malloc.h
+ defining struct mallinfo. (If you'd like to install such a thing
+ yourself, cut out the preliminary declarations as described above
+ and below and save them in a malloc.h file. But there's no
+ compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields, most of which are not even meaningful in this
+ version of malloc. Some of these fields are are instead filled by
+ mallinfo() with other numbers that might possibly be of interest.
+
+ HAVE_USR_INCLUDE_malloc_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_malloc_H */
+
+#if HAVE_USR_INCLUDE_malloc_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+#define M_SCANHEAP -5
+#define M_FILL
+
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The default trim value is high enough to cause trimming only in
+ fairly extreme (by current memory consumption standards) cases.
+ It must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefit that mmapped space
+ can ALWAYS be individually released back to the system, which
+ helps keep the system level memory demands of a long-lived
+ program low. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ menas that even trimming via malloc_trim would not release them.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ All together, these considerations should lead you to use mmap
+ only for relatively large requests.
+
+
+*/
+
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX (64)
+#else
+#define DEFAULT_MMAP_MAX (0)
+#endif
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because:
+
+ 1. Some systems have a limited number of internal tables for
+ use by mmap.
+ 2. In most systems, overreliance on mmap can degrade overall
+ performance.
+ 3. If a program allocates many large regions, it is probably
+ better off using normal sbrk-based allocation routines that
+ can reclaim and reallocate normal heap memory. Using a
+ small value allows transition into this mode after the
+ first few allocations.
+
+ Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
+ the default value is 0, and attempts to set it to non-zero values
+ in mallopt will fail.
+*/
+
+
+
+
+/*
+
+ Special defines for linux libc
+
+ Except when compiled using these special defines for Linux libc
+ using weak aliases, this malloc is NOT designed to work in
+ multithreaded applications. No semaphores or other concurrency
+ control are provided to ensure that multiple malloc or free calls
+ don't run at the same time, which could be disasterous. A single
+ semaphore could be used across malloc, realloc, and free (which is
+ essentially the effect of the linux weak alias approach). It would
+ be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+/* extern Void_t* sbrk(ptrdiff_t);*/
+#else
+extern Void_t* sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 0
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc __libc_calloc
+#define fREe __libc_free
+#define mALLOc __libc_malloc
+#define mEMALIGn __libc_memalign
+#define rEALLOc __libc_realloc
+#define vALLOc __libc_valloc
+#define pvALLOc __libc_pvalloc
+#define mALLINFo __libc_mallinfo
+#define mALLOPt __libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifndef cALLOc
+#define cALLOc dlcalloc
+#endif
+#ifndef fREe
+#define fREe dlfree
+#endif
+#ifndef mALLOc
+#define mALLOc dlmalloc
+#endif
+#ifndef mEMALIGn
+#define mEMALIGn dlmemalign
+#endif
+#ifndef rEALLOc
+#define rEALLOc dlrealloc
+#endif
+#ifndef vALLOc
+#define vALLOc dlvalloc
+#endif
+#ifndef pvALLOc
+#define pvALLOc dlpvalloc
+#endif
+#ifndef mALLINFo
+#define mALLINFo dlmallinfo
+#endif
+#ifndef mALLOPt
+#define mALLOPt dlmallopt
+#endif
+
+#endif
+
+/* Public routines */
+
+#ifdef DEBUG2
+#define malloc(size) malloc_dbg(size, __FILE__, __LINE__)
+#define free(p) free_dbg(p, __FILE__, __LINE__)
+#define realloc(p, size) realloc_dbg(p, size, __FILE__, __LINE__)
+#define calloc(n, size) calloc_dbg(n, size, __FILE__, __LINE__)
+#define memalign(align, size) memalign_dbg(align, size, __FILE__, __LINE__)
+#define valloc(size) valloc_dbg(size, __FILE__, __LINE__)
+#define pvalloc(size) pvalloc_dbg(size, __FILE__, __LINE__)
+#define malloc_trim(pad) malloc_trim_dbg(pad, __FILE__, __LINE__)
+#define malloc_usable_size(p) malloc_usable_size_dbg(p, __FILE__, __LINE__)
+#define malloc_stats(void) malloc_stats_dbg(__FILE__, __LINE__)
+#define mallopt(flag, val) mallopt_dbg(flag, val, __FILE__, __LINE__)
+#define mallinfo(void) mallinfo_dbg(__FILE__, __LINE__)
+
+#if __STD_C
+Void_t* malloc_dbg(size_t, const char *, int);
+void free_dbg(Void_t*, const char *, int);
+Void_t* realloc_dbg(Void_t*, size_t, const char *, int);
+Void_t* calloc_dbg(size_t, size_t, const char *, int);
+Void_t* memalign_dbg(size_t, size_t, const char *, int);
+Void_t* valloc_dbg(size_t, const char *, int);
+Void_t* pvalloc_dbg(size_t, const char *, int);
+int malloc_trim_dbg(size_t, const char *, int);
+size_t malloc_usable_size_dbg(Void_t*, const char *, int);
+void malloc_stats_dbg(const char *, int);
+int mallopt_dbg(int, int, const char *, int);
+struct mallinfo mallinfo_dbg(const char *, int);
+#else
+Void_t* malloc_dbg();
+void free_dbg();
+Void_t* realloc_dbg();
+Void_t* calloc_dbg();
+Void_t* memalign_dbg();
+Void_t* valloc_dbg();
+Void_t* pvalloc_dbg();
+int malloc_trim_dbg();
+size_t malloc_usable_size_dbg();
+void malloc_stats_dbg();
+int mallopt_dbg();
+struct mallinfo mallinfo_dbg();
+#endif /* !__STD_C */
+
+#else /* !DEBUG2 */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* cALLOc(size_t, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats(void);
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* cALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+#endif /* !DEBUG2 */
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+
+#ifdef DEBUG2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef malloc
+#undef free
+#undef realloc
+#undef calloc
+#undef memalign
+#undef valloc
+#undef pvalloc
+#undef malloc_trim
+#undef malloc_usable_size
+#undef malloc_stats
+#undef mallopt
+#undef mallinfo
+
+#if __STD_C
+Void_t* mALLOc(size_t);
+void fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* cALLOc(size_t, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(Void_t*);
+void malloc_stats(void);
+int mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void fREe();
+Void_t* rEALLOc();
+Void_t* cALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+int malloc_trim();
+size_t malloc_usable_size();
+void malloc_stats();
+int mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+#include <ctype.h> /* isprint() */
+#ifdef DEBUG3
+#include <stdlib.h> /* atexit() */
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+#endif /* DEBUG2 */
+
+/*
+ Emulation of sbrk for WIN32
+ All code within the ifdef WIN32 is untested by me.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+ ~(malloc_getpagesize-1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+ GmListElement* next;
+ void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+ GmListElement* this;
+ this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+ ASSERT (this);
+ if (this)
+ {
+ this->base = bas;
+ this->next = head;
+ head = this;
+ }
+ return this;
+}
+
+void gcleanup ()
+{
+ BOOL rval;
+ ASSERT ( (head == NULL) || (head->base == (void*)gAddressBase));
+ if (gAddressBase && (gNextAddress - gAddressBase))
+ {
+ rval = VirtualFree ((void*)gAddressBase,
+ gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ ASSERT (rval);
+ }
+ while (head)
+ {
+ GmListElement* next = head->next;
+ rval = VirtualFree (head->base, 0, MEM_RELEASE);
+ ASSERT (rval);
+ LocalFree (head);
+ head = next;
+ }
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ while ((unsigned long)start_address < TOP_MEMORY)
+ {
+ VirtualQuery (start_address, &info, sizeof (info));
+ if (info.State != MEM_FREE)
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+ else if (info.RegionSize >= size)
+ return start_address;
+ else
+ start_address = (char*)info.BaseAddress + info.RegionSize;
+ }
+ return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+ void* tmp;
+ if (size > 0)
+ {
+ if (gAddressBase == 0)
+ {
+ gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+ gNextAddress = gAddressBase =
+ (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+ } else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+ {
+ long new_size = max (NEXT_SIZE, AlignPage (size));
+ void* new_address = (void*)(gAddressBase+gAllocatedSize);
+ do
+ {
+ new_address = findRegion (new_address, new_size);
+
+ if (new_address == 0)
+ return (void*)-1;
+
+ gAddressBase = gNextAddress =
+ (unsigned int)VirtualAlloc (new_address, new_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ // repeat in case of race condition
+ // The region that we found has been snagged
+ // by another thread
+ }
+ while (gAddressBase == 0);
+
+ ASSERT (new_address == (void*)gAddressBase);
+
+ gAllocatedSize = new_size;
+
+ if (!makeGmListElement ((void*)gAddressBase))
+ return (void*)-1;
+ }
+ if ((size + gNextAddress) > AlignPage (gNextAddress))
+ {
+ void* res;
+ res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+ (size + gNextAddress -
+ AlignPage (gNextAddress)),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (res == 0)
+ return (void*)-1;
+ }
+ tmp = (void*)gNextAddress;
+ gNextAddress = (unsigned int)tmp + size;
+ return tmp;
+ }
+ else if (size < 0)
+ {
+ unsigned int alignedGoal = AlignPage (gNextAddress + size);
+ /* Trim by releasing the virtual memory */
+ if (alignedGoal >= gAddressBase)
+ {
+ VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+ MEM_DECOMMIT);
+ gNextAddress = gNextAddress + size;
+ return (void*)gNextAddress;
+ }
+ else
+ {
+ VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+ MEM_DECOMMIT);
+ gNextAddress = gAddressBase;
+ return (void*)-1;
+ }
+ }
+ else
+ {
+ return (void*)gNextAddress;
+ }
+}
+
+#endif
+
+
+
+/*
+ Type declarations
+*/
+
+#ifdef DEBUG3
+# define MOATWIDTH 4 /* number of guard bytes at each end of
+ allocated region */
+# define MOATFILL 5 /* moat fill character */
+# define ALLOCFILL 1 /* fill char for allocated */
+# define FREEFILL 2 /* and freed regions */
+#endif
+
+typedef struct malloc_chunk
+{
+ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+#ifdef DEBUG3
+ const char *file; /* file and */
+ int line; /* line number of [re]allocation */
+ size_t pad; /* nr pad bytes at mem end, excluding moat */
+ int alloced; /* whether the chunk is allocated -- less prone
+ to segv than inuse(chunk) */
+ char moat[MOATWIDTH]; /* actual leading moat is last MOATWIDTH bytes
+ of chunk header; those bytes may follow this
+ field due to header alignment padding */
+#endif
+} Chunk;
+
+typedef Chunk* mchunkptr;
+
+/*
+
+ malloc_chunk details:
+
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ described in e.g., Knuth or Standish. (See the paper by Paul
+ Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+ survey of such techniques.) Sizes of free chunks are stored both
+ in the front of each chunk and at the end. This makes
+ consolidating fragmented chunks into bigger chunks very fast. The
+ size fields also hold bits representing whether chunks are free or
+ in use.
+
+ An allocated chunk looks like this:
+
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk, if allocated | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | User data starts here... .
+ . .
+ . (malloc_usable_space() bytes) .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+ Where "chunk" is the front of the chunk for the purpose of most of
+ the malloc code, but "mem" is the pointer that is returned to the
+ user. "Nextchunk" is the beginning of the next contiguous chunk.
+
+ Chunks always begin on even word boundries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus double-word aligned.
+
+ Free chunks are stored in circular doubly-linked lists, and look like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ (The very first chunk allocated always has this bit set,
+ preventing access to non-existent (or non-owned) memory.)
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_size of the NEXT chunk. (This makes it easier to
+ deal with alignments etc).
+
+ The two exceptions to all this are
+
+ 1. The special chunk `top', which doesn't bother using the
+ trailing size field since there is no
+ next contiguous chunk that would have to index off it. (After
+ initialization, `top' is forced to always exist. If it would
+ become less than MINSIZE bytes long, it is replenished via
+ malloc_extend_top.)
+
+ 2. Chunks allocated via mmap, which have the second-lowest-order
+ bit (IS_MMAPPED) set in their size fields. Because they are
+ never merged or traversed from any other chunk, they have no
+ foot size or inuse information.
+
+ Available chunks are kept in any of several places (all declared below):
+
+ * `av': An array of chunks serving as bin headers for consolidated
+ chunks. Each bin is doubly linked. The bins are approximately
+ proportionally (log) spaced. There are a lot of these bins
+ (128). This may look excessive, but works very well in
+ practice. All procedures maintain the invariant that no
+ consolidated chunk physically borders another one. Chunks in
+ bins are kept in size order, with ties going to the
+ approximately least recently used chunk.
+
+ The chunks in each bin are maintained in decreasing sorted order by
+ size. This is irrelevant for the small bins, which all contain
+ the same-sized chunks, but facilitates best-fit allocation for
+ larger chunks. (These lists are just sequential. Keeping them in
+ order almost never requires enough traversal to warrant using
+ fancier ordered data structures.) Chunks of the same size are
+ linked with the most recently freed at the front, and allocations
+ are taken from the back. This results in LRU or FIFO allocation
+ order, which tends to give each chunk an equal opportunity to be
+ consolidated with adjacent freed chunks, resulting in larger free
+ chunks and less fragmentation.
+
+ * `top': The top-most available chunk (i.e., the one bordering the
+ end of available memory) is treated specially. It is never
+ included in any bin, is used only if no other chunk is
+ available, and is released back to the system if it is very
+ large (see M_TRIM_THRESHOLD).
+
+ * `last_remainder': A bin holding only the remainder of the
+ most recently split (non-top) chunk. This bin is checked
+ before other non-fitting chunks, so as to provide better
+ locality for runs of sequentially allocated chunks.
+
+ * Implicitly, through the host system's memory mapping tables.
+ If supported, requests greater than a threshold are usually
+ serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+
+
+
+
+
+/* sizes, alignments */
+
+#define SIZE_SZ sizeof(INTERNAL_SIZE_T)
+#define ALIGNMENT (SIZE_SZ + SIZE_SZ)
+#define ALIGN_MASK (ALIGNMENT - 1)
+#ifndef DEBUG3
+# define MEMOFFSET (2*SIZE_SZ)
+# define OVERHEAD SIZE_SZ
+# define MMAP_EXTRA SIZE_SZ /* for correct alignment */
+# define MINSIZE sizeof(Chunk)
+#else
+typedef union {
+ char strut[(sizeof(Chunk) - 1) / ALIGNMENT + 1][ALIGNMENT];
+ Chunk chunk;
+} PaddedChunk;
+# define MEMOFFSET sizeof(PaddedChunk)
+# define OVERHEAD (MEMOFFSET + MOATWIDTH)
+# define MMAP_EXTRA 0
+# define MINSIZE ((OVERHEAD + ALIGN_MASK) & ~ALIGN_MASK)
+#endif
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p) ((Void_t*)((char*)(p) + MEMOFFSET))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - MEMOFFSET))
+
+/* pad request bytes into a usable size, including overhead */
+
+#define request2size(req) \
+ ((long)((req) + OVERHEAD) < (long)MINSIZE ? MINSIZE : \
+ ((req) + OVERHEAD + ALIGN_MASK) & ~ALIGN_MASK)
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((unsigned long)((m)) & ALIGN_MASK) == 0)
+
+
+
+
+/*
+ Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+ ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+ Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#if HAVE_MMAP
+# define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+#else
+# define chunk_is_mmapped(p) 0
+#endif
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+ Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s) ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+ Bins
+
+ The bins, `av_' are an array of pairs of pointers serving as the
+ heads of (initially empty) doubly-linked lists of chunks, laid out
+ in a way so that each pair can be treated as if it were in a
+ malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+ and chunks are the same).
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically
+ spaced. (See the table below.) The `av_' array is never mentioned
+ directly in the code, but instead via bin access macros.
+
+ Bin layout:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ There is actually a little bit of slop in the numbers in bin_index
+ for the sake of speed. This makes no difference elsewhere.
+
+ The special chunks `top' and `last_remainder' get their own bins,
+ (this is implemented via yet more trickery with the av_ array),
+ although `top' is never properly linked to its bin since it is
+ always handled specially.
+
+*/
+
+#define NAV 128 /* number of bins */
+
+typedef Chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+ The first 2 bins are never indexed. The corresponding av_ cells are instead
+ used for bookkeeping. This is not to save space, but to simplify
+ indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top (bin_at(0)->fd) /* The topmost chunk */
+#define last_remainder (bin_at(1)) /* remainder from last split */
+
+
+/*
+ Because top initially points to its own bin with initial
+ zero size, thus forcing extension on the first malloc request,
+ we avoid having any special code in malloc to check whether
+ it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i) bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ 0, 0,
+ IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
+ IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
+ IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
+ IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
+ IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
+ IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
+ IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
+ IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
+ IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
+ IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
+ IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
+ IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
+ IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/*
+ Indexing into bins
+*/
+
+#define bin_index(sz) \
+(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
+ ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
+ ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
+ ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+ 126)
+/*
+ bins for chunks < 512 are all spaced 8 bytes apart, and hold
+ identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN 63
+#define MAX_SMALLBIN_SIZE 512
+#define SMALLBIN_WIDTH 8
+
+#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
+
+/*
+ Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binblocks' is a
+ one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+ have any (possibly) non-empty bins, so they can be skipped over
+ all at once during during traversals. The bits are NOT always
+ cleared as soon as all bins in a block are empty, but instead only
+ when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH 4 /* bins per block */
+
+#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
+
+/* bin<->block macros */
+
+#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
+#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
+
+
+
+
+
+/* Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad = DEFAULT_TOP_PAD;
+static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+#ifdef DEBUG2
+static int scanheap = 1;
+#endif
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+static unsigned int n_mmaps = 0;
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+
+
+/*
+ Debugging support
+*/
+
+#if DEBUG
+
+#ifndef DEBUG2
+# define unless(cond, err, p) assert(cond)
+#else
+# define unless(cond, err, p) do { if (!(cond)) malloc_err(err, p); } while (0)
+
+/*
+ * When debug_file is non-null, it and debug_line respectively contain the
+ * file and line number of the current invocation of malloc(), calloc(),
+ * realloc(), or free().
+ */
+static const char *debug_file = NULL;
+static int debug_line;
+
+/*
+ * Avoid dereferencing invalid chunk.file pointers by tracking the range of
+ * valid ones. Could add an "unallocated" flag to init_freed_chunk() for
+ * more protection, but that's probably not necessary.
+ */
+static const char *debug_file_min = (char *)~0;
+static const char *debug_file_max = NULL;
+
+static char *itos(int n)
+{
+#define NDIGITS (sizeof(int) * 3)
+ static char s[NDIGITS + 1];
+ int i = NDIGITS;
+ do {
+ s[--i] = '0' + n % 10;
+ n /= 10;
+ } while (n);
+ return s + i;
+#undef NDIGITS
+}
+
+static int recurs = 0;
+
+static void errprint(const char *file, int line, const char *err)
+{
+ if (recurs++) {
+ recurs--;
+ return;
+ }
+
+ if (file) {
+ write(2, file, strlen(file));
+ if (line) {
+ write(2, ":", 1);
+ write(2, itos(line), strlen(itos(line)));
+ }
+ write(2, ": ", 2);
+ }
+ write(2, err, strlen(err));
+ write(2, "\n", 1);
+ recurs--;
+}
+
+static void malloc_err(const char *err, mchunkptr p)
+{
+ /*
+ * Display ERR on stderr, accompanying it with the caller's file and line
+ * number if available. If P is non-null, also attempt to display the file
+ * and line number at which P was most recently [re]allocated.
+ *
+ * This function's name begins with "malloc_" to make setting debugger
+ * breakpoints here more convenient.
+ */
+ errprint(debug_file, debug_line, err);
+
+# ifndef DEBUG3
+ p = 0; /* avoid "unused param" warning */
+# else
+ if (p && p->file &&
+ /* avoid invalid pointers */
+ debug_file_min &&
+ p->file >= debug_file_min &&
+ p->file <= debug_file_max)
+ errprint(p->file, p->line, "in block allocated here");
+# endif
+}
+
+#undef malloc
+#undef free
+#undef realloc
+#undef memalign
+#undef valloc
+#undef pvalloc
+#undef calloc
+#undef malloc_trim
+#undef malloc_usable_size
+#undef malloc_stats
+#undef mallopt
+#undef mallinfo
+
+static void malloc_update_mallinfo(void);
+
+/*
+ * Define front-end functions for all user-visible entry points that may
+ * trigger error().
+ */
+#define skel(retdecl, retassign, call, retstmt) \
+ retdecl \
+ debug_file = file; \
+ debug_line = line; \
+ if (debug_file < debug_file_min) \
+ debug_file_min = debug_file; \
+ if (debug_file > debug_file_max) \
+ debug_file_max = debug_file; \
+ if (scanheap) \
+ malloc_update_mallinfo(); \
+ retassign call; \
+ if (scanheap) \
+ malloc_update_mallinfo(); \
+ debug_file = NULL; \
+ retstmt
+
+/*
+ * The final letter of the names of the following macros is either r or v,
+ * indicating that the macro handles functions with or without a return value,
+ * respectively.
+ */
+# define skelr(rettype, call) \
+ skel(rettype ret;, ret = , call, return ret)
+/*
+ * AIX's xlc compiler doesn't like empty macro args, so specify useless but
+ * compilable retdecl, retassign, and retstmt args:
+ */
+#define skelv(call) \
+ skel(line += 0;, if (1), call, return)
+
+#define dbgargs const char *file, int line
+
+/*
+ * Front-end function definitions:
+ */
+Void_t* malloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, malloc(bytes));
+}
+void free_dbg(Void_t *mem, dbgargs) {
+ skelv(free(mem));
+}
+Void_t* realloc_dbg(Void_t *oldmem, size_t bytes, dbgargs) {
+ skelr(Void_t*, realloc(oldmem, bytes));
+}
+Void_t* memalign_dbg(size_t alignment, size_t bytes, dbgargs) {
+ skelr(Void_t*, dlmemalign(alignment, bytes));
+}
+Void_t* valloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, dlvalloc(bytes));
+}
+Void_t* pvalloc_dbg(size_t bytes, dbgargs) {
+ skelr(Void_t*, dlpvalloc(bytes));
+}
+Void_t* calloc_dbg(size_t n, size_t elem_size, dbgargs) {
+ skelr(Void_t*, calloc(n, elem_size));
+}
+int malloc_trim_dbg(size_t pad, dbgargs) {
+ skelr(int, malloc_trim(pad));
+}
+size_t malloc_usable_size_dbg(Void_t *mem, dbgargs) {
+ skelr(size_t, malloc_usable_size(mem));
+}
+void malloc_stats_dbg(dbgargs) {
+ skelv(malloc_stats());
+}
+int mallopt_dbg(int flag, int value, dbgargs) {
+ skelr(int, dlmallopt(flag, value));
+}
+struct mallinfo mallinfo_dbg(dbgargs) {
+ skelr(struct mallinfo, dlmallinfo());
+}
+
+#undef skel
+#undef skelr
+#undef skelv
+#undef dbgargs
+
+#endif /* DEBUG2 */
+
+/*
+ These routines make a number of assertions about the states
+ of data structures that should be true at all times. If any
+ are not true, it's very likely that a user program has somehow
+ trashed memory. (It's also possible that there is a coding error
+ in malloc. In which case, please report it!)
+*/
+
+#ifdef DEBUG3
+static int memtest(void *s, int c, size_t n)
+{
+ /*
+ * Return whether the N-byte memory region starting at S consists
+ * entirely of bytes with value C.
+ */
+ unsigned char *p = (unsigned char *)s;
+ size_t i;
+ for (i = 0; i < n; i++)
+ if (p[i] != (unsigned char)c)
+ return 0;
+ return 1;
+}
+#endif /* DEBUG3 */
+
+#ifndef DEBUG3
+#define check_moats(P)
+#else
+#define check_moats do_check_moats
+static void do_check_moats(mchunkptr p)
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ unless(memtest((char *)chunk2mem(p) - MOATWIDTH, MOATFILL,
+ MOATWIDTH), "region underflow", p);
+ unless(memtest((char *)p + sz - MOATWIDTH - p->pad, MOATFILL,
+ MOATWIDTH + p->pad), "region overflow", p);
+}
+#endif /* DEBUG3 */
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+ /* Try to ensure legal addresses before accessing any chunk fields, in the
+ * hope of issuing an informative message rather than causing a segv.
+ *
+ * The following chunk_is_mmapped() call accesses p->size #if HAVE_MMAP.
+ * This is unavoidable without maintaining a record of mmapped regions.
+ */
+ if (!chunk_is_mmapped(p))
+ {
+ INTERNAL_SIZE_T sz;
+
+ unless((char*)p >= sbrk_base, "chunk precedes sbrk_base", p);
+ unless((char*)p + MINSIZE <= (char*)top + chunksize(top),
+ "chunk past sbrk area", p);
+
+ sz = chunksize(p);
+ if (p != top)
+ unless((char*)p + sz <= (char*)top, "chunk extends beyond top", p);
+ else
+ unless((char*)p + sz <= sbrk_base + sbrked_mem,
+ "chunk extends past sbrk area", p);
+ }
+ check_moats(p);
+}
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ mchunkptr next = chunk_at_offset(p, sz);
+
+ do_check_chunk(p);
+
+ /* Check whether it claims to be free ... */
+ unless(!inuse(p), "free chunk marked inuse", p);
+
+ /* Unless a special marker, must have OK fields */
+ if ((long)sz >= (long)MINSIZE)
+ {
+ unless((sz & ALIGN_MASK) == 0, "freed size defies alignment", p);
+ unless(aligned_OK(chunk2mem(p)), "misaligned freed region", p);
+ /* ... matching footer field */
+ unless(next->prev_size == sz, "chunk size mismatch", p);
+ /* ... and is fully consolidated */
+ unless(prev_inuse(p), "free chunk not joined with prev", p);
+ unless(next == top || inuse(next), "free chunk not joined with next", p);
+
+ /* ... and has minimally sane links */
+ unless(p->fd->bk == p, "broken forward link", p);
+ unless(p->bk->fd == p, "broken backward link", p);
+ }
+ else /* markers are always of size SIZE_SZ */
+ unless(sz == SIZE_SZ, "invalid small chunk size", p);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+ mchunkptr next;
+ do_check_chunk(p);
+
+ if (chunk_is_mmapped(p))
+ return;
+
+ /* Check whether it claims to be in use ... */
+#ifdef DEBUG3
+ unless(p->alloced, "memory not allocated", p);
+#endif
+ unless(inuse(p), "memory not allocated", p);
+
+ /* ... and is surrounded by OK chunks.
+ Since more things can be checked with free chunks than inuse ones,
+ if an inuse chunk borders them and debug is on, it's worth doing them.
+ */
+ if (!prev_inuse(p))
+ {
+ mchunkptr prv = prev_chunk(p);
+ unless(next_chunk(prv) == p, "prev link scrambled", p);
+ do_check_free_chunk(prv);
+ }
+ next = next_chunk(p);
+ if (next == top)
+ {
+ unless(prev_inuse(next), "top chunk wrongly thinks prev is unused", p);
+ unless(chunksize(next) >= MINSIZE, "top chunk too small", p);
+ }
+ else if (!inuse(next))
+ do_check_free_chunk(next);
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+ INTERNAL_SIZE_T sz = chunksize(p);
+ long room = sz - s;
+
+ do_check_inuse_chunk(p);
+
+ /* Legal size ... */
+ unless((long)sz >= (long)MINSIZE, "chunk size too small", p);
+ unless((sz & ALIGN_MASK) == 0, "malloced size defies alignment", p);
+ unless(room >= 0, "chunk size too small for contents", p);
+ unless(room < (long)MINSIZE, "chunk size leaves too much spare room", p);
+
+ /* ... and alignment */
+ unless(aligned_OK(chunk2mem(p)), "misaligned malloced region", p);
+
+
+ /* ... and was allocated at front of an available chunk */
+ unless(prev_inuse(p), "malloced from the middle of a free chunk", p);
+}
+
+#ifdef DEBUG3
+static void init_alloced_chunk(mchunkptr p, size_t bytes)
+{
+ Void_t* mem = chunk2mem(p);
+ p->file = debug_file;
+ p->line = debug_line;
+ p->pad = chunksize(p) - OVERHEAD - bytes;
+ p->alloced = 1;
+ memset((char *)mem + bytes, MOATFILL, p->pad + MOATWIDTH);
+}
+
+static void do_init_malloced_chunk(mchunkptr p, size_t bytes)
+{
+ Void_t* mem = chunk2mem(p);
+ init_alloced_chunk(p, bytes);
+ memset((char *)mem - MOATWIDTH, MOATFILL, MOATWIDTH);
+ memset(mem, ALLOCFILL, bytes);
+}
+
+static void do_init_realloced_chunk(mchunkptr p, size_t bytes,
+ INTERNAL_SIZE_T oldsize)
+{
+ Void_t* mem = chunk2mem(p);
+ INTERNAL_SIZE_T newsize = chunksize(p);
+ init_alloced_chunk(p, bytes);
+ if (oldsize < newsize)
+ /* This incorrectly leaves the leading pad area of the old trailing moat
+ * set to MOATFILL rather than ALLOCFILL. An alternative is to save the
+ * old p->pad in rEALLOc() below and pass it to this function.
+ */
+ memset((char *)mem + oldsize - OVERHEAD, ALLOCFILL,
+ bytes - (oldsize - OVERHEAD));
+}
+
+static void do_check_freefill(mchunkptr p, long newsize,
+ INTERNAL_SIZE_T oldsize)
+{
+ /* The first newsize bytes of oldsize-byte chunk p are about to be
+ * allocated. Issue a warning if any freefill locations in p that are about
+ * to be overwritten do not contain the character FREEFILL.
+ */
+ size_t bytes, maxbytes;
+ if (newsize <= 0)
+ return;
+ bytes = newsize - MEMOFFSET /* don't check p's header */
+ + MEMOFFSET; /* header of split-off remainder */
+ maxbytes = oldsize - OVERHEAD;
+ if (bytes > maxbytes)
+ bytes = maxbytes;
+ unless(memtest(chunk2mem(p), FREEFILL, bytes),
+ "detected write to freed region", p);
+}
+
+static void do_init_freed_chunk(mchunkptr p, INTERNAL_SIZE_T freehead,
+ INTERNAL_SIZE_T freetail)
+{
+ /* freehead and freetail are the number of bytes at the beginning of p and
+ * end of p respectively that should already be initialized as free regions.
+ */
+ Void_t* mem = chunk2mem(p);
+ size_t size = chunksize(p);
+ size_t bytes = size - OVERHEAD;
+ p->pad = 0;
+ p->alloced = 0;
+ memset((char *)mem - MOATWIDTH, MOATFILL, MOATWIDTH);
+ memset((char *)mem + bytes, MOATFILL, MOATWIDTH);
+
+ /* To avoid terrible O(n^2) performance when free() repeatedly grows a free
+ * chunk, it's important not to free-fill regions that are already
+ * free-filled.
+ */
+ if (freehead + freetail < size) {
+ Void_t* start = !freehead ? mem : (char *)p + freehead - MOATWIDTH;
+ size_t len = (char *)p + size - (char *)start -
+ (!freetail ? MOATWIDTH : freetail - OVERHEAD);
+ memset(start, FREEFILL, len);
+ }
+}
+
+static void do_init_freeable_chunk(mchunkptr p)
+{
+ /* Arrange for the subsequent fREe(p) not to generate any warnings. */
+ init_alloced_chunk(p, chunksize(p) - OVERHEAD);
+ memset((char *)chunk2mem(p) - MOATWIDTH, MOATFILL, MOATWIDTH);
+}
+
+static void do_maximize_chunk(mchunkptr p)
+{
+ if (p->pad) {
+ Void_t* mem = chunk2mem(p);
+ size_t bytes = chunksize(p) - OVERHEAD - p->pad;
+ memset((char *)mem + bytes, ALLOCFILL, p->pad);
+ p->pad = 0;
+ }
+}
+
+static int do_check_init(void)
+{
+ /* Called from the first invocation of malloc_extend_top(), as detected by
+ * sbrk_base == -1. Return whether this function allocated any memory.
+ */
+ static int state = 0; /* 1 => initializing, 2 => initialized */
+ if (state == 1)
+ return 0;
+ unless(state == 0, "multiple calls to check_init", NULL);
+ state++;
+ atexit(malloc_update_mallinfo); /* calls malloc on WinNT */
+ return sbrk_base != (char *)-1;
+}
+#endif /* DEBUG3 */
+
+static mchunkptr lowest_chunk;
+
+#define check_free_chunk(P) do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else /* !DEBUG */
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif /* !DEBUG */
+
+#ifdef DEBUG3
+#define check_init do_check_init
+#define init_malloced_chunk do_init_malloced_chunk
+#define init_realloced_chunk do_init_realloced_chunk
+#define check_freefill do_check_freefill
+#define init_freed_chunk do_init_freed_chunk
+#define init_freeable_chunk do_init_freeable_chunk
+#define maximize_chunk do_maximize_chunk
+#else
+#define check_init() 0
+#define init_malloced_chunk(P,B)
+#define init_realloced_chunk(P,B,O)
+#define check_freefill(P,N,O)
+#define init_freed_chunk(P,H,T)
+#define init_freeable_chunk(P)
+#define maximize_chunk(P)
+#endif /* !DEBUG3 */
+
+
+
+/*
+ Macro-based internal utilities
+*/
+
+
+/*
+ Linking chunks in bin lists.
+ Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+ Place chunk p of size s in its bin, in size order,
+ putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD) \
+{ \
+ if (S < MAX_SMALLBIN_SIZE) \
+ { \
+ IDX = smallbin_index(S); \
+ mark_binblock(IDX); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+ else \
+ { \
+ IDX = bin_index(S); \
+ BK = bin_at(IDX); \
+ FD = BK->fd; \
+ if (FD == BK) mark_binblock(IDX); \
+ else \
+ { \
+ while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
+ BK = FD->bk; \
+ } \
+ P->bk = BK; \
+ P->fd = FD; \
+ FD->bk = BK->fd = P; \
+ } \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD) \
+{ \
+ BK = P->bk; \
+ FD = P->fd; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+} \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P) \
+{ \
+ last_remainder->fd = last_remainder->bk = P; \
+ P->fd = P->bk = last_remainder; \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+ (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+ static int fd = -1;
+#endif
+
+ if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+ size = (size + MMAP_EXTRA + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+ if (fd < 0)
+ {
+ fd = open("/dev/zero", O_RDWR);
+ if(fd < 0) return 0;
+ }
+ p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+ if(p == (mchunkptr)-1) return 0;
+
+ n_mmaps++;
+ if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+ /* We demand that eight bytes into a page must be 8-byte aligned. */
+ assert(aligned_OK(chunk2mem(p)));
+
+ /* The offset to the start of the mmapped region is stored
+ * in the prev_size field of the chunk; normally it is zero,
+ * but that can be changed in memalign().
+ */
+ p->prev_size = 0;
+ set_head(p, size|IS_MMAPPED);
+
+ mmapped_mem += size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+ INTERNAL_SIZE_T size = chunksize(p);
+ int ret;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+ n_mmaps--;
+ mmapped_mem -= (size + p->prev_size);
+
+ ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+ size_t page_mask = malloc_getpagesize - 1;
+ INTERNAL_SIZE_T offset = p->prev_size;
+ INTERNAL_SIZE_T size = chunksize(p);
+ char *cp;
+
+ assert (chunk_is_mmapped(p));
+ assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+ assert((n_mmaps > 0));
+ assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+ new_size = (new_size + offset + MMAP_EXTRA + page_mask) & ~page_mask;
+
+ cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+ if (cp == (char *)-1) return 0;
+
+ p = (mchunkptr)(cp + offset);
+
+ assert(aligned_OK(chunk2mem(p)));
+
+ assert(p->prev_size == offset);
+ set_head(p, (new_size - offset)|IS_MMAPPED);
+
+ mmapped_mem -= size + offset;
+ mmapped_mem += new_size;
+ if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+ max_mmapped_mem = mmapped_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+ return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+ Extend the top-most chunk by obtaining memory from system.
+ Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+ char* lim; /* return value from sbrk */
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+ INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
+ char* new_lim; /* return of 2nd sbrk call */
+ INTERNAL_SIZE_T top_size; /* new size of top chunk */
+
+ mchunkptr old_top = top; /* Record state of old top */
+ INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+ char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
+
+ /* Pad request with top_pad plus minimal overhead */
+
+ INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
+ unsigned long pagesz = malloc_getpagesize;
+
+ /* If not the first time through, round to preserve page boundary */
+ /* Otherwise, we need to correct to a page size below anyway. */
+ /* (We also correct below if an intervening foreign sbrk call.) */
+
+ if (sbrk_base != (char*)(-1))
+ sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+ else if (check_init()) {
+ if (chunksize(top) - nb < (long)MINSIZE)
+ malloc_extend_top(nb);
+ return;
+ }
+
+ lim = (char*)(MORECORE (sbrk_size));
+
+ /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+ if (lim == (char*)(MORECORE_FAILURE) ||
+ (lim < old_end && old_top != initial_top))
+ return;
+
+ sbrked_mem += sbrk_size;
+
+ if (lim == old_end) /* can just add bytes to current top */
+ {
+ top_size = sbrk_size + old_top_size;
+ set_head(top, top_size | PREV_INUSE);
+ }
+ else
+ {
+#ifdef SBRKDBG
+ INTERNAL_SIZE_T padding = (char *)sbrk (0) - (lim + sbrk_size);
+ sbrk_size += padding;
+ sbrked_mem += padding;
+#endif
+
+ if (sbrk_base == (char*)(-1)) /* First time through. Record base */
+ sbrk_base = lim;
+ else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
+ sbrked_mem += lim - (char*)old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+ front_misalign = (unsigned long)chunk2mem(lim) & ALIGN_MASK;
+ if (front_misalign > 0)
+ {
+ correction = (ALIGNMENT) - front_misalign;
+ lim += correction;
+ }
+ else
+ correction = 0;
+
+ /* Guarantee the next brk will be at a page boundary */
+ correction += pagesz - ((unsigned long)(lim + sbrk_size) & (pagesz - 1));
+
+ /* Allocate correction */
+ new_lim = (char*)(MORECORE (correction));
+ if (new_lim == (char*)(MORECORE_FAILURE)) return;
+
+ sbrked_mem += correction;
+
+ top = (mchunkptr)lim;
+ top_size = new_lim - lim + correction;
+ set_head(top, top_size | PREV_INUSE);
+#if DEBUG
+ lowest_chunk = top;
+#endif
+
+#ifdef OTHER_SBRKS
+ if (old_top != initial_top)
+ {
+
+ /* There must have been an intervening foreign sbrk call. */
+ /* A double fencepost is necessary to prevent consolidation */
+
+ /* If not enough space to do this, then user did something very wrong */
+ if (old_top_size < MINSIZE)
+ {
+ set_head(top, PREV_INUSE); /* will force null return from malloc */
+ return;
+ }
+
+ old_top_size -= 2*SIZE_SZ;
+ chunk_at_offset(old_top, old_top_size )->size =
+ SIZE_SZ|PREV_INUSE;
+ chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+ SIZE_SZ|PREV_INUSE;
+ set_head_size(old_top, old_top_size);
+ /* If possible, release the rest. */
+ if (old_top_size >= MINSIZE) {
+ init_freeable_chunk(old_top);
+ fREe(chunk2mem(old_top));
+ }
+ }
+#endif /* OTHER_SBRKS */
+ }
+
+ init_freed_chunk(top, old_top == initial_top ? old_top_size : 0, 0);
+
+ if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+ max_sbrked_mem = sbrked_mem;
+ if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+ max_total_mem = mmapped_mem + sbrked_mem;
+
+ /* We always land on a page boundary */
+ assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+ Malloc Algorthim:
+
+ The requested size is first converted into a usable form, `nb'.
+ This currently means to add 4 bytes overhead plus possibly more to
+ obtain 8-byte alignment and/or to obtain a size of at least
+ MINSIZE (currently 16 bytes), the smallest allocatable size.
+ (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+ From there, the first successful of the following steps is taken:
+
+ 1. The bin corresponding to the request size is scanned, and if
+ a chunk of exactly the right size is found, it is taken.
+
+ 2. The most recently remaindered chunk is used if it is big
+ enough. This is a form of (roving) first fit, used only in
+ the absence of exact fits. Runs of consecutive requests use
+ the remainder of the chunk used for the previous such request
+ whenever possible. This limited use of a first-fit style
+ allocation strategy tends to give contiguous chunks
+ coextensive lifetimes, which improves locality and can reduce
+ fragmentation in the long run.
+
+ 3. Other bins are scanned in increasing size order, using a
+ chunk big enough to fulfill the request, and splitting off
+ any remainder. This search is strictly by best-fit; i.e.,
+ the smallest (with ties going to approximately the least
+ recently used) chunk that fits is selected.
+
+ 4. If large enough, the chunk bordering the end of memory
+ (`top') is split off. (This use of `top' is in accord with
+ the best-fit search rule. In effect, `top' is treated as
+ larger (and thus less well fitting) than any other available
+ chunk since it can be extended to be as large as necessary
+ (up to system limitations).
+
+ 5. If the request size meets the mmap threshold and the
+ system supports mmap, and there are few enough currently
+ allocated mmapped regions, and a call to mmap succeeds,
+ the request is allocated via direct memory mapping.
+
+ 6. Otherwise, the top of memory is extended by
+ obtaining more space from the system (normally using sbrk,
+ but definable to anything else via the MORECORE macro).
+ Memory is gathered from the system (in system page-sized
+ units) in a way that allows chunks obtained across different
+ sbrk calls to be consolidated, but does not require
+ contiguous memory. Thus, it should be safe to intersperse
+ mallocs with other sbrk calls.
+
+
+ All allocations are made from the the `lowest' part of any found
+ chunk. (The implementation invariant is that prev_inuse is
+ always true of any allocated chunk; i.e., that each allocated
+ chunk borders either a previously allocated and still in-use chunk,
+ or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mchunkptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T victim_size; /* its size */
+ int idx; /* index for bin traversal */
+ mbinptr bin; /* associated bin */
+ mchunkptr remainder; /* remainder from a split */
+ long remainder_size; /* its size */
+ int remainder_index; /* its bin index */
+ unsigned long block; /* block traverser bit */
+ int startidx; /* first bin of a traversed block */
+ mchunkptr fwd; /* misc temp for linking */
+ mchunkptr bck; /* misc temp for linking */
+ mbinptr q; /* misc temp */
+
+ INTERNAL_SIZE_T nb = request2size(bytes); /* padded request size; */
+
+ /* Check for exact match in a bin */
+
+ if (is_small_request(nb)) /* Faster version for small requests */
+ {
+ idx = smallbin_index(nb);
+
+ /* No traversal or size check necessary for small bins. */
+
+ q = bin_at(idx);
+ victim = last(q);
+
+ /* Also scan the next one, since it would have a remainder < MINSIZE */
+ if (victim == q)
+ {
+ q = next_bin(q);
+ victim = last(q);
+ }
+ if (victim != q)
+ {
+ victim_size = chunksize(victim);
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+
+ return chunk2mem(victim);
+ }
+
+ idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+ }
+ else
+ {
+ idx = bin_index(nb);
+ bin = bin_at(idx);
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* too big */
+ {
+ --idx; /* adjust to rescan below after checking last remainder */
+ break;
+ }
+
+ else if (remainder_size >= 0) /* exact fit */
+ {
+ unlink(victim, bck, fwd);
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+ }
+
+ ++idx;
+
+ }
+
+ /* Try to use the last split-off remainder */
+
+ if ( (victim = last_remainder->fd) != last_remainder)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* re-split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, victim_size);
+ init_malloced_chunk(victim, bytes);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ init_freed_chunk(remainder, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ clear_last_remainder;
+
+ if (remainder_size >= 0) /* exhaust */
+ {
+ set_inuse_bit_at_offset(victim, victim_size);
+ check_freefill(victim, victim_size, victim_size);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ /* Else place in bin */
+
+ frontlink(victim, victim_size, remainder_index, bck, fwd);
+ }
+
+ /*
+ If there are any possibly nonempty big-enough blocks,
+ search for best fitting chunk by scanning bins in blockwidth units.
+ */
+
+ if ( (block = idx2binblock(idx)) <= binblocks)
+ {
+
+ /* Get to the first marked block */
+
+ if ( (block & binblocks) == 0)
+ {
+ /* force to an even block boundary */
+ idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+ block <<= 1;
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+
+ /* For each possibly nonempty block ... */
+ for (;;)
+ {
+ startidx = idx; /* (track incomplete blocks) */
+ q = bin = bin_at(idx);
+
+ /* For each bin in this block ... */
+ do
+ {
+ /* Find and use first big enough chunk ... */
+
+ for (victim = last(bin); victim != bin; victim = victim->bk)
+ {
+ victim_size = chunksize(victim);
+ remainder_size = victim_size - nb;
+
+ if (remainder_size >= (long)MINSIZE) /* split */
+ {
+ remainder = chunk_at_offset(victim, nb);
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, victim_size);
+ unlink(victim, bck, fwd);
+ init_malloced_chunk(victim, bytes);
+ link_last_remainder(remainder);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_foot(remainder, remainder_size);
+ init_freed_chunk(remainder, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ else if (remainder_size >= 0) /* take */
+ {
+ check_freefill(victim, victim_size, victim_size);
+ set_inuse_bit_at_offset(victim, victim_size);
+ unlink(victim, bck, fwd);
+ init_malloced_chunk(victim, bytes);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+ }
+
+ }
+
+ bin = next_bin(bin);
+
+ } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+ /* Clear out the block bit. */
+
+ do /* Possibly backtrack to try to clear a partial block */
+ {
+ if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+ {
+ binblocks &= ~block;
+ break;
+ }
+ --startidx;
+ q = prev_bin(q);
+ } while (first(q) == q);
+
+ /* Get to the next possibly nonempty block */
+
+ if ( (block <<= 1) <= binblocks && (block != 0) )
+ {
+ while ((block & binblocks) == 0)
+ {
+ idx += BINBLOCKWIDTH;
+ block <<= 1;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+
+ /* Try to use top chunk */
+
+ /* Require that there be a remainder, ensuring top always exists */
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ {
+
+#if HAVE_MMAP
+ /* If big and would otherwise need to extend, try to use mmap instead */
+ if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+ (victim = mmap_chunk(nb)) != 0) {
+ init_malloced_chunk(victim, bytes);
+ return chunk2mem(victim);
+ }
+#endif
+
+ /* Try to extend */
+ malloc_extend_top(nb);
+ if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+ return 0; /* propagate failure */
+ }
+
+ victim = top;
+ set_head(victim, nb | PREV_INUSE);
+ check_freefill(victim, nb, nb + remainder_size);
+ init_malloced_chunk(victim, bytes);
+ top = chunk_at_offset(victim, nb);
+ set_head(top, remainder_size | PREV_INUSE);
+ init_freed_chunk(top, remainder_size, 0);
+ check_malloced_chunk(victim, nb);
+ return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+ free() algorithm :
+
+ cases:
+
+ 1. free(0) has no effect.
+
+ 2. If the chunk was allocated via mmap, it is release via munmap().
+
+ 3. If a returned chunk borders the current high end of memory,
+ it is consolidated into the top, and if the total unused
+ topmost memory exceeds the trim threshold, malloc_trim is
+ called.
+
+ 4. Other chunks are consolidated as they arrive, and
+ placed in corresponding bins. (This includes the case of
+ consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T hd; /* its head field */
+ INTERNAL_SIZE_T sz; /* its size */
+ int idx; /* its bin index */
+ mchunkptr next; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsz; /* its size */
+ INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+ int islr; /* track whether merging with last_remainder */
+
+ if (mem == 0) /* free(0) has no effect */
+ return;
+
+ p = mem2chunk(mem);
+ check_inuse_chunk(p);
+
+ hd = p->size;
+
+#if HAVE_MMAP
+ if (hd & IS_MMAPPED) /* release mmapped memory. */
+ {
+ munmap_chunk(p);
+ return;
+ }
+#endif
+
+ sz = hd & ~PREV_INUSE;
+ next = chunk_at_offset(p, sz);
+ nextsz = chunksize(next);
+ prevsz = 0; /* avoid compiler warnings */
+
+ if (next == top) /* merge with top */
+ {
+ sz += nextsz;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -(long)prevsz);
+ sz += prevsz;
+ unlink(p, bck, fwd);
+ }
+
+ set_head(p, sz | PREV_INUSE);
+ top = p;
+ init_freed_chunk(top, !(hd & PREV_INUSE) ? prevsz : 0, nextsz);
+ if ((unsigned long)(sz) >= trim_threshold)
+ malloc_trim(top_pad);
+ return;
+ }
+
+ set_head(next, nextsz); /* clear inuse bit */
+
+ islr = 0;
+
+ if (!(hd & PREV_INUSE)) /* consolidate backward */
+ {
+ prevsz = p->prev_size;
+ p = chunk_at_offset(p, -(long)prevsz);
+ sz += prevsz;
+
+ if (p->fd == last_remainder) /* keep as last_remainder */
+ islr = 1;
+ else
+ unlink(p, bck, fwd);
+ }
+
+ if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
+ {
+ sz += nextsz;
+
+ if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
+ {
+ islr = 1;
+ link_last_remainder(p);
+ }
+ else
+ unlink(next, bck, fwd);
+ }
+
+
+ set_head(p, sz | PREV_INUSE);
+ set_foot(p, sz);
+ if (!islr)
+ frontlink(p, sz, idx, bck, fwd);
+ init_freed_chunk(p, !(hd & PREV_INUSE) ? prevsz : 0,
+ !inuse_bit_at_offset(next, nextsz) ? nextsz : 0);
+}
+
+
+
+
+
+/*
+
+ Realloc algorithm:
+
+ Chunks that were obtained via mmap cannot be extended or shrunk
+ unless HAVE_MREMAP is defined, in which case mremap is used.
+ Otherwise, if their reallocation is for additional space, they are
+ copied. If for less, they are just left alone.
+
+ Otherwise, if the reallocation is for additional space, and the
+ chunk can be extended, it is, else a malloc-copy-free sequence is
+ taken. There are several different ways that a chunk could be
+ extended. All are tried:
+
+ * Extending forward into following adjacent free chunk.
+ * Shifting backwards, joining preceding adjacent space
+ * Both shifting backwards and extending forward.
+ * Extending into newly sbrked space
+
+ Unless the #define realloc_ZERO_BYTES_FREES is set, realloc with a
+ size argument of zero (re)allocates a minimum-sized chunk.
+
+ If the reallocation is for less space, and the new request is for
+ a `small' (<512 bytes) size, then the newly unused space is lopped
+ off and freed.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is no longer supported.
+ I don't know of any programs still relying on this feature,
+ and allowing it would also allow too many other incorrect
+ usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ mchunkptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ mchunkptr next; /* next contiguous chunk after oldp */
+ INTERNAL_SIZE_T nextsize; /* its size */
+
+ mchunkptr prev; /* previous contiguous chunk before oldp */
+ INTERNAL_SIZE_T prevsize; /* its size */
+
+ mchunkptr remainder; /* holds split off extra space from newp */
+ INTERNAL_SIZE_T remainder_size; /* its size */
+
+ mchunkptr bck; /* misc temp for linking */
+ mchunkptr fwd; /* misc temp for linking */
+
+#ifdef realloc_ZERO_BYTES_FREES
+ if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) return mALLOc(bytes);
+
+ newp = oldp = mem2chunk(oldmem);
+ newsize = oldsize = chunksize(oldp);
+
+
+ nb = request2size(bytes);
+
+ check_inuse_chunk(oldp);
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(oldp))
+ {
+ if (oldsize - MMAP_EXTRA >= nb) {
+ init_realloced_chunk(oldp, bytes, oldsize);
+ return oldmem; /* do nothing */
+ }
+#if HAVE_MREMAP
+ newp = mremap_chunk(oldp, nb);
+ if (newp) {
+ init_realloced_chunk(newp, bytes, oldsize);
+ return chunk2mem(newp);
+ }
+#endif
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(bytes);
+ if (newmem == 0) return 0; /* propagate failure */
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD - MMAP_EXTRA);
+ munmap_chunk(oldp);
+ return newmem;
+ }
+#endif
+
+ if (oldsize < nb)
+ {
+
+ /* Try expanding forward */
+
+ next = chunk_at_offset(oldp, oldsize);
+ if (next == top || !inuse(next))
+ {
+ nextsize = chunksize(next);
+
+ /* Forward into top only if a remainder */
+ if (next == top)
+ {
+ if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ check_freefill(next, nb - oldsize, nextsize);
+ newsize += nextsize;
+ top = chunk_at_offset(oldp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ init_freed_chunk(top, newsize - nb, 0);
+ set_head_size(oldp, nb);
+ init_realloced_chunk(oldp, bytes, oldsize);
+ return chunk2mem(oldp);
+ }
+ }
+
+ /* Forward into next chunk */
+ else if (((long)(nextsize + newsize) >= (long)nb))
+ {
+ check_freefill(next, nb - oldsize, nextsize);
+ unlink(next, bck, fwd);
+ newsize += nextsize;
+ goto split;
+ }
+ }
+ else
+ {
+ next = 0;
+ nextsize = 0;
+ }
+
+ /* Try shifting backwards. */
+
+ if (!prev_inuse(oldp))
+ {
+ prev = prev_chunk(oldp);
+ prevsize = chunksize(prev);
+
+ /* try forward + backward first to save a later consolidation */
+
+ if (next != 0)
+ {
+ /* into top */
+ if (next == top)
+ {
+ if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+ {
+ check_freefill(prev, nb, prevsize);
+ check_freefill(next, nb - (prevsize + newsize), nextsize);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize + nextsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ top = chunk_at_offset(newp, nb);
+ set_head(top, (newsize - nb) | PREV_INUSE);
+ init_freed_chunk(top, newsize - nb, 0);
+ set_head_size(newp, nb);
+ init_realloced_chunk(newp, bytes, oldsize);
+ return newmem;
+ }
+ }
+
+ /* into next chunk */
+ else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+ {
+ check_freefill(prev, nb, prevsize);
+ check_freefill(next, nb - (prevsize + newsize), nextsize);
+ unlink(next, bck, fwd);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += nextsize + prevsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ goto split;
+ }
+ }
+
+ /* backward only */
+ if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
+ {
+ check_freefill(prev, nb, prevsize);
+ unlink(prev, bck, fwd);
+ newp = prev;
+ newsize += prevsize;
+ newmem = chunk2mem(newp);
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ goto split;
+ }
+ }
+
+ /* Must allocate */
+
+ newmem = mALLOc (bytes);
+
+ if (newmem == 0) /* propagate failure */
+ return 0;
+
+ /* Avoid copy if newp is next chunk after oldp. */
+ /* (This can only happen when new chunk is sbrk'ed.) */
+
+ if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+ {
+ newsize += chunksize(newp);
+ newp = oldp;
+ goto split;
+ }
+
+ /* Otherwise copy, free, and exit */
+ malloc_COPY(newmem, oldmem, oldsize - OVERHEAD);
+ fREe(oldmem);
+ return newmem;
+ }
+
+
+ split: /* split off extra room in old or expanded chunk */
+
+ if (newsize - nb >= MINSIZE) /* split off remainder */
+ {
+ remainder = chunk_at_offset(newp, nb);
+ remainder_size = newsize - nb;
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_inuse_bit_at_offset(remainder, remainder_size);
+ init_malloced_chunk(remainder, remainder_size - OVERHEAD);
+ fREe(chunk2mem(remainder)); /* let free() deal with it */
+ }
+ else
+ {
+ set_head_size(newp, newsize);
+ set_inuse_bit_at_offset(newp, newsize);
+ }
+
+ init_realloced_chunk(newp, bytes, oldsize);
+ check_inuse_chunk(newp);
+ return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+ memalign algorithm:
+
+ memalign requests more than enough space from malloc, finds a spot
+ within that chunk that meets the alignment request, and then
+ possibly frees the leading and trailing space.
+
+ The alignment argument must be a power of two. This property is not
+ checked by memalign, so misuse may result in random runtime errors.
+
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ mchunkptr p; /* corresponding chunk */
+ char* lim; /* alignment point within p */
+ mchunkptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
+ mchunkptr remainder; /* spare room at end to split off */
+ long remainder_size; /* its size */
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (alignment <= ALIGNMENT) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ nb = request2size(bytes);
+ m = (char*)mALLOc(nb + alignment + MINSIZE);
+
+ if (m == 0) return 0; /* propagate failure */
+
+ p = mem2chunk(m);
+
+ if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+ {
+ init_realloced_chunk(p, bytes, chunksize(p));
+ return chunk2mem(p); /* nothing more to do */
+ }
+ else /* misaligned */
+ {
+ /*
+ Find an aligned spot inside chunk.
+ Since we need to give back leading space in a chunk of at
+ least MINSIZE, if the first calculation places us at
+ a spot with less than MINSIZE leader, we can move to the
+ next aligned spot -- we've allocated enough total room so that
+ this is always possible.
+ */
+
+ lim = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) &
+ ~(alignment - 1));
+ if ((lim - (char*)p) < (long)MINSIZE) lim = lim + alignment;
+
+ newp = (mchunkptr)lim;
+ leadsize = lim - (char*)p;
+ newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+ if(chunk_is_mmapped(p))
+ {
+ newp->prev_size = p->prev_size + leadsize;
+ set_head(newp, newsize|IS_MMAPPED);
+ init_malloced_chunk(newp, bytes);
+ return chunk2mem(newp);
+ }
+#endif
+
+ /* give back leader, use the rest */
+
+ set_head(newp, newsize | PREV_INUSE);
+ set_inuse_bit_at_offset(newp, newsize);
+ set_head_size(p, leadsize);
+ init_freeable_chunk(p);
+ fREe(chunk2mem(p));
+ p = newp;
+
+ assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+
+ remainder_size = chunksize(p) - nb;
+
+ if (remainder_size >= (long)MINSIZE)
+ {
+ remainder = chunk_at_offset(p, nb);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ set_head_size(p, nb);
+ init_freeable_chunk(remainder);
+ fREe(chunk2mem(remainder));
+ }
+
+ init_malloced_chunk(p, bytes);
+ check_inuse_chunk(p);
+ return chunk2mem(p);
+
+}
+
+
+
+
+/*
+ valloc just invokes memalign with alignment argument equal
+ to the page size of the system (or as near to this as can
+ be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+ pvalloc just invokes valloc for the nearest pagesize
+ that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+ size_t pagesize = malloc_getpagesize;
+ return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+ calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+ mchunkptr p;
+ INTERNAL_SIZE_T csz;
+
+ INTERNAL_SIZE_T sz = n * elem_size;
+
+ /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+ mchunkptr oldtop = top;
+ INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+ Void_t* mem = mALLOc (sz);
+
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+
+ /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+ if (chunk_is_mmapped(p)) return mem;
+#endif
+
+ csz = chunksize(p);
+
+#if MORECORE_CLEARS
+ if (p == oldtop && csz > oldtopsize)
+ {
+ /* clear only the bytes from non-freshly-sbrked memory */
+ csz = oldtopsize;
+ }
+#endif
+
+ malloc_ZERO(mem, csz - OVERHEAD);
+ /* reinstate moat fill in pad region */
+ init_realloced_chunk(p, sz, chunksize(p));
+ return mem;
+ }
+}
+
+
+
+/*
+
+ Malloc_trim gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int dlmalloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ char* current_lim; /* address returned by pre-check sbrk call */
+ char* new_lim; /* address returned by negative sbrk call */
+
+ unsigned long pagesz = malloc_getpagesize;
+
+ top_size = chunksize(top);
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra < (long)pagesz) /* Not enough memory to release */
+ return 0;
+
+ else
+ {
+#ifdef OTHER_SBRKS
+ /* Test to make sure no one else called sbrk */
+ current_lim = (char*)(MORECORE (0));
+ if (current_lim != (char*)(top) + top_size)
+ return 0; /* Apparently we don't own memory; must fail */
+
+ else
+#endif
+ {
+ new_lim = (char*)(MORECORE (-extra));
+
+ if (new_lim == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+ {
+ /* Try to figure out what we have */
+ current_lim = (char*)(MORECORE (0));
+ top_size = current_lim - (char*)top;
+ if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+ {
+ sbrked_mem = current_lim - sbrk_base;
+ set_head(top, top_size | PREV_INUSE);
+ init_freed_chunk(top, top_size, 0);
+ }
+ check_chunk(top);
+ return 0;
+ }
+
+ else
+ {
+ /* Success. Adjust top accordingly. */
+ set_head(top, (top_size - extra) | PREV_INUSE);
+ sbrked_mem -= extra;
+ init_freed_chunk(top, top_size - extra, 0);
+ check_chunk(top);
+ return 1;
+ }
+ }
+ }
+}
+
+
+
+/*
+ malloc_usable_size:
+
+ This routine tells you how many bytes you can actually use in an
+ allocated chunk, which may be more than you requested (although
+ often not). You can use this many bytes without worrying about
+ overwriting other allocated objects. Not a particularly great
+ programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t dlmalloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+ mchunkptr p;
+ if (mem == 0)
+ return 0;
+ else
+ {
+ p = mem2chunk(mem);
+ check_inuse_chunk(p);
+ maximize_chunk(p);
+ if(!chunk_is_mmapped(p))
+ {
+ if (!inuse(p)) return 0;
+ return chunksize(p) - OVERHEAD;
+ }
+ return chunksize(p) - OVERHEAD - MMAP_EXTRA;
+ }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+static void malloc_update_mallinfo(void)
+{
+ int i;
+ mbinptr b;
+ mchunkptr p;
+#if DEBUG
+ mchunkptr q;
+#endif
+
+ INTERNAL_SIZE_T avail = chunksize(top);
+ int navail = avail >= MINSIZE ? 1 : 0;
+ check_freefill(top, avail, avail);
+
+#if DEBUG
+ if (lowest_chunk)
+ for (p = lowest_chunk;
+ p < top && inuse(p) && chunksize(p) >= MINSIZE;
+ p = next_chunk(p))
+ check_inuse_chunk(p);
+#endif
+
+ for (i = 1; i < NAV; ++i)
+ {
+ b = bin_at(i);
+ for (p = last(b); p != b; p = p->bk)
+ {
+#if DEBUG
+ check_free_chunk(p);
+ check_freefill(p, chunksize(p), chunksize(p));
+ for (q = next_chunk(p);
+ q < top && inuse(q) && chunksize(q) >= MINSIZE;
+ q = next_chunk(q))
+ check_inuse_chunk(q);
+#endif
+ avail += chunksize(p);
+ navail++;
+ }
+ }
+
+ current_mallinfo.ordblks = navail;
+ current_mallinfo.uordblks = sbrked_mem - avail;
+ current_mallinfo.fordblks = avail;
+ current_mallinfo.hblks = n_mmaps;
+ current_mallinfo.hblkhd = mmapped_mem;
+ current_mallinfo.keepcost = chunksize(top);
+
+}
+
+
+
+/*
+
+ malloc_stats:
+
+ Prints on stderr the amount of space obtain from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), the maximum
+ number of simultaneous mmap regions used, and the current number
+ of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. (Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead.)
+
+*/
+
+void dlmalloc_stats(void)
+{
+ malloc_update_mallinfo();
+ fprintf(stderr, "max system bytes = %10u\n",
+ (unsigned int)(max_total_mem));
+ fprintf(stderr, "system bytes = %10u\n",
+ (unsigned int)(sbrked_mem + mmapped_mem));
+ fprintf(stderr, "in use bytes = %10u\n",
+ (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+ fprintf(stderr, "max mmap regions = %10u\n",
+ (unsigned int)max_n_mmaps);
+#endif
+}
+
+/*
+ mallinfo returns a copy of updated current mallinfo.
+*/
+
+struct mallinfo mALLINFo(void)
+{
+ malloc_update_mallinfo();
+ return current_mallinfo;
+}
+
+
+
+
+/*
+ mallopt:
+
+ mallopt is the general SVID/XPG interface to tunable parameters.
+ The format is to provide a (parameter-number, parameter-value) pair.
+ mallopt then sets the corresponding parameter to the argument
+ value if it can (i.e., so long as the value is meaningful),
+ and returns 1 if successful else 0.
+
+ See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ switch(param_number)
+ {
+ case M_TRIM_THRESHOLD:
+ trim_threshold = value; return 1;
+ case M_TOP_PAD:
+ top_pad = value; return 1;
+ case M_MMAP_THRESHOLD:
+ mmap_threshold = value; return 1;
+ case M_MMAP_MAX:
+#if HAVE_MMAP
+ n_mmaps_max = value; return 1;
+#else
+ if (value != 0) return 0; else n_mmaps_max = value; return 1;
+#endif
+ case M_SCANHEAP:
+#ifdef DEBUG2
+ scanheap = value;
+#endif
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+
+History:
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
diff --git a/winsup/cygwin/dlmalloc.h b/winsup/cygwin/dlmalloc.h
new file mode 100644
index 000000000..d7bd86927
--- /dev/null
+++ b/winsup/cygwin/dlmalloc.h
@@ -0,0 +1,93 @@
+
+/*
+ * Header file for BBCized version of Doug Lea's malloc.c, automatically
+ * generated by
+ * /source/prod/libbbc/compat/dlmalloc/cvt
+ * from
+ * /source/prod/libbbc/compat/dlmalloc/malloc.c
+ *
+ * bbclabel: autogenerated
+ */
+#define _INCLUDE_MALLOC_H_ 1
+void malloc_outofmem(void (*)(void));
+
+
+struct mallinfo {
+ int arena; /* total space allocated from system */
+ int ordblks; /* number of non-inuse chunks */
+ int smblks; /* unused -- always zero */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* total space in mmapped regions */
+ int usmblks; /* unused -- always zero */
+ int fsmblks; /* unused -- always zero */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total non-inuse space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+
+#define M_MXFAST 1 /* UNUSED in this malloc */
+#define M_NLBLKS 2 /* UNUSED in this malloc */
+#define M_GRAIN 3 /* UNUSED in this malloc */
+#define M_KEEP 4 /* UNUSED in this malloc */
+
+
+#define M_TRIM_THRESHOLD -1
+#define M_TOP_PAD -2
+#define M_MMAP_THRESHOLD -3
+#define M_MMAP_MAX -4
+#define M_SCANHEAP -5
+#define M_FILL
+
+#ifdef MALLOC_DEBUG
+
+#define dlmalloc(size) malloc_dbg(size, __FILE__, __LINE__)
+#define dlfree(p) free_dbg(p, __FILE__, __LINE__)
+#define dlrealloc(p, size) realloc_dbg(p, size, __FILE__, __LINE__)
+#define dlcalloc(n, size) calloc_dbg(n, size, __FILE__, __LINE__)
+#define dlmemalign(align, size) memalign_dbg(align, size, __FILE__, __LINE__)
+#define dlvalloc(size) valloc_dbg(size, __FILE__, __LINE__)
+#define dlpvalloc(size) pvalloc_dbg(size, __FILE__, __LINE__)
+#define dlmalloc_trim(pad) malloc_trim_dbg(pad, __FILE__, __LINE__)
+#define dlmalloc_usable_size(p) malloc_usable_size_dbg(p, __FILE__, __LINE__)
+#define dlmalloc_stats() malloc_stats_dbg(__FILE__, __LINE__)
+#define dlmallopt(flag, val) mallopt_dbg(flag, val, __FILE__, __LINE__)
+#define dlmallinfo() mallinfo_dbg(__FILE__, __LINE__)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void* malloc_dbg(size_t, const char *, int);
+void free_dbg(void*, const char *, int);
+void* realloc_dbg(void*, size_t, const char *, int);
+void* calloc_dbg(size_t, size_t, const char *, int);
+void* memalign_dbg(size_t, size_t, const char *, int);
+void* valloc_dbg(size_t, const char *, int);
+void* pvalloc_dbg(size_t, const char *, int);
+int malloc_trim_dbg(size_t, const char *, int);
+size_t malloc_usable_size_dbg(void*, const char *, int);
+void malloc_stats_dbg(const char *, int);
+int mallopt_dbg(int, int, const char *, int);
+struct mallinfo mallinfo_dbg(const char *, int);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MALLOC_DEBUG */
+
+#ifndef MALLOC_DEBUG
+
+void* malloc(size_t);
+void free(void*);
+void* realloc(void*, size_t);
+void* calloc(size_t, size_t);
+void* memalign(size_t, size_t);
+void* valloc(size_t);
+void* pvalloc(size_t);
+int malloc_trim(size_t);
+size_t malloc_usable_size(void*);
+void malloc_stats(void);
+int mallopt(int, int);
+struct mallinfo mallinfo(void);
+#endif /* !MALLOC_DEBUG */
diff --git a/winsup/cygwin/dtable.sgml b/winsup/cygwin/dtable.sgml
new file mode 100644
index 000000000..73d8b78cc
--- /dev/null
+++ b/winsup/cygwin/dtable.sgml
@@ -0,0 +1,20 @@
+
+<sect1 id="func-cygwin-attach-handle-to-fd">
+<title>cygwin_attach_handle_to_fd</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" int
+<function>cygwin_attach_handle_to_fd</function></funcdef>
+<paramdef>char *<parameter>name</parameter></paramdef>
+<paramdef>int <parameter>fd</parameter></paramdef>
+<paramdef>HANDLE <parameter>handle</parameter></paramdef>
+<paramdef>int <parameter>bin</parameter></paramdef>
+<paramdef>int <parameter>access</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This function can be used to turn a Win32 "handle" into a
+posix-style file handle. <parameter>fd</parameter> may be -1 to
+make cygwin allocate a handle; the actual handle is returned
+in all cases.</para>
+
+</sect1>
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index 589410a9a..2a5f711bd 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -1,7 +1,7 @@
/* errno.cc: errno-related functions
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -59,21 +59,17 @@ static const struct
X (BUSY, EBUSY),
X (BUS_RESET, EIO),
X (CALL_NOT_IMPLEMENTED, ENOSYS),
- X (CANCELLED, EINTR),
X (CANNOT_MAKE, EPERM),
X (CHILD_NOT_COMPLETE, EBUSY),
X (COMMITMENT_LIMIT, EAGAIN),
- X (CONNECTION_REFUSED, ECONNREFUSED),
X (CRC, EIO),
X (DEVICE_DOOR_OPEN, EIO),
X (DEVICE_IN_USE, EAGAIN),
X (DEVICE_REQUIRES_CLEANING, EIO),
- X (DEV_NOT_EXIST, ENOENT),
X (DIRECTORY, ENOTDIR),
X (DIR_NOT_EMPTY, ENOTEMPTY),
X (DISK_CORRUPT, EIO),
X (DISK_FULL, ENOSPC),
- X (DS_GENERIC_ERROR, EIO),
X (DUP_NAME, ENOTUNIQ),
X (EAS_DIDNT_FIT, ENOSPC),
X (EAS_NOT_SUPPORTED, ENOTSUP),
@@ -119,7 +115,6 @@ static const struct
X (NONPAGED_SYSTEM_RESOURCES, EAGAIN),
X (NOT_CONNECTED, ENOLINK),
X (NOT_ENOUGH_MEMORY, ENOMEM),
- X (NOT_ENOUGH_QUOTA, EIO),
X (NOT_OWNER, EPERM),
X (NOT_READY, ENOMEDIUM),
X (NOT_SAME_DEVICE, EXDEV),
@@ -151,7 +146,6 @@ static const struct
X (REM_NOT_LIST, ENONET),
X (SECTOR_NOT_FOUND, EINVAL),
X (SEEK, EINVAL),
- X (SERVICE_REQUEST_TIMEOUT, EBUSY),
X (SETMARK_DETECTED, EIO),
X (SHARING_BUFFER_EXCEEDED, ENOLCK),
X (SHARING_VIOLATION, EBUSY),
@@ -159,10 +153,8 @@ static const struct
X (SIGNAL_REFUSED, EIO),
X (SXS_CANT_GEN_ACTCTX, ELIBBAD),
X (THREAD_1_INACTIVE, EINVAL),
- X (TIMEOUT, EBUSY),
X (TOO_MANY_LINKS, EMLINK),
X (TOO_MANY_OPEN_FILES, EMFILE),
- X (UNEXP_NET_ERR, EIO),
X (WAIT_NO_CHILDREN, ECHILD),
X (WORKING_SET_QUOTA, EAGAIN),
X (WRITE_PROTECT, EROFS),
@@ -363,6 +355,13 @@ seterrno_from_nt_status (const char *file, int line, NTSTATUS status)
errno = _impure_ptr->_errno = geterrno_from_win_error (code, EACCES);
}
+/* seterrno: Set `errno' based on GetLastError (). */
+void __reg2
+seterrno (const char *file, int line)
+{
+ seterrno_from_win_error (file, line, GetLastError ());
+}
+
static char *
strerror_worker (int errnum)
{
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
index fce161192..fd0c46864 100644
--- a/winsup/cygwin/external.cc
+++ b/winsup/cygwin/external.cc
@@ -382,13 +382,13 @@ cygwin_internal (cygwin_getinfo_types t, ...)
case CW_GET_UID_FROM_SID:
{
cygpsid psid = va_arg (arg, PSID);
- res = psid.get_uid (NULL);
+ res = psid.get_id (false, NULL);
}
break;
case CW_GET_GID_FROM_SID:
{
cygpsid psid = va_arg (arg, PSID);
- res = psid.get_gid (NULL);
+ res = psid.get_id (true, NULL);
}
break;
case CW_GET_BINMODE:
@@ -556,123 +556,22 @@ cygwin_internal (cygwin_getinfo_types t, ...)
}
break;
- case CW_SETENT:
- {
- int group = va_arg (arg, int);
- int enums = va_arg (arg, int);
- PCWSTR enum_tdoms = va_arg (arg, PCWSTR);
- if (group)
- res = (uintptr_t) setgrent_filtered (enums, enum_tdoms);
- else
- res = (uintptr_t) setpwent_filtered (enums, enum_tdoms);
- }
- break;
-
- case CW_GETENT:
- {
- int group = va_arg (arg, int);
- void *obj = va_arg (arg, void *);
- if (obj)
- {
- if (group)
- res = (uintptr_t) getgrent_filtered (obj);
- else
- res = (uintptr_t) getpwent_filtered (obj);
- }
- }
- break;
-
- case CW_ENDENT:
- {
- int group = va_arg (arg, int);
- void *obj = va_arg (arg, void *);
- if (obj)
- {
- if (group)
- endgrent_filtered (obj);
- else
- endpwent_filtered (obj);
- res = 0;
- }
- }
- break;
-
- case CW_GETNSSSEP:
- res = (uintptr_t) cygheap->pg.nss_separator ();
- break;
-
case CW_GETPWSID:
- {
- int db_only = va_arg (arg, int);
- PSID psid = va_arg (arg, PSID);
- cygpsid sid (psid);
- res = (uintptr_t) (db_only ? internal_getpwsid_from_db (sid)
- : internal_getpwsid (sid));
- }
- break;
+ {
+ va_arg (arg, int);
+ PSID psid = va_arg (arg, PSID);
+ cygpsid sid (psid);
+ res = (uintptr_t) internal_getpwsid (sid);
+ }
+ break;
case CW_GETGRSID:
- {
- int db_only = va_arg (arg, int);
- PSID psid = va_arg (arg, PSID);
- cygpsid sid (psid);
- res = (uintptr_t) (db_only ? internal_getgrsid_from_db (sid)
- : internal_getgrsid (sid));
- }
- break;
-
- case CW_CYGNAME_FROM_WINNAME:
- {
- /* This functionality has been added mainly for sshd. Sshd
- calls getpwnam() with the username of the non-privileged
- user used for privilege separation. This is usually a
- fixed string "sshd". However, when using usernames from
- the Windows DBs, it's no safe bet anymore if the username
- is "sshd", it could also be "DOMAIN+sshd". So what we do
- here is this:
-
- Sshd calls cygwin_internal (CW_CYGNAME_FROM_WINNAME,
- "sshd",
- username_buffer,
- sizeof username_buffer);
-
- If this call succeeds, sshd expects the correct Cygwin
- username of the unprivileged sshd account in username_buffer.
-
- The below code checks for a Windows username matching the
- incoming username, and then fetches the Cygwin username with
- the matching SID. This is our username used for privsep then.
-
- Of course, other applications with similar needs can use the
- same method. */
- const char *winname = va_arg (arg, const char *);
- char *buffer = va_arg (arg, char *);
- size_t buflen = va_arg (arg, size_t);
-
- if (!winname || !buffer || !buflen)
- break;
-
- WCHAR name[UNLEN + 1];
- sys_mbstowcs (name, sizeof name, winname);
-
- cygsid sid;
- DWORD slen = SECURITY_MAX_SID_SIZE;
- WCHAR dom[DNLEN + 1];
- DWORD dlen = DNLEN + 1;
- SID_NAME_USE acc_type;
-
- if (!LookupAccountNameW (NULL, name, sid, &slen, dom, &dlen,
- &acc_type))
- break;
-
- struct passwd *pw = internal_getpwsid (sid);
- if (!pw)
- break;
-
- buffer[0] = '\0';
- strncat (buffer, pw->pw_name, buflen - 1);
- res = 0;
- }
+ {
+ va_arg (arg, int);
+ PSID psid = va_arg (arg, PSID);
+ cygpsid sid (psid);
+ res = (uintptr_t) internal_getgrsid (sid);
+ }
break;
case CW_FIXED_ATEXIT:
diff --git a/winsup/cygwin/external.sgml b/winsup/cygwin/external.sgml
new file mode 100644
index 000000000..bbfdd0fb8
--- /dev/null
+++ b/winsup/cygwin/external.sgml
@@ -0,0 +1,18 @@
+
+<sect1 id="func-cygwin-internal">
+<title>cygwin_internal</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" DWORD
+<function>cygwin_internal</function></funcdef>
+<paramdef>cygwin_getinfo_types <parameter>t</parameter></paramdef>
+<paramdef><parameter>...</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This function gives you access to various internal data and functions.
+It takes two arguments. The first argument is a type from the 'cygwin_getinfo_types'
+enum. The second is an optional pointer.</para>
+<para>Stay away unless you know what you're doing.</para>
+
+</sect1>
+
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 8444d4abc..c64fc33b1 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1737,6 +1737,9 @@ fhandler_base::facl (int cmd, int nentries, aclent_t *aclbufp)
aclbufp[2].a_type = OTHER_OBJ;
aclbufp[2].a_id = ILLEGAL_GID;
aclbufp[2].a_perm = S_IROTH | S_IWOTH;
+ aclbufp[3].a_type = CLASS_OBJ;
+ aclbufp[3].a_id = ILLEGAL_GID;
+ aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
res = MIN_ACL_ENTRIES;
}
break;
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index ba615c26f..22709ffdf 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -10,8 +10,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <winioctl.h>
-#include <lm.h>
#include <stdlib.h>
#include <sys/acl.h>
#include <sys/statvfs.h>
@@ -25,8 +23,10 @@ details. */
#include "pinfo.h"
#include "ntdll.h"
#include "tls_pbuf.h"
+#include "pwdgrp.h"
+#include <winioctl.h>
+#include <lm.h>
#include "devices.h"
-#include "ldap.h"
#define _COMPILING_NEWLIB
#include <dirent.h>
@@ -323,9 +323,6 @@ int __reg2
fhandler_base::fstat_by_nfs_ea (struct stat *buf)
{
fattr3 *nfs_attr = pc.nfsattr ();
- PWCHAR domain;
- cyg_ldap cldap;
- bool ldap_open = false;
if (get_io_handle ())
{
@@ -343,36 +340,14 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf)
buf->st_mode = (nfs_attr->mode & 0xfff)
| nfs_type_mapping[nfs_attr->type & 7];
buf->st_nlink = nfs_attr->nlink;
- /* Try to map UNIX uid/gid to Cygwin uid/gid. If there's no mapping in
- the cache, try to fetch it from the configured RFC 2307 domain (see
- last comment in cygheap_domain_info::init() for more information) and
- add it to the mapping cache. */
- buf->st_uid = cygheap->ugid_cache.get_uid (nfs_attr->uid);
- buf->st_gid = cygheap->ugid_cache.get_gid (nfs_attr->gid);
- if (buf->st_uid == ILLEGAL_UID)
- {
- uid_t map_uid = ILLEGAL_UID;
-
- domain = cygheap->dom.get_rfc2307_domain ();
- if ((ldap_open = (cldap.open (domain) == NO_ERROR)))
- map_uid = cldap.remap_uid (nfs_attr->uid);
- if (map_uid == ILLEGAL_UID)
- map_uid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->uid);
- cygheap->ugid_cache.add_uid (nfs_attr->uid, map_uid);
- buf->st_uid = map_uid;
- }
- if (buf->st_gid == ILLEGAL_GID)
- {
- gid_t map_gid = ILLEGAL_GID;
-
- domain = cygheap->dom.get_rfc2307_domain ();
- if ((ldap_open || cldap.open (domain) == NO_ERROR))
- map_gid = cldap.remap_gid (nfs_attr->gid);
- if (map_gid == ILLEGAL_GID)
- map_gid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->gid);
- cygheap->ugid_cache.add_gid (nfs_attr->gid, map_gid);
- buf->st_gid = map_gid;
- }
+ /* FIXME: How to convert UNIX uid/gid to Windows SIDs? */
+#if 0
+ buf->st_uid = nfs_attr->uid;
+ buf->st_gid = nfs_attr->gid;
+#else
+ buf->st_uid = myself->uid;
+ buf->st_gid = myself->gid;
+#endif
buf->st_rdev = makedev (nfs_attr->rdev.specdata1,
nfs_attr->rdev.specdata2);
buf->st_size = nfs_attr->size;
@@ -534,7 +509,8 @@ fhandler_base::fstat_fs (struct stat *buf)
}
int __reg3
-fhandler_base::fstat_helper (struct stat *buf, DWORD nNumberOfLinks)
+fhandler_base::fstat_helper (struct stat *buf,
+ DWORD nNumberOfLinks)
{
IO_STATUS_BLOCK st;
FILE_COMPRESSION_INFORMATION fci;
@@ -822,7 +798,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs)
}
else
debug_printf ("%y = NtQueryVolumeInformationFile"
- "(%S, FileFsFullSizeInformation)",
+ "(%S, FileFsFullSizeInformation)",
status, pc.get_nt_native_path ());
out:
if (opened)
@@ -1045,6 +1021,9 @@ cant_access_acl:
aclbufp[2].a_type = OTHER_OBJ;
aclbufp[2].a_id = ILLEGAL_GID;
aclbufp[2].a_perm = st.st_mode & S_IRWXO;
+ aclbufp[3].a_type = CLASS_OBJ;
+ aclbufp[3].a_id = ILLEGAL_GID;
+ aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
res = MIN_ACL_ENTRIES;
}
}
@@ -2046,8 +2025,7 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
fname->Length = 0;
return geterrno_from_win_error (w32_err);
}
- if (de->d_ino == 2) /* Inode number for virtual dirs. */
- de->d_type = DT_DIR;
+
attr = 0;
dir->__flags &= ~dirent_set_d_ino;
}
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
index 0fd2e569c..34acf4ed1 100644
--- a/winsup/cygwin/fhandler_proc.cc
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -254,9 +254,7 @@ fhandler_proc::readdir (DIR *dir, dirent *de)
int res;
if (dir->__d_position < PROC_LINK_COUNT)
{
- strcpy (de->d_name, proc_tab[dir->__d_position].name);
- de->d_type = virt_ftype_to_dtype (proc_tab[dir->__d_position].type);
- dir->__d_position++;
+ strcpy (de->d_name, proc_tab[dir->__d_position++].name);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
}
@@ -269,7 +267,6 @@ fhandler_proc::readdir (DIR *dir, dirent *de)
if (found++ == dir->__d_position - PROC_LINK_COUNT)
{
__small_sprintf (de->d_name, "%d", pids[i]->pid);
- de->d_type = DT_DIR;
dir->__d_position++;
res = 0;
break;
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index e2de05b3c..01de47436 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -24,6 +24,7 @@ details. */
#include "cygheap.h"
#include "ntdll.h"
#include "cygtls.h"
+#include "pwdgrp.h"
#include "mount.h"
#include "tls_pbuf.h"
#include <sys/sysmacros.h>
@@ -230,14 +231,9 @@ fhandler_process::readdir (DIR *dir, dirent *de)
{
int *p = (int *) filebuf;
__small_sprintf (de->d_name, "%d", p[dir->__d_position++ - 2]);
- de->d_type = DT_LNK;
}
else
- {
- strcpy (de->d_name, process_tab[dir->__d_position].name);
- de->d_type = virt_ftype_to_dtype (process_tab[dir->__d_position].type);
- dir->__d_position++;
- }
+ strcpy (de->d_name, process_tab[dir->__d_position++].name);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
out:
diff --git a/winsup/cygwin/fhandler_procnet.cc b/winsup/cygwin/fhandler_procnet.cc
index 1961fdda3..0ba64aeea 100644
--- a/winsup/cygwin/fhandler_procnet.cc
+++ b/winsup/cygwin/fhandler_procnet.cc
@@ -1,6 +1,6 @@
/* fhandler_procnet.cc: fhandler for /proc/net virtual filesystem
- Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -115,9 +115,7 @@ fhandler_procnet::readdir (DIR *dir, dirent *de)
if (procnet_tab[dir->__d_position].type == virt_file
&& !get_adapters_addresses (NULL, AF_INET6))
goto out;
- strcpy (de->d_name, procnet_tab[dir->__d_position].name);
- de->d_type = virt_ftype_to_dtype (procnet_tab[dir->__d_position].type);
- dir->__d_position++;
+ strcpy (de->d_name, procnet_tab[dir->__d_position++].name);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
out:
diff --git a/winsup/cygwin/fhandler_procsys.cc b/winsup/cygwin/fhandler_procsys.cc
index 1e937c89d..759712f04 100644
--- a/winsup/cygwin/fhandler_procsys.cc
+++ b/winsup/cygwin/fhandler_procsys.cc
@@ -1,6 +1,6 @@
/* fhandler_procsys.cc: fhandler for native NT namespace.
- Copyright 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ Copyright 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -177,28 +177,30 @@ fhandler_procsys::exists (struct stat *buf)
/* Don't call NtQueryInformationFile unless we know it's a safe type.
The call is known to crash machines, if the underlying driver is
badly written. */
- if (NT_SUCCESS (status))
+ if (!NT_SUCCESS (status))
+ {
+ NtClose (h);
+ return file_type;
+ }
+ if (ffdi.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
+ file_type = virt_blk;
+ else if (ffdi.DeviceType == FILE_DEVICE_NAMED_PIPE)
+ file_type = internal ? virt_blk : virt_pipe;
+ else if (ffdi.DeviceType == FILE_DEVICE_DISK
+ || ffdi.DeviceType == FILE_DEVICE_CD_ROM
+ || ffdi.DeviceType == FILE_DEVICE_DFS
+ || ffdi.DeviceType == FILE_DEVICE_VIRTUAL_DISK)
{
- if (ffdi.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
+ /* Check for file attributes. If we get them, we peeked
+ into a real FS through /proc/sys. */
+ status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
+ FileBasicInformation);
+ debug_printf ("NtQueryInformationFile: %y", status);
+ if (!NT_SUCCESS (status))
file_type = virt_blk;
- else if (ffdi.DeviceType == FILE_DEVICE_NAMED_PIPE)
- file_type = internal ? virt_blk : virt_pipe;
- else if (ffdi.DeviceType == FILE_DEVICE_DISK
- || ffdi.DeviceType == FILE_DEVICE_CD_ROM
- || ffdi.DeviceType == FILE_DEVICE_DFS
- || ffdi.DeviceType == FILE_DEVICE_VIRTUAL_DISK)
- {
- /* Check for file attributes. If we get them, we peeked
- into a real FS through /proc/sys. */
- status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
- FileBasicInformation);
- debug_printf ("NtQueryInformationFile: %y", status);
- if (!NT_SUCCESS (status))
- file_type = virt_blk;
- else
- file_type = (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- ? virt_fsdir : virt_fsfile;
- }
+ else
+ file_type = (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ? virt_fsdir : virt_fsfile;
}
NtClose (h);
}
@@ -358,17 +360,7 @@ fhandler_procsys::readdir (DIR *dir, dirent *de)
sys_wcstombs (de->d_name, NAME_MAX + 1, f.dbi.ObjectName.Buffer,
f.dbi.ObjectName.Length / sizeof (WCHAR));
de->d_ino = hash_path_name (get_ino (), de->d_name);
- if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdir,
- FALSE))
- de->d_type = DT_DIR;
- else if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natsyml,
- FALSE))
- de->d_type = DT_LNK;
- else if (!RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdev,
- FALSE))
- de->d_type = DT_CHR;
- else /* Can't nail down "Device" objects without further testing. */
- de->d_type = DT_UNKNOWN;
+ de->d_type = 0;
res = 0;
}
}
diff --git a/winsup/cygwin/fhandler_procsysvipc.cc b/winsup/cygwin/fhandler_procsysvipc.cc
index bd1eee0a1..1c0ea287a 100644
--- a/winsup/cygwin/fhandler_procsysvipc.cc
+++ b/winsup/cygwin/fhandler_procsysvipc.cc
@@ -125,9 +125,7 @@ fhandler_procsysvipc::readdir (DIR *dir, dirent *de)
if (cygserver_running != CYGSERVER_OK)
goto out;
}
- strcpy (de->d_name, procsysvipc_tab[dir->__d_position].name);
- de->d_type = virt_ftype_to_dtype (procsysvipc_tab[dir->__d_position].type);
- dir->__d_position++;
+ strcpy (de->d_name, procsysvipc_tab[dir->__d_position++].name);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
out:
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
index fd3b76824..d4b6706c7 100644
--- a/winsup/cygwin/fhandler_registry.cc
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -586,8 +586,8 @@ fhandler_registry::fstat (struct stat *buf)
and it's also rather unlikely that the user is the owner.
Therefore it's probably most safe to assume unknown ownership
and no permissions for nobody. */
- buf->st_uid = ILLEGAL_UID;
- buf->st_gid = ILLEGAL_GID;
+ buf->st_uid = UNKNOWN_UID;
+ buf->st_gid = UNKNOWN_GID;
buf->st_mode &= ~0777;
}
}
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 59561bc58..8f38712a8 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -396,8 +396,7 @@ fhandler_socket::af_local_send_cred ()
int
fhandler_socket::af_local_connect ()
{
- bool orig_async_io, orig_is_nonblocking;
-
+ /* This keeps the test out of select. */
if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM)
return 0;
@@ -405,6 +404,7 @@ fhandler_socket::af_local_connect ()
if (no_getpeereid ())
return 0;
+ bool orig_async_io, orig_is_nonblocking;
af_local_setblocking (orig_async_io, orig_is_nonblocking);
if (!af_local_send_secret () || !af_local_recv_secret ()
|| !af_local_send_cred () || !af_local_recv_cred ())
@@ -421,12 +421,11 @@ fhandler_socket::af_local_connect ()
int
fhandler_socket::af_local_accept ()
{
- bool orig_async_io, orig_is_nonblocking;
-
debug_printf ("af_local_accept called, no_getpeereid=%d", no_getpeereid ());
if (no_getpeereid ())
return 0;
+ bool orig_async_io, orig_is_nonblocking;
af_local_setblocking (orig_async_io, orig_is_nonblocking);
if (!af_local_recv_secret () || !af_local_send_secret ()
|| !af_local_recv_cred () || !af_local_send_cred ())
@@ -644,35 +643,7 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
wsock_events->events |= evts.lNetworkEvents;
events_now = (wsock_events->events & event_mask);
if (evts.lNetworkEvents & FD_CONNECT)
- {
- wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
-
- /* Setting the connect_state and calling the AF_LOCAL handshake
- here allows to handle this stuff from a single point. This
- is independent of FD_CONNECT being requested. Consider a
- server calling connect(2) and then immediately poll(2) with
- only polling for POLLIN (example: postfix), or select(2) just
- asking for descriptors ready to read.
-
- Something weird occurs in Winsock: If you fork off and call
- recv/send on the duplicated, already connected socket, another
- FD_CONNECT event is generated in the child process. This
- would trigger a call to af_local_connect which obviously fail.
- Avoid this by calling set_connect_state only if connect_state
- is connect_pending. */
- if (connect_state () == connect_pending)
- {
- if (wsock_events->connect_errorcode)
- connect_state (connect_failed);
- else if (af_local_connect ())
- {
- wsock_events->connect_errorcode = WSAGetLastError ();
- connect_state (connect_failed);
- }
- else
- connect_state (connected);
- }
- }
+ wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
UNLOCK_EVENTS;
if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner)
kill (wsock_events->owner, SIGURG);
@@ -685,15 +656,15 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
{
if (events & FD_CONNECT)
{
- int wsa_err = wsock_events->connect_errorcode;
- if (wsa_err)
+ int wsa_err = 0;
+ if ((wsa_err = wsock_events->connect_errorcode) != 0)
{
/* CV 2014-04-23: This is really weird. If you call connect
asynchronously on a socket and then select, an error like
"Connection refused" is set in the event and in the SO_ERROR
socket option. If you call connect, then dup, then select,
the error is set in the event, but not in the SO_ERROR socket
- option, despite the dup'ed socket handle referring to the same
+ option, even if the dup'ed socket handle refers to the same
socket. We're trying to workaround this problem here by
taking the connect errorcode from the event and write it back
into the SO_ERROR socket option.
@@ -1135,45 +1106,21 @@ out:
int
fhandler_socket::connect (const struct sockaddr *name, int namelen)
{
+ bool in_progress = false;
struct sockaddr_storage sst;
+ DWORD err;
int type;
if (get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)
== SOCKET_ERROR)
return SOCKET_ERROR;
- if (get_addr_family () == AF_LOCAL)
+ if (get_addr_family () == AF_LOCAL && get_socket_type () != type)
{
- if (get_socket_type () != type)
- {
- WSASetLastError (WSAEPROTOTYPE);
- set_winsock_errno ();
- return SOCKET_ERROR;
- }
-
- set_peer_sun_path (name->sa_data);
-
- /* Don't move af_local_set_cred into af_local_connect which may be called
- via select, possibly running under another identity. Call early here,
- because af_local_connect is called in wait_for_events. */
- if (get_socket_type () == SOCK_STREAM)
- af_local_set_cred ();
+ WSASetLastError (WSAEPROTOTYPE);
+ set_winsock_errno ();
+ return SOCKET_ERROR;
}
-
- /* Initialize connect state to "connect_pending". State is ultimately set
- to "connected" or "connect_failed" in wait_for_events when the FD_CONNECT
- event occurs. Note that the underlying OS sockets are always non-blocking
- and a successfully initiated non-blocking Winsock connect always returns
- WSAEWOULDBLOCK. Thus it's safe to rely on event handling.
-
- Check for either unconnected or connect_failed since in both cases it's
- allowed to retry connecting the socket. It's also ok (albeit ugly) to
- call connect to check if a previous non-blocking connect finished.
-
- Set connect_state before calling connect, otherwise a race condition with
- an already running select or poll might occur. */
- if (connect_state () == unconnected || connect_state () == connect_failed)
- connect_state (connect_pending);
int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
if (!is_nonblocking ()
@@ -1181,31 +1128,48 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
&& WSAGetLastError () == WSAEWOULDBLOCK)
res = wait_for_events (FD_CONNECT | FD_CLOSE, 0);
- if (res)
+ if (!res)
+ err = 0;
+ else
{
- DWORD err = WSAGetLastError ();
-
- /* Some applications use the ugly technique to check if a non-blocking
- connect succeeded by calling connect again, until it returns EISCONN.
- This circumvents the event handling and connect_state is never set.
- Thus we check for this situation here. */
- if (err == WSAEISCONN)
- connect_state (connected);
- /* Winsock returns WSAEWOULDBLOCK if the non-blocking socket cannot be
- conected immediately. Convert to POSIX/Linux compliant EINPROGRESS. */
- else if (is_nonblocking () && err == WSAEWOULDBLOCK)
- WSASetLastError (WSAEINPROGRESS);
- /* Winsock returns WSAEINVAL if the socket is already a listener.
- Convert to POSIX/Linux compliant EISCONN. */
- else if (err == WSAEINVAL && connect_state () == listener)
- WSASetLastError (WSAEISCONN);
- /* Any other error except WSAEALREADY during connect_pending means the
- connect failed. */
- else if (connect_state () == connect_pending && err != WSAEALREADY)
- connect_state (connect_failed);
+ err = WSAGetLastError ();
+ /* Special handling for connect to return the correct error code
+ when called on a non-blocking socket. */
+ if (is_nonblocking ())
+ {
+ if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
+ in_progress = true;
+
+ if (err == WSAEWOULDBLOCK)
+ WSASetLastError (err = WSAEINPROGRESS);
+ }
+ if (err == WSAEINVAL)
+ WSASetLastError (err = WSAEISCONN);
set_winsock_errno ();
}
+ if (get_addr_family () == AF_LOCAL && (!res || in_progress))
+ set_peer_sun_path (name->sa_data);
+
+ if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
+ {
+ af_local_set_cred (); /* Don't move into af_local_connect since
+ af_local_connect is called from select,
+ possibly running under another identity. */
+ if (!res && af_local_connect ())
+ {
+ set_winsock_errno ();
+ return SOCKET_ERROR;
+ }
+ }
+
+ if (err == WSAEINPROGRESS || err == WSAEALREADY)
+ connect_state (connect_pending);
+ else if (err)
+ connect_state (connect_failed);
+ else
+ connect_state (connected);
+
return res;
}
@@ -1463,13 +1427,6 @@ fhandler_socket::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
static NO_COPY LPFN_WSARECVMSG WSARecvMsg;
int orig_namelen = wsamsg->namelen;
- /* CV 2014-10-26: Do not check for the connect_state at this point. In
- certain scenarios there's no way to check the connect state reliably.
- Example (hexchat): Parent process creates socket, forks, child process
- calls connect, parent process calls read. Even if the event handling
- allows to check for FD_CONNECT in the parent, there is always yet another
- scenario we can easily break. */
-
DWORD wait_flags = wsamsg->dwFlags;
bool waitall = !!(wait_flags & MSG_WAITALL);
wsamsg->dwFlags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE);
diff --git a/winsup/cygwin/fhandler_virtual.h b/winsup/cygwin/fhandler_virtual.h
index f92c06b89..9747dd2cb 100644
--- a/winsup/cygwin/fhandler_virtual.h
+++ b/winsup/cygwin/fhandler_virtual.h
@@ -1,6 +1,6 @@
/* fhandler_virtual.h: Header for virtual fhandlers
- Copyright 2009, 2010, 2011, 2014 Red Hat, Inc.
+ Copyright 2009, 2010, 2011 Red Hat, Inc.
This file is part of Cygwin.
@@ -20,26 +20,3 @@ struct virt_tab_t {
extern virt_tab_t *virt_tab_search (const char *, bool, const virt_tab_t *,
size_t);
-
-static inline unsigned char
-virt_ftype_to_dtype (virtual_ftype_t type)
-{
- unsigned char d_type;
-
- switch (type)
- {
- case virt_directory:
- d_type = DT_DIR;
- break;
- case virt_symlink:
- d_type = DT_LNK;
- break;
- case virt_file:
- d_type = DT_REG;
- break;
- default:
- d_type = DT_UNKNOWN;
- break;
- }
- return d_type;
-}
diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc
index 92f9acc8a..a37175469 100644
--- a/winsup/cygwin/globals.cc
+++ b/winsup/cygwin/globals.cc
@@ -148,9 +148,6 @@ extern "C" {
extern UNICODE_STRING _RDATA ro_u_pipedir = _ROU (L"\\\\?\\PIPE\\");
extern UNICODE_STRING _RDATA ro_u_globalroot = _ROU (L"\\\\.\\GLOBALROOT");
extern UNICODE_STRING _RDATA ro_u_null = _ROU (L"\\Device\\Null");
- extern UNICODE_STRING _RDATA ro_u_natdir = _ROU (L"Directory");
- extern UNICODE_STRING _RDATA ro_u_natsyml = _ROU (L"SymbolicLink");
- extern UNICODE_STRING _RDATA ro_u_natdev = _ROU (L"Device");
#undef _ROU
/* Cygwin properties are meant to be readonly data placed in the DLL, but
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index f7ce61b08..d4d1b653f 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -1,7 +1,7 @@
/* grp.cc
Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2008, 2009, 2011, 2012, 2013 Red Hat, Inc.
Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
@@ -13,7 +13,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <lm.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,166 +23,134 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
-#include "miscfuncs.h"
-#include "ldap.h"
-#include "tls_pbuf.h"
+#include "pwdgrp.h"
+static group *group_buf;
+static pwdgrp gr (group_buf);
static char * NO_COPY_RO null_ptr;
bool
pwdgrp::parse_group ()
{
- pg_grp &grp = group ()[curr_lines];
- grp.g.gr_name = next_str (':');
- if (!*grp.g.gr_name)
+ group &grp = (*group_buf)[curr_lines];
+ grp.gr_name = next_str (':');
+ if (!*grp.gr_name)
return false;
- grp.g.gr_passwd = next_str (':');
- /* Note that lptr points to the first byte of the gr_gid field.
- We deliberately ignore the gr_gid and gr_mem entries when copying
- the buffer content since they are not referenced anymore. */
- grp.len = lptr - grp.g.gr_name;
- if (!next_num (grp.g.gr_gid))
+
+ grp.gr_passwd = next_str (':');
+
+ if (!next_num (grp.gr_gid))
return false;
- /* Don't generate gr_mem entries. */
- grp.g.gr_mem = &null_ptr;
- grp.sid.getfromgr (&grp.g);
+
+ int n;
+ char *dp = raw_ptr ();
+ for (n = 0; *next_str (','); n++)
+ continue;
+
+ grp.gr_mem = &null_ptr;
+ if (n)
+ {
+ char **namearray = (char **) calloc (n + 1, sizeof (char *));
+ if (namearray)
+ {
+ for (int i = 0; i < n; i++, dp = strchr (dp, '\0') + 1)
+ namearray[i] = dp;
+ grp.gr_mem = namearray;
+ }
+ }
+
return true;
}
-muto NO_COPY pwdgrp::pglock;
-
+/* Cygwin internal */
+/* Read in /etc/group and save contents in the group cache */
+/* This sets group_in_memory_p to 1 so functions in this file can
+ tell that /etc/group has been read in */
void
-pwdgrp::init_grp ()
+pwdgrp::read_group ()
{
- pwdgrp_buf_elem_size = sizeof (pg_grp);
- parse = &pwdgrp::parse_group;
-}
+ for (int i = 0; i < gr.curr_lines; i++)
+ if ((*group_buf)[i].gr_mem != &null_ptr)
+ free ((*group_buf)[i].gr_mem);
-struct group *
-pwdgrp::find_group (cygpsid &sid)
-{
- for (ULONG i = 0; i < curr_lines; i++)
- if (sid == group ()[i].sid)
- return &group ()[i].g;
- return NULL;
+ load (L"\\etc\\group");
+
+ /* Complete /etc/group in memory if needed */
+ if (!internal_getgrgid (myself->gid))
+ {
+ static char linebuf [200];
+ char group_name [UNLEN + 1] = "mkgroup";
+ char strbuf[128] = "";
+ struct group *gr;
+
+ cygheap->user.groups.pgsid.string (strbuf);
+ if ((gr = internal_getgrsid (cygheap->user.groups.pgsid)))
+ snprintf (group_name, sizeof (group_name),
+ "passwd/group_GID_clash(%u/%u)", myself->gid, gr->gr_gid);
+ if (myself->uid == UNKNOWN_UID)
+ strcpy (group_name, "mkpasswd"); /* Feedback... */
+ snprintf (linebuf, sizeof (linebuf), "%s:%s:%u:%s",
+ group_name, strbuf, myself->gid, cygheap->user.name ());
+ debug_printf ("Completing /etc/group: %s", linebuf);
+ add_line (linebuf);
+ }
+ static char NO_COPY pretty_ls[] = "????????::-1:";
+ add_line (pretty_ls);
}
-struct group *
-pwdgrp::find_group (const char *name)
+muto NO_COPY pwdgrp::pglock;
+
+pwdgrp::pwdgrp (passwd *&pbuf) :
+ pwdgrp_buf_elem_size (sizeof (*pbuf)), passwd_buf (&pbuf)
{
- for (ULONG i = 0; i < curr_lines; i++)
- if (strcasematch (group ()[i].g.gr_name, name))
- return &group ()[i].g;
- return NULL;
+ read = &pwdgrp::read_passwd;
+ parse = &pwdgrp::parse_passwd;
+ pglock.init ("pglock");
}
-struct group *
-pwdgrp::find_group (gid_t gid)
+pwdgrp::pwdgrp (group *&gbuf) :
+ pwdgrp_buf_elem_size (sizeof (*gbuf)), group_buf (&gbuf)
{
- for (ULONG i = 0; i < curr_lines; i++)
- if (gid == group ()[i].g.gr_gid)
- return &group ()[i].g;
- return NULL;
+ read = &pwdgrp::read_group;
+ parse = &pwdgrp::parse_group;
+ pglock.init ("pglock");
}
struct group *
-internal_getgrsid (cygpsid &sid, cyg_ldap *pldap)
+internal_getgrsid (cygpsid &sid)
{
- struct group *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.find_group (sid)))
- return ret;
- if (cygheap->pg.nss_grp_files ()
- && (ret = cygheap->pg.grp_cache.file.find_group (sid)))
- return ret;
- if (cygheap->pg.nss_grp_db ()
- && (ret = cygheap->pg.grp_cache.win.find_group (sid)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (sid)))
- return ret;
- if (cygheap->pg.nss_grp_files ())
- {
- cygheap->pg.grp_cache.file.check_file ();
- if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (sid)))
- return ret;
- }
- if (cygheap->pg.nss_grp_db ())
- return cygheap->pg.grp_cache.win.add_group_from_windows (sid, pldap);
+ char sid_string[128];
+
+ gr.refresh (false);
+
+ if (sid.string (sid_string))
+ for (int i = 0; i < gr.curr_lines; i++)
+ if (!strcmp (sid_string, group_buf[i].gr_passwd))
+ return group_buf + i;
return NULL;
}
-/* This function gets only called from mkgroup via cygwin_internal. */
struct group *
-internal_getgrsid_from_db (cygpsid &sid)
+internal_getgrgid (gid_t gid, bool check)
{
- cygheap->pg.nss_init ();
- return cygheap->pg.grp_cache.win.add_group_from_windows (sid);
-}
+ gr.refresh (check);
-struct group *
-internal_getgrnam (const char *name, cyg_ldap *pldap)
-{
- struct group *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.find_group (name)))
- return ret;
- if (cygheap->pg.nss_grp_files ()
- && (ret = cygheap->pg.grp_cache.file.find_group (name)))
- return ret;
- if (cygheap->pg.nss_grp_db ()
- && (ret = cygheap->pg.grp_cache.win.find_group (name)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (name)))
- return ret;
- if (cygheap->pg.nss_grp_files ())
- {
- cygheap->pg.grp_cache.file.check_file ();
- if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (name)))
- return ret;
- }
- if (cygheap->pg.nss_grp_db ())
- return cygheap->pg.grp_cache.win.add_group_from_windows (name, pldap);
+ for (int i = 0; i < gr.curr_lines; i++)
+ if (group_buf[i].gr_gid == gid)
+ return group_buf + i;
return NULL;
}
struct group *
-internal_getgrgid (gid_t gid, cyg_ldap *pldap)
+internal_getgrnam (const char *name, bool check)
{
- struct group *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.find_group (gid)))
- return ret;
- if (cygheap->pg.nss_grp_files ()
- && (ret = cygheap->pg.grp_cache.file.find_group (gid)))
- return ret;
- if (cygheap->pg.nss_grp_db ()
- && (ret = cygheap->pg.grp_cache.win.find_group (gid)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver (gid)))
- return ret;
- if (cygheap->pg.nss_grp_files ())
- {
- cygheap->pg.grp_cache.file.check_file ();
- if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (gid)))
- return ret;
- }
- if (cygheap->pg.nss_grp_db () || gid == ILLEGAL_GID)
- return cygheap->pg.grp_cache.win.add_group_from_windows (gid, pldap);
+ gr.refresh (check);
+
+ for (int i = 0; i < gr.curr_lines; i++)
+ if (strcasematch (group_buf[i].gr_name, name))
+ return group_buf + i;
+
+ /* Didn't find requested group */
return NULL;
}
@@ -214,65 +181,37 @@ getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize,
if (!grp || !buffer)
return ERANGE;
- struct group *tempgr = internal_getgrgid (gid);
+ struct group *tempgr = internal_getgrgid (gid, true);
pthread_testcancel ();
if (!tempgr)
return 0;
- /* Check needed buffer size. Deliberately ignore gr_mem. */
+ /* check needed buffer size. */
+ int i;
size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
+ 2 + sizeof (char *);
+ for (i = 0; tempgr->gr_mem[i]; ++i)
+ needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *);
if (needsize > bufsize)
return ERANGE;
- /* Make a copy of tempgr. Deliberately ignore gr_mem. */
+ /* make a copy of tempgr */
*result = grp;
grp->gr_gid = tempgr->gr_gid;
buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
grp->gr_mem = (char **) (buffer + 1);
- grp->gr_mem[0] = NULL;
+ buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *);
+ for (i = 0; tempgr->gr_mem[i]; ++i)
+ buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1;
+ grp->gr_mem[i] = NULL;
return 0;
}
-/* getgrgid/getgrnam are not reentrant. */
-static struct {
- struct group g;
- char *buf;
- size_t bufsiz;
-} app_gr;
-
-static struct group *
-getgr_cp (struct group *tempgr)
-{
- if (!tempgr)
- return NULL;
- pg_grp *gr = (pg_grp *) tempgr;
- if (app_gr.bufsiz < gr->len)
- {
- char *newbuf = (char *) realloc (app_gr.buf, gr->len);
- if (!newbuf)
- {
- set_errno (ENOMEM);
- return NULL;
- }
- app_gr.buf = newbuf;
- app_gr.bufsiz = gr->len;
- }
- memcpy (app_gr.buf, gr->g.gr_name, gr->len);
- memcpy (&app_gr.g, &gr->g, sizeof gr->g);
- ptrdiff_t diff = app_gr.buf - gr->g.gr_name;
- app_gr.g.gr_name += diff;
- app_gr.g.gr_passwd += diff;
- return &app_gr.g;
-}
-
extern "C" struct group *
getgrgid32 (gid_t gid)
{
- struct group *tempgr = internal_getgrgid (gid);
- pthread_testcancel ();
- return getgr_cp (tempgr);
+ return internal_getgrgid (gid, true);
}
#ifdef __x86_64__
@@ -296,33 +235,37 @@ getgrnam_r (const char *nam, struct group *grp, char *buffer,
if (!grp || !buffer)
return ERANGE;
- struct group *tempgr = internal_getgrnam (nam);
+ struct group *tempgr = internal_getgrnam (nam, true);
pthread_testcancel ();
if (!tempgr)
return 0;
- /* Check needed buffer size. Deliberately ignore gr_mem. */
+ /* check needed buffer size. */
+ int i;
size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
+ 2 + sizeof (char *);
+ for (i = 0; tempgr->gr_mem[i]; ++i)
+ needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *);
if (needsize > bufsize)
return ERANGE;
- /* Make a copy of tempgr. Deliberately ignore gr_mem. */
+ /* make a copy of tempgr */
*result = grp;
grp->gr_gid = tempgr->gr_gid;
buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
grp->gr_mem = (char **) (buffer + 1);
- grp->gr_mem[0] = NULL;
+ buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *);
+ for (i = 0; tempgr->gr_mem[i]; ++i)
+ buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1;
+ grp->gr_mem[i] = NULL;
return 0;
}
extern "C" struct group *
getgrnam32 (const char *name)
{
- struct group *tempgr = internal_getgrnam (name);
- pthread_testcancel ();
- return getgr_cp (tempgr);
+ return internal_getgrnam (name, true);
}
#ifdef __x86_64__
@@ -337,119 +280,21 @@ getgrnam (const char *name)
}
#endif
-/* getgrent functions are not reentrant. */
-static gr_ent grent;
-
-void *
-gr_ent::enumerate_caches ()
-{
- switch (max)
- {
- case 0:
- if (cygheap->pg.nss_cygserver_caching ())
- {
- pwdgrp &grc = cygheap->pg.grp_cache.cygserver;
- if (cnt < grc.cached_groups ())
- return &grc.group ()[cnt++].g;
- }
- cnt = 0;
- max = 1;
- /*FALLTHRU*/
- case 1:
- if (from_files)
- {
- pwdgrp &grf = cygheap->pg.grp_cache.file;
- grf.check_file ();
- if (cnt < grf.cached_groups ())
- return &grf.group ()[cnt++].g;
- }
- cnt = 0;
- max = 2;
- /*FALLTHRU*/
- case 2:
- if (from_db)
- {
- pwdgrp &grw = cygheap->pg.grp_cache.win;
- if (cnt < grw.cached_groups ())
- return &grw.group ()[cnt++].g;
- }
- break;
- }
- cnt = max = 0;
- return NULL;
-}
-
-void *
-gr_ent::enumerate_local ()
-{
- while (true)
- {
- if (!cnt)
- {
- DWORD total;
- NET_API_STATUS ret;
-
- if (buf)
- {
- NetApiBufferFree (buf);
- buf = NULL;
- }
- if (resume == ULONG_MAX)
- ret = ERROR_NO_MORE_ITEMS;
- else
- ret = NetLocalGroupEnum (NULL, 0, (PBYTE *) &buf,
- MAX_PREFERRED_LENGTH,
- &max, &total, &resume);
- if (ret == NERR_Success)
- resume = ULONG_MAX;
- else if (ret != ERROR_MORE_DATA)
- {
- cnt = max = resume = 0;
- return NULL;
- }
- }
- while (cnt < max)
- {
- cygsid sid;
- DWORD slen = SECURITY_MAX_SID_SIZE;
- WCHAR dom[DNLEN + 1];
- DWORD dlen = DNLEN + 1;
- SID_NAME_USE acc_type;
-
- LookupAccountNameW (NULL,
- ((PLOCALGROUP_INFO_0) buf)[cnt++].lgrpi0_name,
- sid, &slen, dom, &dlen, &acc_type);
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = pg.fetch_account_from_windows (arg);
- if (line)
- return pg.add_account_post_fetch (line, false);
- }
- cnt = 0;
- }
-}
-
-struct group *
-gr_ent::getgrent (void)
-{
- if (state == rewound)
- setent (true);
- else
- clear_cache ();
- return (struct group *) getent ();
-}
-
extern "C" void
-setgrent ()
+endgrent ()
{
- grent.setgrent ();
+ _my_tls.locals.grp_pos = 0;
}
extern "C" struct group *
-getgrent32 (void)
+getgrent32 ()
{
- return grent.getgrent ();
+ if (_my_tls.locals.grp_pos == 0)
+ gr.refresh (true);
+ if (_my_tls.locals.grp_pos < gr.curr_lines)
+ return group_buf + _my_tls.locals.grp_pos++;
+
+ return NULL;
}
#ifdef __x86_64__
@@ -465,85 +310,90 @@ getgrent ()
#endif
extern "C" void
-endgrent (void)
-{
- grent.endgrent ();
-}
-
-/* *_filtered functions are called from mkgroup */
-void *
-setgrent_filtered (int enums, PCWSTR enum_tdoms)
+setgrent ()
{
- gr_ent *gr = new gr_ent;
- if (gr)
- gr->setgrent (enums, enum_tdoms);
- return (void *) gr;
+ _my_tls.locals.grp_pos = 0;
}
-void *
-getgrent_filtered (void *gr)
+/* Internal function. ONLY USE THIS INTERNALLY, NEVER `getgrent'!!! */
+struct group *
+internal_getgrent (int pos)
{
- return (void *) ((gr_ent *) gr)->getgrent ();
-}
+ gr.refresh (false);
-void
-endgrent_filtered (void *gr)
-{
- ((gr_ent *) gr)->endgrent ();
+ if (pos < gr.curr_lines)
+ return group_buf + pos;
+ return NULL;
}
int
-internal_getgroups (int gidsetsize, gid_t *grouplist, cyg_ldap *pldap)
+internal_getgroups (int gidsetsize, gid_t *grouplist, cygpsid * srchsid)
{
NTSTATUS status;
- HANDLE tok;
+ HANDLE hToken = NULL;
ULONG size;
int cnt = 0;
- struct group *grp;
+ struct group *gr;
- if (cygheap->user.groups.issetgroups ())
+ if (!srchsid && cygheap->user.groups.issetgroups ())
{
- for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
- if ((grp = internal_getgrsid (cygheap->user.groups.sgsids.sids[pg],
- pldap)))
- {
- if (cnt < gidsetsize)
- grouplist[cnt] = grp->gr_gid;
- ++cnt;
- if (gidsetsize && cnt > gidsetsize)
- goto error;
- }
+ cygsid sid;
+ for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+ if (sid.getfromgr (gr))
+ for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
+ if (sid == cygheap->user.groups.sgsids.sids[pg]
+ && sid != well_known_world_sid)
+ {
+ if (cnt < gidsetsize)
+ grouplist[cnt] = gr->gr_gid;
+ ++cnt;
+ if (gidsetsize && cnt > gidsetsize)
+ goto error;
+ break;
+ }
return cnt;
}
+
/* If impersonated, use impersonation token. */
- tok = cygheap->user.issetuid () ? cygheap->user.primary_token () : hProcToken;
+ if (cygheap->user.issetuid ())
+ hToken = cygheap->user.primary_token ();
+ else
+ hToken = hProcToken;
- status = NtQueryInformationToken (tok, TokenGroups, NULL, 0, &size);
+ status = NtQueryInformationToken (hToken, TokenGroups, NULL, 0, &size);
if (NT_SUCCESS (status) || status == STATUS_BUFFER_TOO_SMALL)
{
PTOKEN_GROUPS groups = (PTOKEN_GROUPS) alloca (size);
- status = NtQueryInformationToken (tok, TokenGroups, groups, size, &size);
+ status = NtQueryInformationToken (hToken, TokenGroups, groups,
+ size, &size);
if (NT_SUCCESS (status))
{
- for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ cygsid sid;
+
+ if (srchsid)
{
- cygpsid sid = groups->Groups[pg].Sid;
- if ((grp = internal_getgrsid (sid, pldap)))
- {
- if ((groups->Groups[pg].Attributes
- & (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED))
+ for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ if ((cnt = (*srchsid == groups->Groups[pg].Sid)))
+ break;
+ }
+ else
+ for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+ if (sid.getfromgr (gr))
+ for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ if (sid == groups->Groups[pg].Sid
+ && (groups->Groups[pg].Attributes
+ & (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED))
&& sid != well_known_world_sid)
{
if (cnt < gidsetsize)
- grouplist[cnt] = grp->gr_gid;
+ grouplist[cnt] = gr->gr_gid;
++cnt;
if (gidsetsize && cnt > gidsetsize)
goto error;
+ break;
}
- }
- }
}
}
else
@@ -558,9 +408,7 @@ error:
extern "C" int
getgroups32 (int gidsetsize, gid_t *grouplist)
{
- cyg_ldap cldap;
-
- return internal_getgroups (gidsetsize, grouplist, &cldap);
+ return internal_getgroups (gidsetsize, grouplist);
}
#ifdef __x86_64__
@@ -579,7 +427,7 @@ getgroups (int gidsetsize, __gid16_t *grouplist)
if (gidsetsize > 0 && grouplist)
grouplist32 = (gid_t *) alloca (gidsetsize * sizeof (gid_t));
- int ret = getgroups32 (gidsetsize, grouplist32);
+ int ret = internal_getgroups (gidsetsize, grouplist32);
if (gidsetsize > 0 && grouplist)
for (int i = 0; i < ret; ++ i)
@@ -593,15 +441,13 @@ getgroups (int gidsetsize, __gid16_t *grouplist)
static void
get_groups (const char *user, gid_t gid, cygsidlist &gsids)
{
- cyg_ldap cldap;
-
cygheap->user.deimpersonate ();
- struct passwd *pw = internal_getpwnam (user, &cldap);
- struct group *grp = internal_getgrgid (gid, &cldap);
+ struct passwd *pw = internal_getpwnam (user);
+ struct group *gr = internal_getgrgid (gid);
cygsid usersid, grpsid;
if (usersid.getfrompw (pw))
get_server_groups (gsids, usersid, pw);
- if (gid != ILLEGAL_GID && grpsid.getfromgr (grp))
+ if (gid != ILLEGAL_GID && grpsid.getfromgr (gr))
gsids += grpsid;
cygheap->user.reimpersonate ();
}
@@ -636,8 +482,7 @@ getgrouplist (const char *user, gid_t gid, gid_t *groups, int *ngroups)
{
int ret = 0;
int cnt = 0;
- struct group *grp;
- cyg_ldap cldap;
+ struct group *gr;
/* Note that it's not defined if groups or ngroups may be NULL!
GLibc does not check the pointers on entry and just uses them.
@@ -650,10 +495,10 @@ getgrouplist (const char *user, gid_t gid, gid_t *groups, int *ngroups)
cygsidlist tmp_gsids (cygsidlist_auto, 12);
get_groups (user, gid, tmp_gsids);
for (int i = 0; i < tmp_gsids.count (); i++)
- if ((grp = internal_getgrsid (tmp_gsids.sids[i], &cldap)) != NULL)
+ if ((gr = internal_getgrsid (tmp_gsids.sids[i])) != NULL)
{
if (groups && cnt < *ngroups)
- groups[cnt] = grp->gr_gid;
+ groups[cnt] = gr->gr_gid;
++cnt;
}
if (cnt > *ngroups)
@@ -679,16 +524,15 @@ setgroups32 (int ngroups, const gid_t *grouplist)
}
cygsidlist gsids (cygsidlist_alloc, ngroups);
- struct group *grp;
- cyg_ldap cldap;
+ struct group *gr;
if (ngroups && !gsids.sids)
return -1;
for (int gidx = 0; gidx < ngroups; ++gidx)
{
- if ((grp = internal_getgrgid (grouplist[gidx], &cldap))
- && gsids.addfromgr (grp))
+ if ((gr = internal_getgrgid (grouplist[gidx]))
+ && gsids.addfromgr (gr))
continue;
debug_printf ("No sid found for gid %u", grouplist[gidx]);
gsids.free_sids ();
diff --git a/winsup/cygwin/import/rexec.c b/winsup/cygwin/import/rexec.c
deleted file mode 100644
index 4e01eb659..000000000
--- a/winsup/cygwin/import/rexec.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (c) 1980, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)rexec.c 8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <netdb.h>
-#include <errno.h>
-#include <ctype.h>
-#include <err.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-int rexecoptions;
-char *getpass(), *getlogin();
-
-/*
- * Options and other state info.
- */
-struct macel {
- char mac_name[9]; /* macro name */
- char *mac_start; /* start of macro in macbuf */
- char *mac_end; /* end of macro in macbuf */
-};
-
-int macnum; /* number of defined macros */
-struct macel macros[16];
-char macbuf[4096];
-
-static FILE *cfile;
-
-#define DEFAULT 1
-#define LOGIN 2
-#define PASSWD 3
-#define ACCOUNT 4
-#define MACDEF 5
-#define ID 10
-#define MACH 11
-
-static char tokval[100];
-
-static struct toktab {
- char *tokstr;
- int tval;
-} toktab[]= {
- { "default", DEFAULT },
- { "login", LOGIN },
- { "password", PASSWD },
- { "passwd", PASSWD },
- { "account", ACCOUNT },
- { "machine", MACH },
- { "macdef", MACDEF },
- { NULL, 0 }
-};
-
-static int
-token()
-{
- char *cp;
- int c;
- struct toktab *t;
-
- if (feof(cfile) || ferror(cfile))
- return (0);
- while ((c = getc(cfile)) != EOF &&
- (c == '\n' || c == '\t' || c == ' ' || c == ','))
- continue;
- if (c == EOF)
- return (0);
- cp = tokval;
- if (c == '"') {
- while ((c = getc(cfile)) != EOF && c != '"') {
- if (c == '\\')
- c = getc(cfile);
- *cp++ = c;
- }
- } else {
- *cp++ = c;
- while ((c = getc(cfile)) != EOF
- && c != '\n' && c != '\t' && c != ' ' && c != ',') {
- if (c == '\\')
- c = getc(cfile);
- *cp++ = c;
- }
- }
- *cp = 0;
- if (tokval[0] == 0)
- return (0);
- for (t = toktab; t->tokstr; t++)
- if (!strcmp(t->tokstr, tokval))
- return (t->tval);
- return (ID);
-}
-
-static int
-ruserpass(host, aname, apass, aacct)
- char *host, **aname, **apass, **aacct;
-{
- char *hdir, buf[BUFSIZ], *tmp;
- char myname[MAXHOSTNAMELEN], *mydomain;
- int t, i, c, usedefault = 0;
- struct stat stb;
-
- hdir = getenv("HOME");
- if (hdir == NULL)
- hdir = ".";
- if (strlen(hdir) + 8 > sizeof(buf))
- return (0);
- (void) sprintf(buf, "%s/.netrc", hdir);
- cfile = fopen(buf, "r");
- if (cfile == NULL) {
- if (errno != ENOENT)
- warn("%s", buf);
- return (0);
- }
- if (gethostname(myname, sizeof(myname)) < 0)
- myname[0] = '\0';
- if ((mydomain = strchr(myname, '.')) == NULL)
- mydomain = "";
-next:
- while ((t = token())) switch(t) {
-
- case DEFAULT:
- usedefault = 1;
- /* FALL THROUGH */
-
- case MACH:
- if (!usedefault) {
- if (token() != ID)
- continue;
- /*
- * Allow match either for user's input host name
- * or official hostname. Also allow match of
- * incompletely-specified host in local domain.
- */
- if (strcasecmp(host, tokval) == 0)
- goto match;
- if ((tmp = strchr(host, '.')) != NULL &&
- strcasecmp(tmp, mydomain) == 0 &&
- strncasecmp(host, tokval, tmp - host) == 0 &&
- tokval[tmp - host] == '\0')
- goto match;
- continue;
- }
- match:
- while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
-
- case LOGIN:
- if (token())
- if (*aname == 0) {
- *aname = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*aname, tokval);
- } else {
- if (strcmp(*aname, tokval))
- goto next;
- }
- break;
- case PASSWD:
- if ((*aname == 0 || strcmp(*aname, "anonymous")) &&
- fstat(fileno(cfile), &stb) >= 0 &&
- (stb.st_mode & 077) != 0) {
- warnx("Error: .netrc file is readable by others.");
- warnx("Remove password or make file unreadable by others.");
- goto bad;
- }
- if (token() && *apass == 0) {
- *apass = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*apass, tokval);
- }
- break;
- case ACCOUNT:
- if (fstat(fileno(cfile), &stb) >= 0
- && (stb.st_mode & 077) != 0) {
- warnx("Error: .netrc file is readable by others.");
- warnx("Remove account or make file unreadable by others.");
- goto bad;
- }
- if (token() && *aacct == 0) {
- *aacct = malloc((unsigned) strlen(tokval) + 1);
- (void) strcpy(*aacct, tokval);
- }
- break;
- case MACDEF:
- while ((c=getc(cfile)) != EOF &&
- (c == ' ' || c == '\t'))
- ;
- if (c == EOF || c == '\n') {
- printf("Missing macdef name argument.\n");
- goto bad;
- }
- if (macnum == 16) {
- printf("Limit of 16 macros have already been defined\n");
- goto bad;
- }
- tmp = macros[macnum].mac_name;
- *tmp++ = c;
- for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
- !isspace(c); ++i) {
- *tmp++ = c;
- }
- if (c == EOF) {
- printf("Macro definition missing null line terminator.\n");
- goto bad;
- }
- *tmp = '\0';
- if (c != '\n') {
- while ((c=getc(cfile)) != EOF && c != '\n');
- }
- if (c == EOF) {
- printf("Macro definition missing null line terminator.\n");
- goto bad;
- }
- if (macnum == 0) {
- macros[macnum].mac_start = macbuf;
- }
- else {
- macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
- }
- tmp = macros[macnum].mac_start;
- while (tmp != macbuf + 4096) {
- if ((c=getc(cfile)) == EOF) {
- printf("Macro definition missing null line terminator.\n");
- goto bad;
- }
- *tmp = c;
- if (*tmp == '\n') {
- if (*(tmp-1) == '\0') {
- macros[macnum++].mac_end = tmp - 1;
- break;
- }
- *tmp = '\0';
- }
- tmp++;
- }
- if (tmp == macbuf + 4096) {
- printf("4K macro buffer exceeded\n");
- goto bad;
- }
- break;
- default:
- warnx("Unknown .netrc keyword %s", tokval);
- break;
- }
- goto done;
- }
-done:
- (void) fclose(cfile);
- return (0);
-bad:
- (void) fclose(cfile);
- return (-1);
-}
-
-int
-rexec(ahost, rport, name, pass, cmd, fd2p)
- char **ahost;
- int rport;
- char *name, *pass, *cmd;
- int *fd2p;
-{
- struct sockaddr_in sin, sin2, from;
- struct hostent *hp;
- u_short port;
- int s, timo = 1, s3;
- char c, *acct;
-
- hp = gethostbyname(*ahost);
- if (hp == 0) {
- herror(*ahost);
- return (-1);
- }
- *ahost = hp->h_name;
- acct = NULL;
- ruserpass(hp->h_name, &name, &pass, &acct);
- free(acct);
-retry:
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0) {
- perror("rexec: socket");
- return (-1);
- }
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = rport;
- bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- if (errno == ECONNREFUSED && timo <= 16) {
- (void) close(s);
- sleep(timo);
- timo *= 2;
- goto retry;
- }
- perror(hp->h_name);
- return (-1);
- }
- if (fd2p == 0) {
- (void) write(s, "", 1);
- port = 0;
- } else {
- char num[8];
- int s2, sin2len;
-
- s2 = socket(AF_INET, SOCK_STREAM, 0);
- if (s2 < 0) {
- (void) close(s);
- return (-1);
- }
- listen(s2, 1);
- sin2len = sizeof (sin2);
- if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 ||
- sin2len != sizeof (sin2)) {
- perror("getsockname");
- (void) close(s2);
- goto bad;
- }
- port = ntohs((u_short)sin2.sin_port);
- (void) sprintf(num, "%u", port);
- (void) write(s, num, strlen(num)+1);
- { int len = sizeof (from);
- s3 = accept(s2, (struct sockaddr *)&from, &len);
- close(s2);
- if (s3 < 0) {
- perror("accept");
- port = 0;
- goto bad;
- }
- }
- *fd2p = s3;
- }
- (void) write(s, name, strlen(name) + 1);
- /* should public key encypt the password here */
- (void) write(s, pass, strlen(pass) + 1);
- (void) write(s, cmd, strlen(cmd) + 1);
- if (read(s, &c, 1) != 1) {
- perror(*ahost);
- goto bad;
- }
- if (c != 0) {
- while (read(s, &c, 1) == 1) {
- (void) write(2, &c, 1);
- if (c == '\n')
- break;
- }
- goto bad;
- }
- return (s);
-bad:
- if (port)
- (void) close(*fd2p);
- (void) close(s);
- return (-1);
-}
diff --git a/winsup/cygwin/include/cygwin/acl.h b/winsup/cygwin/include/cygwin/acl.h
index 8fa5a65a5..9a62e325e 100644
--- a/winsup/cygwin/include/cygwin/acl.h
+++ b/winsup/cygwin/include/cygwin/acl.h
@@ -1,6 +1,6 @@
/* cygwin/acl.h header file for Cygwin.
- Copyright 1999, 2000, 2001, 2002, 2010, 2014 Red Hat, Inc.
+ Copyright 1999, 2000, 2001, 2002, 2010 Red Hat, Inc.
Written by C. Vinschen.
This file is part of Cygwin.
@@ -25,7 +25,7 @@ extern "C" {
#define GETACL (0x1)
#define GETACLCNT (0x2)
-#define MIN_ACL_ENTRIES (3) // minimal acl entries from GETACLCNT
+#define MIN_ACL_ENTRIES (4) // minimal acl entries from GETACLCNT
#define MAX_ACL_ENTRIES (256) // max entries of each type
// Return values of aclcheck(3) in case of error */
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index e1ac2cee9..6c46a0b43 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -448,9 +448,8 @@ details. */
272: Export tm_gmtoff and tm_zone members.
273: Skipped.
274: Export __cxa_atexit and __cxa_finalize.
- 275: Introduce account mapping from Windows account DBs. Add CW_SETENT,
- CW_GETENT, CW_ENDENT, CW_GETNSSSEP, CW_GETPWSID, CW_GETGRSID,
- CW_CYGNAME_FROM_WINNAME.
+ 275: Add CW_SETENT, CW_GETENT, CW_ENDENT, CW_GETNSSSEP, CW_GETPWSID,
+ CW_GETGRSID, CW_CYGNAME_FROM_WINNAME as no-ops for forward compat.
276: Export ffsl, ffsll.
277: Add setsockopt(SO_PEERCRED).
278: Add quotactl.
diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h
index 7f40475e8..6dbf2d322 100644
--- a/winsup/cygwin/include/sys/cygwin.h
+++ b/winsup/cygwin/include/sys/cygwin.h
@@ -218,20 +218,6 @@ enum
CW_TOKEN_RESTRICTED = 1
};
-/* Enumeration source constants for CW_SETENT called from mkpasswd/mkgroup. */
-enum nss_enum_t
-{
- ENUM_NONE = 0x00,
- ENUM_CACHE = 0x01,
- ENUM_FILES = 0x02,
- ENUM_BUILTIN = 0x04,
- ENUM_LOCAL = 0x08,
- ENUM_PRIMARY = 0x10,
- ENUM_TDOMS = 0x20,
- ENUM_TDOMS_ALL = 0x40,
- ENUM_ALL = 0x7f
-};
-
#define CW_NEXTPID 0x80000000 /* or with pid to get next one */
uintptr_t cygwin_internal (cygwin_getinfo_types, ...);
diff --git a/winsup/cygwin/ldap.cc b/winsup/cygwin/ldap.cc
deleted file mode 100644
index df7756809..000000000
--- a/winsup/cygwin/ldap.cc
+++ /dev/null
@@ -1,629 +0,0 @@
-/* ldap.cc: Helper functions for ldap access to Active Directory.
-
- Copyright 2014 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 "ldap.h"
-#include "cygerrno.h"
-#include "security.h"
-#include "path.h"
-#include "fhandler.h"
-#include "dtable.h"
-#include "cygheap.h"
-#include "registry.h"
-#include "pinfo.h"
-#include "lm.h"
-#include "dsgetdc.h"
-#include "tls_pbuf.h"
-
-#define CYG_LDAP_ENUM_PAGESIZE 100 /* entries per page */
-
-static PWCHAR rootdse_attr[] =
-{
- (PWCHAR) L"defaultNamingContext",
- (PWCHAR) L"supportedCapabilities",
- NULL
-};
-
-static PWCHAR user_attr[] =
-{
- (PWCHAR) L"primaryGroupID",
- (PWCHAR) L"gecos",
- (PWCHAR) L"unixHomeDirectory",
- (PWCHAR) L"loginShell",
- (PWCHAR) L"uidNumber",
- NULL
-};
-
-static PWCHAR group_attr[] =
-{
- (PWCHAR) L"cn",
- (PWCHAR) L"gidNumber",
- NULL
-};
-
-PWCHAR tdom_attr[] =
-{
- (PWCHAR) L"trustPosixOffset",
- NULL
-};
-
-PWCHAR sid_attr[] =
-{
- (PWCHAR) L"objectSid",
- NULL
-};
-
-PWCHAR rfc2307_uid_attr[] =
-{
- (PWCHAR) L"uid",
- NULL
-};
-
-PWCHAR rfc2307_gid_attr[] =
-{
- (PWCHAR) L"cn",
- NULL
-};
-
-/* ================================================================= */
-/* Helper methods. */
-/* ================================================================= */
-
-inline int
-cyg_ldap::map_ldaperr_to_errno (ULONG lerr)
-{
- switch (lerr)
- {
- case LDAP_SUCCESS:
- return NO_ERROR;
- case LDAP_NO_RESULTS_RETURNED:
- /* LdapMapErrorToWin32 maps LDAP_NO_RESULTS_RETURNED to ERROR_MORE_DATA,
- which in turn is mapped to EMSGSIZE by geterrno_from_win_error. This
- is SO wrong, especially considering that LDAP_MORE_RESULTS_TO_RETURN
- is mapped to ERROR_MORE_DATA as well :-P */
- return ENMFILE;
- default:
- break;
- }
- return geterrno_from_win_error (LdapMapErrorToWin32 (lerr));
-}
-
-inline int
-cyg_ldap::wait (cygthread *thr)
-{
- if (!thr)
- return EIO;
- if (cygwait (*thr, INFINITE, cw_sig | cw_sig_eintr) != WAIT_OBJECT_0)
- {
- thr->terminate_thread ();
- _my_tls.call_signal_handler ();
- return EINTR;
- }
- thr->detach ();
- return 0;
-}
-
-/* ================================================================= */
-/* Helper struct and functions for interruptible LDAP initalization. */
-/* ================================================================= */
-
-struct cyg_ldap_init {
- cyg_ldap *that;
- PCWSTR domain;
- bool ssl;
- ULONG ret;
-};
-
-ULONG
-cyg_ldap::connect_ssl (PCWSTR domain)
-{
- ULONG ret;
-
- if (!(lh = ldap_sslinitW ((PWCHAR) domain, LDAP_SSL_PORT, 1)))
- {
- debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ());
- return LdapGetLastError ();
- }
- if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS)
- debug_printf ("ldap_bind(%W) 0x%02x", domain, ret);
- else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE,
- (PWCHAR) L"(objectclass=*)", rootdse_attr,
- 0, &msg))
- != LDAP_SUCCESS)
- debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret);
- return ret;
-}
-
-ULONG
-cyg_ldap::connect_non_ssl (PCWSTR domain)
-{
- ULONG ret;
-
- if (!(lh = ldap_initW ((PWCHAR) domain, LDAP_PORT)))
- {
- debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ());
- return LdapGetLastError ();
- }
- if ((ret = ldap_set_option (lh, LDAP_OPT_SIGN, LDAP_OPT_ON))
- != LDAP_SUCCESS)
- debug_printf ("ldap_set_option(LDAP_OPT_SIGN) error 0x%02x", ret);
- if ((ret = ldap_set_option (lh, LDAP_OPT_ENCRYPT, LDAP_OPT_ON))
- != LDAP_SUCCESS)
- debug_printf ("ldap_set_option(LDAP_OPT_ENCRYPT) error 0x%02x", ret);
- if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS)
- debug_printf ("ldap_bind(%W) 0x%02x", domain, ret);
- else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE,
- (PWCHAR) L"(objectclass=*)", rootdse_attr,
- 0, &msg))
- != LDAP_SUCCESS)
- debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret);
- return ret;
-}
-
-static DWORD WINAPI
-ldap_init_thr (LPVOID param)
-{
- cyg_ldap_init *cl = (cyg_ldap_init *) param;
- cl->ret = cl->ssl ? cl->that->connect_ssl (cl->domain)
- : cl->that->connect_non_ssl (cl->domain);
- return 0;
-}
-
-inline int
-cyg_ldap::connect (PCWSTR domain)
-{
- /* FIXME? connect_ssl can take ages even when failing, so we're trying to
- do everything the non-SSL (but still encrypted) way. */
- cyg_ldap_init cl = { this, domain, false, NO_ERROR };
- cygthread *thr = new cygthread (ldap_init_thr, &cl, "ldap_init");
- return wait (thr) ?: map_ldaperr_to_errno (cl.ret);
-}
-
-/* ================================================================= */
-/* Helper struct and functions for interruptible LDAP search. */
-/* ================================================================= */
-
-struct cyg_ldap_search {
- cyg_ldap *that;
- PWCHAR base;
- PWCHAR filter;
- PWCHAR *attrs;
- ULONG ret;
-};
-
-ULONG
-cyg_ldap::search_s (PWCHAR base, PWCHAR filter, PWCHAR *attrs)
-{
- ULONG ret;
-
- if ((ret = ldap_search_sW (lh, base, LDAP_SCOPE_SUBTREE, filter,
- attrs, 0, &msg)) != LDAP_SUCCESS)
- debug_printf ("ldap_search_sW(%W,%W) error 0x%02x", base, filter, ret);
- return ret;
-}
-
-static DWORD WINAPI
-ldap_search_thr (LPVOID param)
-{
- cyg_ldap_search *cl = (cyg_ldap_search *) param;
- cl->ret = cl->that->search_s (cl->base, cl->filter, cl->attrs);
- return 0;
-}
-
-inline int
-cyg_ldap::search (PWCHAR base, PWCHAR filter, PWCHAR *attrs)
-{
- cyg_ldap_search cl = { this, base, filter, attrs, NO_ERROR };
- cygthread *thr = new cygthread (ldap_search_thr, &cl, "ldap_search");
- return wait (thr) ?: map_ldaperr_to_errno (cl.ret);
-}
-
-/* ================================================================= */
-/* Helper struct and functions for interruptible LDAP page search. */
-/* ================================================================= */
-
-struct cyg_ldap_next_page {
- cyg_ldap *that;
- ULONG ret;
-};
-
-ULONG
-cyg_ldap::next_page_s ()
-{
- ULONG total;
- ULONG ret;
-
- do
- {
- ret = ldap_get_next_page_s (lh, srch_id, NULL, CYG_LDAP_ENUM_PAGESIZE,
- &total, &srch_msg);
- }
- while (ret == LDAP_SUCCESS && ldap_count_entries (lh, srch_msg) == 0);
- if (ret && ret != LDAP_NO_RESULTS_RETURNED)
- debug_printf ("ldap_result() error 0x%02x", ret);
- return ret;
-}
-
-static DWORD WINAPI
-ldap_next_page_thr (LPVOID param)
-{
- cyg_ldap_next_page *cl = (cyg_ldap_next_page *) param;
- cl->ret = cl->that->next_page_s ();
- return 0;
-}
-
-inline int
-cyg_ldap::next_page ()
-{
- cyg_ldap_next_page cl = { this, NO_ERROR };
- cygthread *thr = new cygthread (ldap_next_page_thr, &cl, "ldap_next_page");
- return wait (thr) ?: map_ldaperr_to_errno (cl.ret);
-}
-
-/* ================================================================= */
-/* Public methods. */
-/* ================================================================= */
-
-int
-cyg_ldap::open (PCWSTR domain)
-{
- int ret = 0;
-
- /* Already open? */
- if (lh)
- return 0;
-
- if ((ret = connect (domain)) != NO_ERROR)
- goto err;
- /* Prime `ret' and fetch ROOTDSE search result. */
- ret = EIO;
- if (!(entry = ldap_first_entry (lh, msg)))
- {
- debug_printf ("No ROOTDSE entry for %W", domain);
- goto err;
- }
- if (!(val = ldap_get_valuesW (lh, entry, rootdse_attr[0])))
- {
- debug_printf ("No ROOTDSE value for %W", domain);
- goto err;
- }
- if (!(rootdse = wcsdup (val[0])))
- {
- debug_printf ("wcsdup(%W, ROOTDSE) %d", domain, get_errno ());
- goto err;
- }
- ldap_value_freeW (val);
- if ((val = ldap_get_valuesW (lh, entry, rootdse_attr[1])))
- {
- for (ULONG idx = 0; idx < ldap_count_valuesW (val); ++idx)
- if (!wcscmp (val[idx], LDAP_CAP_ACTIVE_DIRECTORY_OID_W))
- {
- isAD = true;
- break;
- }
- }
- ldap_value_freeW (val);
- val = NULL;
- ldap_msgfree (msg);
- msg = entry = NULL;
- return 0;
-err:
- close ();
- return ret;
-}
-
-void
-cyg_ldap::close ()
-{
- if (srch_id != NULL)
- ldap_search_abandon_page (lh, srch_id);
- if (lh)
- ldap_unbind (lh);
- if (srch_msg)
- ldap_msgfree (srch_msg);
- if (msg)
- ldap_msgfree (msg);
- if (val)
- ldap_value_freeW (val);
- if (rootdse)
- free (rootdse);
- lh = NULL;
- msg = entry = NULL;
- val = NULL;
- rootdse = NULL;
- srch_id = NULL;
- srch_msg = srch_entry = NULL;
-}
-
-bool
-cyg_ldap::fetch_ad_account (PSID sid, bool group, PCWSTR domain)
-{
- WCHAR filter[140], *f, *rdse = rootdse;
- LONG len = (LONG) RtlLengthSid (sid);
- PBYTE s = (PBYTE) sid;
- static WCHAR hex_wchars[] = L"0123456789abcdef";
- tmp_pathbuf tp;
-
- if (msg)
- {
- ldap_msgfree (msg);
- msg = entry = NULL;
- }
- if (val)
- {
- ldap_value_freeW (val);
- val = NULL;
- }
- f = wcpcpy (filter, L"(objectSid=");
- while (len-- > 0)
- {
- *f++ = L'\\';
- *f++ = hex_wchars[*s >> 4];
- *f++ = hex_wchars[*s++ & 0xf];
- }
- wcpcpy (f, L")");
- if (domain)
- {
- /* FIXME: This is a hack. The most correct solution is probably to
- open a connection to the DC of the trusted domain. But this always
- takes extra time, so we're trying to avoid it. If this results in
- problems, we know what to do. */
- rdse = tp.w_get ();
- PWCHAR r = rdse;
- for (PWCHAR dotp = (PWCHAR) domain; dotp && *dotp; domain = dotp)
- {
- dotp = wcschr (domain, L'.');
- if (dotp)
- *dotp++ = L'\0';
- if (r > rdse)
- *r++ = L',';
- r = wcpcpy (r, L"DC=");
- r = wcpcpy (r, domain);
- }
- }
- attr = group ? group_attr : user_attr;
- if (search (rdse, filter, attr) != 0)
- return false;
- if (!(entry = ldap_first_entry (lh, msg)))
- {
- debug_printf ("No entry for %W in rootdse %W", filter, rdse);
- return false;
- }
- return true;
-}
-
-int
-cyg_ldap::enumerate_ad_accounts (PCWSTR domain, bool group)
-{
- int ret;
- tmp_pathbuf tp;
- PCWSTR filter;
-
- close ();
- if ((ret = open (domain)) != NO_ERROR)
- return ret;
-
- if (!group)
- filter = L"(&(objectClass=User)"
- "(objectCategory=Person)"
- /* 512 == ADS_UF_NORMAL_ACCOUNT */
- "(userAccountControl:" LDAP_MATCHING_RULE_BIT_AND ":=512)"
- "(objectSid=*))";
- else if (!domain)
- filter = L"(&(objectClass=Group)"
- "(objectSid=*))";
- else
- filter = L"(&(objectClass=Group)"
- /* 1 == ACCOUNT_GROUP */
- "(!(groupType:" LDAP_MATCHING_RULE_BIT_AND ":=1))"
- "(objectSid=*))";
- srch_id = ldap_search_init_pageW (lh, rootdse, LDAP_SCOPE_SUBTREE,
- (PWCHAR) filter, sid_attr, 0, NULL, NULL,
- INFINITE, CYG_LDAP_ENUM_PAGESIZE, NULL);
- if (srch_id == NULL)
- {
- debug_printf ("ldap_search_init_pageW(%W,%W) error 0x%02x",
- rootdse, filter, LdapGetLastError ());
- return map_ldaperr_to_errno (LdapGetLastError ());
- }
- return NO_ERROR;
-}
-
-int
-cyg_ldap::next_account (cygsid &sid)
-{
- ULONG ret;
- PLDAP_BERVAL *bval;
-
- if (srch_entry)
- {
- if ((srch_entry = ldap_next_entry (lh, srch_entry))
- && (bval = ldap_get_values_lenW (lh, srch_entry, sid_attr[0])))
- {
- sid = (PSID) bval[0]->bv_val;
- ldap_value_free_len (bval);
- return NO_ERROR;
- }
- ldap_msgfree (srch_msg);
- srch_msg = srch_entry = NULL;
- }
- ret = next_page ();
- if (ret == NO_ERROR)
- {
- if ((srch_entry = ldap_first_entry (lh, srch_msg))
- && (bval = ldap_get_values_lenW (lh, srch_entry, sid_attr[0])))
- {
- sid = (PSID) bval[0]->bv_val;
- ldap_value_free_len (bval);
- return NO_ERROR;
- }
- ret = EIO;
- }
- ldap_search_abandon_page (lh, srch_id);
- srch_id = NULL;
- return ret;
-}
-
-/* Return UINT32_MAX on error to allow differing between not being able
- to fetch a value and a real 0 offset. */
-uint32_t
-cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain)
-{
- WCHAR filter[300];
-
- if (msg)
- {
- ldap_msgfree (msg);
- msg = entry = NULL;
- }
- if (val)
- {
- ldap_value_freeW (val);
- val = NULL;
- }
- /* If domain name has no dot, it's a Netbios name. In that case, filter
- by flatName rather than by name. */
- __small_swprintf (filter, L"(&(objectClass=trustedDomain)(%W=%W))",
- wcschr (domain, L'.') ? L"name" : L"flatName", domain);
- if (search (rootdse, filter, attr = tdom_attr) != 0)
- return UINT32_MAX;
- if (!(entry = ldap_first_entry (lh, msg)))
- {
- debug_printf ("No entry for %W in rootdse %W", filter, rootdse);
- return UINT32_MAX;
- }
- return get_num_attribute (0);
-}
-
-PWCHAR
-cyg_ldap::get_string_attribute (int idx)
-{
- if (val)
- ldap_value_freeW (val);
- val = ldap_get_valuesW (lh, entry, attr[idx]);
- if (val)
- return val[0];
- return NULL;
-}
-
-uint32_t
-cyg_ldap::get_num_attribute (int idx)
-{
- PWCHAR ret = get_string_attribute (idx);
- if (ret)
- return (uint32_t) wcstoul (ret, NULL, 10);
- return (uint32_t) -1;
-}
-
-bool
-cyg_ldap::fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group)
-{
- WCHAR filter[48];
- PLDAP_BERVAL *bval;
-
- if (msg)
- {
- ldap_msgfree (msg);
- msg = entry = NULL;
- }
- if (group)
- __small_swprintf (filter, L"(&(objectClass=Group)(gidNumber=%u))", id);
- else
- __small_swprintf (filter, L"(&(objectClass=User)(uidNumber=%u))", id);
- if (search (rootdse, filter, sid_attr) != 0)
- return false;
- if ((entry = ldap_first_entry (lh, msg))
- && (bval = ldap_get_values_lenW (lh, entry, sid_attr[0])))
- {
- sid = (PSID) bval[0]->bv_val;
- ldap_value_free_len (bval);
- return true;
- }
- return false;
-}
-
-PWCHAR
-cyg_ldap::fetch_unix_name_from_rfc2307 (uint32_t id, bool group)
-{
- WCHAR filter[52];
-
- if (msg)
- {
- ldap_msgfree (msg);
- msg = entry = NULL;
- }
- if (val)
- {
- ldap_value_freeW (val);
- val = NULL;
- }
- attr = group ? rfc2307_gid_attr : rfc2307_uid_attr;
- if (group)
- __small_swprintf (filter, L"(&(objectClass=posixGroup)(gidNumber=%u))", id);
- else
- __small_swprintf (filter, L"(&(objectClass=posixAccount)(uidNumber=%u))",
- id);
- if (search (rootdse, filter, attr) != 0)
- return NULL;
- if (!(entry = ldap_first_entry (lh, msg)))
- {
- debug_printf ("No entry for %W in rootdse %W", filter, rootdse);
- return NULL;
- }
- return get_string_attribute (0);
-}
-
-uid_t
-cyg_ldap::remap_uid (uid_t uid)
-{
- cygsid user (NO_SID);
- PWCHAR name;
- struct passwd *pw;
-
- if (isAD)
- {
- if (fetch_unix_sid_from_ad (uid, user, false)
- && user != NO_SID
- && (pw = internal_getpwsid (user, this)))
- return pw->pw_uid;
- }
- else if ((name = fetch_unix_name_from_rfc2307 (uid, false)))
- {
- char *mbname = NULL;
- sys_wcstombs_alloc (&mbname, HEAP_NOTHEAP, name);
- if ((pw = internal_getpwnam (mbname)))
- return pw->pw_uid;
- }
- return ILLEGAL_UID;
-}
-
-gid_t
-cyg_ldap::remap_gid (gid_t gid)
-{
- cygsid group (NO_SID);
- PWCHAR name;
- struct group *gr;
-
- if (isAD)
- {
- if (fetch_unix_sid_from_ad (gid, group, true)
- && group != NO_SID
- && (gr = internal_getgrsid (group, this)))
- return gr->gr_gid;
- }
- else if ((name = fetch_unix_name_from_rfc2307 (gid, true)))
- {
- char *mbname = NULL;
- sys_wcstombs_alloc (&mbname, HEAP_NOTHEAP, name);
- if ((gr = internal_getgrnam (mbname)))
- return gr->gr_gid;
- }
- return ILLEGAL_GID;
-}
diff --git a/winsup/cygwin/ldap.h b/winsup/cygwin/ldap.h
deleted file mode 100644
index 7f90a3821..000000000
--- a/winsup/cygwin/ldap.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* ldap.h.
-
- Copyright 2014 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. */
-
-#pragma once
-
-#pragma push_macro ("DECLSPEC_IMPORT")
-#undef DECLSPEC_IMPORT
-#define DECLSPEC_IMPORT
-#include <winldap.h>
-#include <ntldap.h>
-#pragma pop_macro ("DECLSPEC_IMPORT")
-
-#define LDAP_USER_PGRP_ATTR 0
-#define LDAP_USER_GECOS_ATTR 1
-#define LDAP_USER_HOME_ATTR 2
-#define LDAP_USER_SHELL_ATTR 3
-#define LDAP_USER_UID_ATTR 4
-
-#define LDAP_GROUP_NAME_ATTR 0
-#define LDAP_GROUP_GID_ATTR 1
-
-class cyg_ldap {
- PLDAP lh;
- PWCHAR rootdse;
- PLDAPMessage msg, entry;
- PWCHAR *val;
- PWCHAR *attr;
- bool isAD;
- PLDAPSearch srch_id;
- PLDAPMessage srch_msg, srch_entry;
-
- inline int map_ldaperr_to_errno (ULONG lerr);
- inline int wait (cygthread *thr);
- inline int connect (PCWSTR domain);
- inline int search (PWCHAR base, PWCHAR filter, PWCHAR *attrs);
- inline int next_page ();
- bool fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group);
- PWCHAR fetch_unix_name_from_rfc2307 (uint32_t id, bool group);
- PWCHAR get_string_attribute (int idx);
- uint32_t get_num_attribute (int idx);
-
-public:
- cyg_ldap () : lh (NULL), rootdse (NULL), msg (NULL), entry (NULL), val (NULL),
- isAD (false), srch_id (NULL), srch_msg (NULL), srch_entry (NULL)
- {}
- ~cyg_ldap () { close (); }
-
- ULONG connect_ssl (PCWSTR domain);
- ULONG connect_non_ssl (PCWSTR domain);
- ULONG search_s (PWCHAR base, PWCHAR filter, PWCHAR *attrs);
- ULONG next_page_s ();
-
- operator PLDAP () const { return lh; }
- int open (PCWSTR in_domain);
- void close ();
- bool fetch_ad_account (PSID sid, bool group, PCWSTR domain = NULL);
- int enumerate_ad_accounts (PCWSTR domain, bool group);
- int next_account (cygsid &sid);
- uint32_t fetch_posix_offset_for_domain (PCWSTR domain);
- uid_t remap_uid (uid_t uid);
- gid_t remap_gid (gid_t gid);
- /* User only */
- gid_t get_primary_gid () { return get_num_attribute (LDAP_USER_PGRP_ATTR); }
- PWCHAR get_gecos () { return get_string_attribute (LDAP_USER_GECOS_ATTR); }
- PWCHAR get_home ()
- { return get_string_attribute (LDAP_USER_HOME_ATTR); }
- PWCHAR get_shell () { return get_string_attribute (LDAP_USER_SHELL_ATTR); }
- gid_t get_unix_uid () { return get_num_attribute (LDAP_USER_UID_ATTR); }
- /* group only */
- PWCHAR get_group_name ()
- { return get_string_attribute (LDAP_GROUP_NAME_ATTR); }
- gid_t get_unix_gid () { return get_num_attribute (LDAP_GROUP_GID_ATTR); }
-};
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index eee47a53a..3787853d5 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -387,82 +387,6 @@ WritePipeOverlapped (HANDLE h, LPCVOID buf, DWORD len, LPDWORD ret_len,
return ret;
}
-bool
-NT_readline::init (POBJECT_ATTRIBUTES attr, PCHAR in_buf, ULONG in_buflen)
-{
- NTSTATUS status;
- IO_STATUS_BLOCK io;
-
- status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, attr, &io,
- FILE_SHARE_VALID_FLAGS,
- FILE_SYNCHRONOUS_IO_NONALERT
- | FILE_OPEN_FOR_BACKUP_INTENT);
- if (!NT_SUCCESS (status))
- {
- paranoid_printf ("NtOpenFile(%S) failed, status %y",
- attr->ObjectName, status);
- return false;
- }
- buf = in_buf;
- buflen = in_buflen;
- got = end = buf;
- len = 0;
- line = 1;
- return true;
-}
-
-PCHAR
-NT_readline::gets ()
-{
- IO_STATUS_BLOCK io;
-
- while (true)
- {
- /* len == 0 indicates we have to read from the file. */
- if (!len)
- {
- if (!NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got,
- (buflen - 2) - (got - buf), NULL, NULL)))
- return NULL;
- len = io.Information;
- /* Set end marker. */
- got[len] = got[len + 1] = '\0';
- /* Set len to the absolute len of bytes in buf. */
- len += got - buf;
- /* Reset got to start reading at the start of the buffer again. */
- got = end = buf;
- }
- else
- {
- got = end + 1;
- ++line;
- }
- /* Still some valid full line? */
- if (got < buf + len)
- {
- if ((end = strchr (got, '\n')))
- {
- end[end[-1] == '\r' ? -1 : 0] = '\0';
- return got;
- }
- /* Last line missing a \n at EOF? */
- if (len < buflen - 2)
- {
- len = 0;
- return got;
- }
- }
- /* We have to read once more. Move remaining bytes to the start of
- the buffer and reposition got so that it points to the end of
- the remaining bytes. */
- len = buf + len - got;
- memmove (buf, got, len);
- got = buf + len;
- buf[len] = buf[len + 1] = '\0';
- len = 0;
- }
-}
-
/* backslashify: Convert all forward slashes in src path to back slashes
in dst path. Add a trailing slash to dst when trailing_slash_p arg
is set to 1. */
diff --git a/winsup/cygwin/miscfuncs.h b/winsup/cygwin/miscfuncs.h
index e42940c1a..bc36a1987 100644
--- a/winsup/cygwin/miscfuncs.h
+++ b/winsup/cygwin/miscfuncs.h
@@ -1,7 +1,7 @@
/* miscfuncs.h: main Cygwin header file.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -23,25 +23,6 @@ BOOL WINAPI ReadPipeOverlapped (HANDLE h, PVOID buf, DWORD len,
BOOL WINAPI WritePipeOverlapped (HANDLE h, LPCVOID buf, DWORD len,
LPDWORD ret_len, DWORD timeout);
-/* class for per-line reading using native functions. The caller provides
- the file as an POBJECT_ATTRIBUTES, and the buffer space. */
-class NT_readline
-{
- HANDLE fh;
- PCHAR buf;
- PCHAR got;
- PCHAR end;
- ULONG buflen;
- ULONG len;
- ULONG line;
-public:
- NT_readline () : fh (NULL) {}
- bool init (POBJECT_ATTRIBUTES attr, char *buf, ULONG buflen);
- PCHAR gets ();
- void close () { if (fh) NtClose (fh); fh = NULL; }
- ~NT_readline () { close (); }
-};
-
extern "C" void yield ();
#define import_address(x) __import_address ((void *)(x))
diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc
index 94e305489..2d8d38a15 100644
--- a/winsup/cygwin/mount.cc
+++ b/winsup/cygwin/mount.cc
@@ -1177,9 +1177,10 @@ mount_info::from_fstab (bool user, WCHAR fstab[], PWCHAR fstab_end)
{
UNICODE_STRING upath;
OBJECT_ATTRIBUTES attr;
- NT_readline rl;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE fh;
tmp_pathbuf tp;
- char *buf = tp.c_get ();
if (user)
{
@@ -1194,10 +1195,81 @@ mount_info::from_fstab (bool user, WCHAR fstab[], PWCHAR fstab_end)
RtlInitUnicodeString (&upath, fstab);
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
debug_printf ("Try to read mounts from %W", fstab);
- if (rl.init (&attr, buf, NT_MAX_PATH))
- while ((buf = rl.gets ()))
- if (!from_fstab_line (buf, user))
+ status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS (status))
+ {
+ debug_printf ("NtOpenFile(%S) failed, %y", &upath, status);
+ return false;
+ }
+
+ char *buf = tp.c_get ();
+ char *got = buf;
+ DWORD len = 0;
+ unsigned line = 1;
+ /* Using buffer size - 2 leaves space to append two \0. */
+ while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got,
+ (NT_MAX_PATH - 2) - (got - buf), NULL, NULL)))
+ {
+ char *end;
+
+ len = io.Information;
+ /* Set end marker. */
+ got[len] = got[len + 1] = '\0';
+ /* Set len to the absolute len of bytes in buf. */
+ len += got - buf;
+ /* Reset got to start reading at the start of the buffer again. */
+ got = buf;
+retry:
+ bool got_nl = false;
+ while (got < buf + len && (end = strchr (got, '\n')))
+ {
+ got_nl = true;
+ end[end[-1] == '\r' ? -1 : 0] = '\0';
+ if (!from_fstab_line (got, user))
+ goto done;
+ got = end + 1;
+ ++line;
+ }
+ if (len < (NT_MAX_PATH - 2))
break;
+ /* Check if the buffer contained at least one \n. If not, the
+ line length is > 32K. We don't take such long lines. Print
+ a debug message and skip this line entirely. */
+ if (!got_nl)
+ {
+ system_printf ("%W: Line %d too long, skipping...", fstab, line);
+ while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, buf,
+ (NT_MAX_PATH - 2), NULL, NULL)))
+ {
+ len = io.Information;
+ buf[len] = buf[len + 1] = '\0';
+ got = strchr (buf, '\n');
+ if (got)
+ {
+ ++got;
+ ++line;
+ goto retry;
+ }
+ }
+ got = buf;
+ break;
+ }
+ /* We have to read once more. Move remaining bytes to the start of
+ the buffer and reposition got so that it points to the end of
+ the remaining bytes. */
+ len = buf + len - got;
+ memmove (buf, got, len);
+ got = buf + len;
+ buf[len] = buf[len + 1] = '\0';
+ }
+ /* Catch a last line without trailing \n. */
+ if (got > buf)
+ from_fstab_line (got, user);
+done:
+ NtClose (fh);
return true;
}
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc
index b8ed09466..88690e379 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -10,7 +10,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <lm.h>
#include <stdlib.h>
#include <stdio.h>
#include "cygerrno.h"
@@ -20,210 +19,127 @@ details. */
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
+#include "pwdgrp.h"
#include "shared_info.h"
-#include "miscfuncs.h"
-#include "ldap.h"
-#include "tls_pbuf.h"
+
+/* Read /etc/passwd only once for better performance. This is done
+ on the first call that needs information from it. */
+
+passwd *passwd_buf;
+static pwdgrp pr (passwd_buf);
/* Parse /etc/passwd line into passwd structure. */
bool
pwdgrp::parse_passwd ()
{
- pg_pwd &res = passwd ()[curr_lines];
- res.p.pw_name = next_str (':');
- res.p.pw_passwd = next_str (':');
- if (!next_num (res.p.pw_uid))
+ passwd &res = (*passwd_buf)[curr_lines];
+ res.pw_name = next_str (':');
+ res.pw_passwd = next_str (':');
+ if (!next_num (res.pw_uid))
return false;
- if (!next_num (res.p.pw_gid))
+ if (!next_num (res.pw_gid))
return false;
- res.p.pw_comment = NULL;
- res.p.pw_gecos = next_str (':');
- res.p.pw_dir = next_str (':');
- res.p.pw_shell = next_str (':');
- res.sid.getfrompw (&res.p);
- /* lptr points to the \0 after pw_shell. Increment by one to get the correct
- required buffer len in getpw_cp. */
- res.len = lptr - res.p.pw_name + 1;
+ res.pw_comment = NULL;
+ res.pw_gecos = next_str (':');
+ res.pw_dir = next_str (':');
+ res.pw_shell = next_str (':');
return true;
}
+/* Read in /etc/passwd and save contents in the password cache.
+ This sets pr to loaded or emulated so functions in this file can
+ tell that /etc/passwd has been read in or will be emulated. */
void
-pwdgrp::init_pwd ()
-{
- pwdgrp_buf_elem_size = sizeof (pg_pwd);
- parse = &pwdgrp::parse_passwd;
+pwdgrp::read_passwd ()
+{
+ load (L"\\etc\\passwd");
+
+ char strbuf[128] = "";
+ bool searchentry = true;
+ struct passwd *pw;
+ /* must be static */
+ static char NO_COPY pretty_ls[] = "????????:*:-1:-1:::";
+
+ add_line (pretty_ls);
+ cygsid tu = cygheap->user.sid ();
+ tu.string (strbuf);
+ if (!user_shared->cb || myself->uid == ILLEGAL_UID)
+ searchentry = !internal_getpwsid (tu);
+ if (searchentry
+ && (!(pw = internal_getpwnam (cygheap->user.name ()))
+ || !user_shared->cb
+ || (myself->uid != ILLEGAL_UID
+ && myself->uid != pw->pw_uid
+ && !internal_getpwuid (myself->uid))))
+ {
+ static char linebuf[1024]; // must be static and
+ // should not be NO_COPY
+ snprintf (linebuf, sizeof (linebuf), "%s:*:%u:%u:,%s:%s:/bin/sh",
+ cygheap->user.name (),
+ (!user_shared->cb || myself->uid == ILLEGAL_UID)
+ ? UNKNOWN_UID : myself->uid,
+ !user_shared->cb ? UNKNOWN_GID : myself->gid,
+ strbuf, getenv ("HOME") ?: "");
+ debug_printf ("Completing /etc/passwd: %s", linebuf);
+ add_line (linebuf);
+ }
}
struct passwd *
-pwdgrp::find_user (cygpsid &sid)
+internal_getpwsid (cygpsid &sid)
{
- for (ULONG i = 0; i < curr_lines; i++)
- if (sid == passwd ()[i].sid)
- return &passwd ()[i].p;
- return NULL;
-}
+ struct passwd *pw;
+ char *ptr1, *ptr2, *endptr;
+ char sid_string[128] = {0,','};
-struct passwd *
-pwdgrp::find_user (const char *name)
-{
- for (ULONG i = 0; i < curr_lines; i++)
- /* on Windows NT user names are case-insensitive */
- if (strcasematch (name, passwd ()[i].p.pw_name))
- return &passwd ()[i].p;
- return NULL;
-}
+ pr.refresh (false);
-struct passwd *
-pwdgrp::find_user (uid_t uid)
-{
- for (ULONG i = 0; i < curr_lines; i++)
- if (uid == passwd ()[i].p.pw_uid)
- return &passwd ()[i].p;
- return NULL;
-}
-
-struct passwd *
-internal_getpwsid (cygpsid &sid, cyg_ldap *pldap)
-{
- struct passwd *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.find_user (sid)))
- return ret;
- if (cygheap->pg.nss_pwd_files ()
- && (ret = cygheap->pg.pwd_cache.file.find_user (sid)))
- return ret;
- if (cygheap->pg.nss_pwd_db ()
- && (ret = cygheap->pg.pwd_cache.win.find_user (sid)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (sid)))
- return ret;
- if (cygheap->pg.nss_pwd_files ())
+ if (sid.string (sid_string + 2))
{
- cygheap->pg.pwd_cache.file.check_file ();
- if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (sid)))
- return ret;
+ endptr = strchr (sid_string + 2, 0) - 1;
+ for (int i = 0; i < pr.curr_lines; i++)
+ {
+ pw = passwd_buf + i;
+ if (pw->pw_dir > pw->pw_gecos + 8)
+ for (ptr1 = endptr, ptr2 = pw->pw_dir - 2;
+ *ptr1 == *ptr2; ptr2--)
+ if (!*--ptr1)
+ return pw;
+ }
}
- if (cygheap->pg.nss_pwd_db ())
- return cygheap->pg.pwd_cache.win.add_user_from_windows (sid, pldap);
return NULL;
}
-/* This function gets only called from mkpasswd via cygwin_internal. */
struct passwd *
-internal_getpwsid_from_db (cygpsid &sid)
+internal_getpwuid (uid_t uid, bool check)
{
- cygheap->pg.nss_init ();
- return cygheap->pg.pwd_cache.win.add_user_from_windows (sid);
-}
+ pr.refresh (check);
-struct passwd *
-internal_getpwnam (const char *name, cyg_ldap *pldap)
-{
- struct passwd *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.find_user (name)))
- return ret;
- if (cygheap->pg.nss_pwd_files ()
- && (ret = cygheap->pg.pwd_cache.file.find_user (name)))
- return ret;
- if (cygheap->pg.nss_pwd_db ()
- && (ret = cygheap->pg.pwd_cache.win.find_user (name)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (name)))
- return ret;
- if (cygheap->pg.nss_pwd_files ())
- {
- cygheap->pg.pwd_cache.file.check_file ();
- if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (name)))
- return ret;
- }
- if (cygheap->pg.nss_pwd_db ())
- return cygheap->pg.pwd_cache.win.add_user_from_windows (name, pldap);
+ for (int i = 0; i < pr.curr_lines; i++)
+ if (uid == passwd_buf[i].pw_uid)
+ return passwd_buf + i;
return NULL;
}
struct passwd *
-internal_getpwuid (uid_t uid, cyg_ldap *pldap)
+internal_getpwnam (const char *name, bool check)
{
- struct passwd *ret;
-
- cygheap->pg.nss_init ();
- /* Check caches first. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.find_user (uid)))
- return ret;
- if (cygheap->pg.nss_pwd_files ()
- && (ret = cygheap->pg.pwd_cache.file.find_user (uid)))
- return ret;
- if (cygheap->pg.nss_pwd_db ()
- && (ret = cygheap->pg.pwd_cache.win.find_user (uid)))
- return ret;
- /* Ask sources afterwards. */
- if (cygheap->pg.nss_cygserver_caching ()
- && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (uid)))
- return ret;
- if (cygheap->pg.nss_pwd_files ())
- {
- cygheap->pg.pwd_cache.file.check_file ();
- if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (uid)))
- return ret;
- }
- if (cygheap->pg.nss_pwd_db () || uid == ILLEGAL_UID)
- return cygheap->pg.pwd_cache.win.add_user_from_windows (uid, pldap);
+ pr.refresh (check);
+
+ for (int i = 0; i < pr.curr_lines; i++)
+ /* on Windows NT user names are case-insensitive */
+ if (strcasematch (name, passwd_buf[i].pw_name))
+ return passwd_buf + i;
return NULL;
}
-/* getpwuid/getpwnam are not reentrant. */
-static struct {
- struct passwd p;
- char *buf;
- size_t bufsiz;
-} app_pw;
-
-static struct passwd *
-getpw_cp (struct passwd *temppw)
-{
- if (!temppw)
- return NULL;
- pg_pwd *pw = (pg_pwd *) temppw;
- if (app_pw.bufsiz < pw->len)
- {
- char *newbuf = (char *) realloc (app_pw.buf, pw->len);
- if (!newbuf)
- {
- set_errno (ENOMEM);
- return NULL;
- }
- app_pw.buf = newbuf;
- app_pw.bufsiz = pw->len;
- }
- memcpy (app_pw.buf, pw->p.pw_name, pw->len);
- memcpy (&app_pw.p, &pw->p, sizeof pw->p);
- ptrdiff_t diff = app_pw.buf - pw->p.pw_name;
- app_pw.p.pw_name += diff;
- app_pw.p.pw_passwd += diff;
- app_pw.p.pw_gecos += diff;
- app_pw.p.pw_dir += diff;
- app_pw.p.pw_shell += diff;
- return &app_pw.p;
-}
extern "C" struct passwd *
getpwuid32 (uid_t uid)
{
- struct passwd *temppw = internal_getpwuid (uid);
+ struct passwd *temppw = internal_getpwuid (uid, true);
pthread_testcancel ();
- return getpw_cp (temppw);
+ return temppw;
}
#ifdef __x86_64__
@@ -244,7 +160,7 @@ getpwuid_r32 (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struc
if (!pwd || !buffer)
return ERANGE;
- struct passwd *temppw = internal_getpwuid (uid);
+ struct passwd *temppw = internal_getpwuid (uid, true);
pthread_testcancel ();
if (!temppw)
return 0;
@@ -282,9 +198,9 @@ getpwuid_r (__uid16_t uid, struct passwd *pwd, char *buffer, size_t bufsize, str
extern "C" struct passwd *
getpwnam (const char *name)
{
- struct passwd *temppw = internal_getpwnam (name);
+ struct passwd *temppw = internal_getpwnam (name, true);
pthread_testcancel ();
- return getpw_cp (temppw);
+ return temppw;
}
@@ -300,7 +216,7 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
if (!pwd || !buffer || !nam)
return ERANGE;
- struct passwd *temppw = internal_getpwnam (nam);
+ struct passwd *temppw = internal_getpwnam (nam, true);
pthread_testcancel ();
if (!temppw)
@@ -326,429 +242,37 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
return 0;
}
-/* getpwent functions are not reentrant. */
-static pw_ent pwent;
-
-void
-pg_ent::clear_cache ()
-{
- if (pg.curr_lines)
- {
- if (state > from_file)
- cfree (group ? grp.g.gr_name : pwd.p.pw_name);
- pg.curr_lines = 0;
- }
-}
-
-void
-pg_ent::setent (bool _group, int _enums, PCWSTR _enum_tdoms)
-{
- cygheap->dom.init ();
- endent (_group);
- if (!_enums && !_enum_tdoms)
- {
- /* This is the default, when called from the usual setpwent/setgrent
- functions. */
- enums = cygheap->pg.nss_db_enums ();
- enum_tdoms = cygheap->pg.nss_db_enum_tdoms ();
- if (_group)
- {
- from_files = cygheap->pg.nss_grp_files ();
- from_db = cygheap->pg.nss_grp_db ();
- }
- else
- {
- from_files = cygheap->pg.nss_pwd_files ();
- from_db = cygheap->pg.nss_pwd_db ();
- }
- }
- else
- {
- /* This case is when called from mkpasswd/mkgroup via cygwin_internal. */
- enums = _enums;
- enum_tdoms = _enum_tdoms;
- from_files = false;
- from_db = true;
- }
- state = from_cache;
-}
-
-void *
-pg_ent::getent (void)
-{
- void *entry;
-
- switch (state)
- {
- case rewound:
- state = from_cache;
- /*FALLTHRU*/
- case from_cache:
- if (nss_db_enum_caches ()
- && (entry = enumerate_caches ()))
- return entry;
- state = from_file;
- /*FALLTHRU*/
- case from_file:
- if (from_files
- && nss_db_enum_files ()
- && (entry = enumerate_file ()))
- return entry;
- state = from_builtin;
- /*FALLTHRU*/
- case from_builtin:
- if (from_db
- && nss_db_enum_builtin ()
- && (entry = enumerate_builtin ()))
- return entry;
- state = from_local;
- /*FALLTHRU*/
- case from_local:
- if (from_db
- && nss_db_enum_local ()
- && (!cygheap->dom.member_machine ()
- || !nss_db_enum_primary ())
- && (entry = enumerate_local ()))
- return entry;
- state = from_sam;
- /*FALLTHRU*/
- case from_sam:
- if (from_db
- && nss_db_enum_local ()
- /* Domain controller? If so, sam and ad are one and the same
- and "local ad" would list all domain accounts twice without
- this test. */
- && (cygheap->dom.account_flat_name ()[0] != L'@'
- || !nss_db_enum_primary ())
- && (entry = enumerate_sam ()))
- return entry;
- state = from_ad;
- /*FALLTHRU*/
- case from_ad:
- if (cygheap->dom.member_machine ()
- && from_db
- && (entry = enumerate_ad ()))
- return entry;
- state = finished;
- /*FALLTHRU*/
- case finished:
- break;
- }
- return NULL;
-}
-
-void
-pg_ent::endent (bool _group)
-{
- if (buf)
- {
- if (state == from_file)
- free (buf);
- else if (state == from_local || state == from_sam)
- NetApiBufferFree (buf);
- buf = NULL;
- }
- if (!pg.curr_lines)
- {
- if ((group = _group))
- {
- pg.init_grp ();
- pg.pwdgrp_buf = (void *) &grp;
- }
- else
- {
- pg.init_pwd ();
- pg.pwdgrp_buf = (void *) &pwd;
- }
- pg.max_lines = 1;
- }
- else
- clear_cache ();
- cldap.close ();
- rl.close ();
- cnt = max = resume = 0;
- enums = 0;
- enum_tdoms = NULL;
- state = rewound;
-}
-
-void *
-pg_ent::enumerate_file ()
-{
- void *entry;
-
- if (!cnt)
- {
- pwdgrp &prf = group ? cygheap->pg.grp_cache.file
- : cygheap->pg.pwd_cache.file;
- if (prf.check_file ())
- {
- if (!buf)
- buf = (char *) malloc (NT_MAX_PATH);
- if (buf
- && !rl.init (prf.file_attr (), buf, NT_MAX_PATH))
- {
- free (buf);
- buf = NULL;
- }
- }
- }
- ++cnt;
- if ((entry = pg.add_account_post_fetch (rl.gets (), false)))
- return entry;
- rl.close ();
- free (buf);
- buf = NULL;
- cnt = max = resume = 0;
- return NULL;
-}
-
-void *
-pg_ent::enumerate_builtin ()
-{
- static cygpsid *pwd_builtins[] = {
- &well_known_system_sid,
- &well_known_local_service_sid,
- &well_known_network_service_sid,
- &well_known_admins_sid,
- &trusted_installer_sid,
- NULL
- };
- static cygpsid *grp_builtins[] = {
- &well_known_system_sid,
- &trusted_installer_sid,
- NULL
- };
-
- cygpsid **builtins = group ? grp_builtins : pwd_builtins;
- if (!builtins[cnt])
- {
- cnt = max = resume = 0;
- return NULL;
- }
- cygsid sid (*builtins[cnt++]);
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = pg.fetch_account_from_windows (arg);
- return pg.add_account_post_fetch (line, false);
-}
-
-void *
-pg_ent::enumerate_sam ()
-{
- while (true)
- {
- if (!cnt)
- {
- DWORD total;
- NET_API_STATUS ret;
-
- if (buf)
- {
- NetApiBufferFree (buf);
- buf = NULL;
- }
- if (resume == ULONG_MAX)
- ret = ERROR_NO_MORE_ITEMS;
- else if (group)
- ret = NetGroupEnum (NULL, 2, (PBYTE *) &buf, MAX_PREFERRED_LENGTH,
- &max, &total, &resume);
- else
- ret = NetUserEnum (NULL, 20, FILTER_NORMAL_ACCOUNT, (PBYTE *) &buf,
- MAX_PREFERRED_LENGTH, &max, &total,
- (PDWORD) &resume);
- if (ret == NERR_Success)
- resume = ULONG_MAX;
- else if (ret != ERROR_MORE_DATA)
- {
- cnt = max = resume = 0;
- return NULL;
- }
- }
- while (cnt < max)
- {
- cygsid sid (cygheap->dom.account_sid ());
- sid_sub_auth (sid, sid_sub_auth_count (sid)) =
- group ? ((PGROUP_INFO_2) buf)[cnt].grpi2_group_id
- : ((PUSER_INFO_20) buf)[cnt].usri20_user_id;
- ++cnt;
- ++sid_sub_auth_count (sid);
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = pg.fetch_account_from_windows (arg);
- if (line)
- return pg.add_account_post_fetch (line, false);
- }
- cnt = 0;
- }
-}
-
-void *
-pg_ent::enumerate_ad ()
+extern "C" struct passwd *
+getpwent (void)
{
- while (true)
- {
- if (!cnt)
- {
- PDS_DOMAIN_TRUSTSW td;
-
- if (!resume)
- {
- ++resume;
- if (!nss_db_enum_primary ()
- || cldap.enumerate_ad_accounts (NULL, group) != NO_ERROR)
- continue;
- }
- else if ((td = cygheap->dom.trusted_domain (resume - 1)))
- {
- ++resume;
- /* Ignore primary domain in list of trusted domains only if all
- trusted domains are enumerated anyway. This handles an
- annoying backward compatibility problem in mkpasswd/mkgroup.
- Without this test, `mkpasswd -d PRIMARY_DOMAIN' wouldn't
- work as expected. */
- if (((enums & ENUM_TDOMS_ALL) && td->Flags & DS_DOMAIN_PRIMARY)
- || !td->DomainSid
- || (!nss_db_enum_tdom (td->NetbiosDomainName)
- && !nss_db_enum_tdom (td->DnsDomainName))
- || cldap.enumerate_ad_accounts (td->DnsDomainName, group)
- != NO_ERROR)
- continue;
- }
- else
- {
- cldap.close ();
- return NULL;
- }
- }
- ++cnt;
- cygsid sid;
- int ret = cldap.next_account (sid);
- if (ret == NO_ERROR)
- {
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = pg.fetch_account_from_windows (arg, &cldap);
- if (line)
- return pg.add_account_post_fetch (line, false);
- ret = EIO;
- }
- if (ret != ENMFILE)
- {
- cldap.close ();
- set_errno (ret);
- return NULL;
- }
- cnt = 0;
- }
-}
+ if (_my_tls.locals.pw_pos == 0)
+ pr.refresh (true);
+ if (_my_tls.locals.pw_pos < pr.curr_lines)
+ return passwd_buf + _my_tls.locals.pw_pos++;
-void *
-pw_ent::enumerate_caches ()
-{
- switch (max)
- {
- case 0:
- if (cygheap->pg.nss_cygserver_caching ())
- {
- pwdgrp &prc = cygheap->pg.pwd_cache.cygserver;
- if (cnt < prc.cached_users ())
- return &prc.passwd ()[cnt++].p;
- }
- cnt = 0;
- max = 1;
- /*FALLTHRU*/
- case 1:
- if (from_files)
- {
- pwdgrp &prf = cygheap->pg.pwd_cache.file;
- prf.check_file ();
- if (cnt < prf.cached_users ())
- return &prf.passwd ()[cnt++].p;
- }
- cnt = 0;
- max = 2;
- /*FALLTHRU*/
- default:
- if (from_db)
- {
- pwdgrp &prw = cygheap->pg.pwd_cache.win;
- if (cnt < prw.cached_users ())
- return &prw.passwd ()[cnt++].p;
- }
- break;
- }
- cnt = max = 0;
return NULL;
}
-void *
-pw_ent::enumerate_local ()
+#ifndef __x86_64__
+extern "C" struct passwd *
+getpwduid (__uid16_t)
{
return NULL;
}
-
-struct passwd *
-pw_ent::getpwent (void)
-{
- if (state == rewound)
- setent (false);
- else
- clear_cache ();
- return (struct passwd *) getent ();
-}
+#endif
extern "C" void
-setpwent ()
-{
- pwent.setpwent ();
-}
-
-extern "C" struct passwd *
-getpwent (void)
+setpwent (void)
{
- return pwent.getpwent ();
+ _my_tls.locals.pw_pos = 0;
}
extern "C" void
endpwent (void)
{
- pwent.endpwent ();
+ _my_tls.locals.pw_pos = 0;
}
-/* *_filtered functions are called from mkpasswd */
-void *
-setpwent_filtered (int enums, PCWSTR enum_tdoms)
-{
- pw_ent *pw = new pw_ent;
- if (pw)
- pw->setpwent (enums, enum_tdoms);
- return (void *) pw;
-}
-
-void *
-getpwent_filtered (void *pw)
-{
- return (void *) ((pw_ent *) pw)->getpwent ();
-}
-
-void
-endpwent_filtered (void *pw)
-{
- ((pw_ent *) pw)->endpwent ();
-}
-
-#ifndef __x86_64__
-extern "C" struct passwd *
-getpwduid (__uid16_t)
-{
- return NULL;
-}
-#endif
-
extern "C" int
setpassent (int)
{
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 6a3a889a3..d8604817a 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2834,13 +2834,13 @@ restart:
This case is only recognized by the length of the
basename part. If it's 0, the incoming file is the
root of a drive. So we at least know it's a directory. */
- if (basename.Length)
- fileattr = FILE_ATTRIBUTE_DIRECTORY;
- else
- {
- fileattr = 0;
- set_error (geterrno_from_nt_status (status));
- }
+ if (basename.Length)
+ fileattr = FILE_ATTRIBUTE_DIRECTORY;
+ else
+ {
+ fileattr = 0;
+ set_error (geterrno_from_nt_status (status));
+ }
}
else
{
@@ -4695,6 +4695,142 @@ out:
return buf;
}
+int etc::curr_ix = 0;
+/* Note that the first elements of the below arrays are unused */
+bool etc::change_possible[MAX_ETC_FILES + 1];
+OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
+LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
+
+int
+etc::init (int n, POBJECT_ATTRIBUTES attr)
+{
+ if (n > 0)
+ /* ok */;
+ else if (++curr_ix <= MAX_ETC_FILES)
+ n = curr_ix;
+ else
+ api_fatal ("internal error");
+
+ fn[n] = *attr;
+ change_possible[n] = false;
+ test_file_change (n);
+ paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
+ return n;
+}
+
+bool
+etc::test_file_change (int n)
+{
+ NTSTATUS status;
+ FILE_NETWORK_OPEN_INFORMATION fnoi;
+ bool res;
+
+ status = NtQueryFullAttributesFile (&fn[n], &fnoi);
+ if (!NT_SUCCESS (status))
+ {
+ res = status != STATUS_OBJECT_NAME_NOT_FOUND;
+ memset (last_modified + n, 0, sizeof (last_modified[n]));
+ debug_printf ("NtQueryFullAttributesFile (%S) failed, %y",
+ fn[n].ObjectName, status);
+ }
+ else
+ {
+ res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
+ (FILETIME *) last_modified + n) > 0;
+ last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
+ }
+
+ paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
+ return res;
+}
+
+bool
+etc::dir_changed (int n)
+{
+ /* io MUST be static because NtNotifyChangeDirectoryFile works asynchronously.
+ It may write into io after the function has left, which may result in all
+ sorts of stack corruption. */
+ static IO_STATUS_BLOCK io NO_COPY;
+ static HANDLE changed_h NO_COPY;
+
+ if (!change_possible[n])
+ {
+ NTSTATUS status;
+
+ if (!changed_h)
+ {
+ OBJECT_ATTRIBUTES attr;
+
+ path_conv dir ("/etc");
+ status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ dir.get_object_attr (attr, sec_none_nih), &io,
+ FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtOpenFile (%S) failed, %y",
+ dir.get_nt_native_path (), status);
+#endif
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
+ NULL, &io, NULL, 0,
+ FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_FILE_NAME,
+ FALSE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtNotifyChangeDirectoryFile (1) failed, %y",
+ status);
+#endif
+ NtClose (changed_h);
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ }
+ memset (change_possible, true, sizeof (change_possible));
+ }
+
+ if (changed_h == INVALID_HANDLE_VALUE)
+ change_possible[n] = true;
+ else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
+ {
+ status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
+ NULL, &io, NULL, 0,
+ FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_FILE_NAME,
+ FALSE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtNotifyChangeDirectoryFile (2) failed, %y",
+ status);
+#endif
+ NtClose (changed_h);
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ memset (change_possible, true, sizeof change_possible);
+ }
+ }
+
+ paranoid_printf ("fn[%d] %S change_possible %d",
+ n, fn[n].ObjectName, change_possible[n]);
+ return change_possible[n];
+}
+
+bool
+etc::file_changed (int n)
+{
+ bool res = false;
+ if (dir_changed (n) && test_file_change (n))
+ res = true;
+ change_possible[n] = false; /* Change is no longer possible */
+ paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
+ return res;
+}
+
/* No need to be reentrant or thread-safe according to SUSv3.
/ and \\ are treated equally. Leading drive specifiers are
kept intact as far as it makes sense. Everything else is
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index 8d4525890..18b05261c 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -448,4 +448,21 @@ int normalize_win32_path (const char *, char *, char *&);
int normalize_posix_path (const char *, char *, char *&);
PUNICODE_STRING __reg3 get_nt_native_path (const char *, UNICODE_STRING&, bool);
+/* FIXME: Move to own include file eventually */
+
+#define MAX_ETC_FILES 2
+class etc
+{
+ friend class dtable;
+ static int curr_ix;
+ static bool change_possible[MAX_ETC_FILES + 1];
+ static OBJECT_ATTRIBUTES fn[MAX_ETC_FILES + 1];
+ static LARGE_INTEGER last_modified[MAX_ETC_FILES + 1];
+ static bool dir_changed (int);
+ static int init (int, POBJECT_ATTRIBUTES);
+ static bool file_changed (int);
+ static bool test_file_change (int);
+ friend class pwdgrp;
+};
+
int __reg3 symlink_worker (const char *, const char *, bool);
diff --git a/winsup/cygwin/path.sgml b/winsup/cygwin/path.sgml
new file mode 100644
index 000000000..79f97dff5
--- /dev/null
+++ b/winsup/cygwin/path.sgml
@@ -0,0 +1,178 @@
+<sect1 id="func-cygwin-conv-path">
+<title>cygwin_conv_path</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" ssize_t
+<function>cygwin_conv_path</function></funcdef>
+<paramdef>cygwin_conv_path_t <parameter>what</parameter></paramdef>
+<paramdef>const void * <parameter>from</parameter></paramdef>
+<paramdef>void * <parameter>to</parameter></paramdef>
+<paramdef>size_t <parameter>size</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>Use this function to convert POSIX paths in
+<parameter>from</parameter> to Win32 paths in <parameter>to</parameter>
+or, vice versa, Win32 paths in <parameter>from</parameter> to POSIX paths
+in <parameter>to</parameter>. <parameter>what</parameter>
+defines the direction of this conversion and can be any of the below
+values.</para>
+
+<programlisting>
+ CCP_POSIX_TO_WIN_A /* from is char *posix, to is char *win32 */
+ CCP_POSIX_TO_WIN_W, /* from is char *posix, to is wchar_t *win32 */
+ CCP_WIN_A_TO_POSIX, /* from is char *win32, to is char *posix */
+ CCP_WIN_W_TO_POSIX, /* from is wchar_t *win32, to is char *posix */
+</programlisting>
+
+<para>You can additionally or the following values to
+<parameter>what</parameter>, to define whether you want the resulting
+path in <parameter>to</parameter> to be absolute or if you want to keep
+relative paths in relative notation. Creating absolute paths is the
+default.</para>
+
+<programlisting>
+ CCP_ABSOLUTE = 0, /* Request absolute path (default). */
+ CCP_RELATIVE = 0x100 /* Request to keep path relative. */
+</programlisting>
+
+<para><parameter>size</parameter> is the size of the buffer pointed to
+by <parameter>to</parameter> in bytes. If <parameter>size</parameter>
+is 0, <function>cygwin_conv_path</function> just returns the required
+buffer size in bytes. Otherwise, it returns 0 on success, or -1 on
+error and errno is set to one of the below values.</para>
+
+<programlisting>
+ EINVAL what has an invalid value or from is NULL.
+ EFAULT from or to point into nirvana.
+ ENAMETOOLONG the resulting path is longer than 32K, or, in case
+ of what == CCP_POSIX_TO_WIN_A, longer than MAX_PATH.
+ ENOSPC size is less than required for the conversion.
+</programlisting>
+
+<example>
+<title>Example use of cygwin_conv_path</title>
+<programlisting>
+<![CDATA[
+#include <sys/cygwin.h>
+
+/* Conversion from incoming Win32 path given as wchar_t *win32 to POSIX path.
+ If incoming path is a relative path, stick to it. First ask how big
+ the output buffer has to be and allocate space dynamically. */
+ssize_t size;
+char *posix;
+size = cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_RELATIVE, win32, NULL, 0);
+if (size < 0)
+ perror ("cygwin_conv_path");
+else
+ {
+ posix = (char *) malloc (size);
+ if (cygwin_conv_path (CCP_WIN_W_TO_POSIX | CCP_RELATIVE, win32,
+ posix, size))
+ perror ("cygwin_conv_path");
+ }
+]]>
+</programlisting>
+</example>
+
+</sect1>
+
+<sect1 id="func-cygwin-conv-path-list">
+<title>cygwin_conv_path_list</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" ssize_t
+<function>cygwin_conv_path_list</function></funcdef>
+<paramdef>cygwin_conv_path_t <parameter>what</parameter></paramdef>
+<paramdef>const void * <parameter>from</parameter></paramdef>
+<paramdef>void * <parameter>to</parameter></paramdef>
+<paramdef>size_t <parameter>size</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This is the same as <function>cygwin_conv_path</function>, but the
+input is treated as a path list in $PATH or %PATH% notation.</para>
+<para>If <parameter>what</parameter> is CCP_POSIX_TO_WIN_A or
+CCP_POSIX_TO_WIN_W, given a POSIX $PATH-style string (i.e. /foo:/bar)
+convert it to the equivalent Win32 %PATH%-style string (i.e. d:\;e:\bar).</para>
+<para>If <parameter>what</parameter> is CCP_WIN_A_TO_POSIX or
+CCP_WIN_W_TO_POSIX, given a Win32 %PATH%-style string (i.e. d:\;e:\bar)
+convert it to the equivalent POSIX $PATH-style string (i.e. /foo:/bar).</para>
+<para><parameter>size</parameter> is the size of the buffer pointed to by
+<parameter>to</parameter> in bytes.</para>
+
+<para>See also <link linkend="func-cygwin-conv-path">cygwin_conv_path</link></para>
+
+</sect1>
+
+<sect1 id="func-cygwin-create-path">
+<title>cygwin_create_path</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" void *
+<function>cygwin_create_path</function></funcdef>
+<paramdef>cygwin_conv_path_t <parameter>what</parameter></paramdef>
+<paramdef>const void * <parameter>from</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This is equivalent to the <function>cygwin_conv_path</function>, except
+that <function>cygwin_create_path</function> does not take a buffer pointer
+for the result of the conversion as input. Rather it allocates the buffer
+itself using <function>malloc</function>(3) and returns a pointer to this
+buffer. In case of error it returns NULL and sets errno to one of the
+values defined for <function>cygwin_conv_path</function>. Additionally
+errno can be set to the below value.</para>
+
+<programlisting>
+ ENOMEM Insufficient memory was available.
+</programlisting>
+
+<para>When you don't need the returned buffer anymore, use
+<function>free</function>(3) to deallocate it.</para>
+
+<para>See also <link linkend="func-cygwin-conv-path">cygwin_conv_path</link></para>
+
+</sect1>
+
+<sect1 id="func-cygwin-posix-path-list-p">
+<title>cygwin_posix_path_list_p</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" int
+<function>cygwin_posix_path_list_p</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>This function tells you if the supplied
+<parameter>path</parameter> is a POSIX-style path (i.e. posix names,
+forward slashes, colon delimiters) or a Win32-style path (drive
+letters, reverse slashes, semicolon delimiters. The return value is
+true if the path is a POSIX path. Note that "_p" means "predicate", a
+lisp term meaning that the function tells you something about the
+parameter.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-split-path">
+<title>cygwin_split_path</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" void
+<function>cygwin_split_path</function>
+</funcdef>
+<paramdef>const char * <parameter>path</parameter></paramdef>
+<paramdef>char * <parameter>dir</parameter></paramdef>
+<paramdef>char * <parameter>file</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>Split a path into the directory and the file portions. Both
+<parameter>dir</parameter> and <parameter>file</parameter> are
+expected to point to buffers of sufficient size. </para>
+
+<example>
+<title>Example use of cygwin_split_path</title>
+<programlisting>
+char dir[200], file[100];
+cygwin_split_path("c:/foo/bar.c", dir, file);
+printf("dir=%s, file=%s\n", dir, file);
+</programlisting>
+</example>
+</sect1>
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 4518d6d51..5d9e74895 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -41,7 +41,7 @@ pinfo_basic::pinfo_basic ()
GetModuleFileNameW (NULL, progname, sizeof (progname) / sizeof (WCHAR));
/* Default uid/gid are needed very early to initialize shared user info. */
uid = ILLEGAL_UID;
- gid = ILLEGAL_GID;
+ gid = UNKNOWN_GID;
}
pinfo_basic myself_initial NO_COPY;
@@ -100,7 +100,7 @@ pinfo_init (char **envp, int envc)
myself->pgid = myself->sid = myself->pid;
myself->ctty = -1;
myself->uid = ILLEGAL_UID;
- myself->gid = ILLEGAL_GID;
+ myself->gid = UNKNOWN_GID;
environ_init (NULL, 0); /* call after myself has been set up */
myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
myself->ppid = 1; /* always set last */
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
index 2b6f8a90a..17411a098 100644
--- a/winsup/cygwin/poll.cc
+++ b/winsup/cygwin/poll.cc
@@ -115,9 +115,8 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout)
So it looks like there's actually no good reason to
return POLLERR. */
fds[i].revents |= POLLIN;
- /* Handle failed connect. A failed connect implicitly sets
- POLLOUT, if requested, but it doesn't set POLLIN. */
- if ((fds[i].events & POLLIN)
+ /* Handle failed connect. */
+ if (FD_ISSET(fds[i].fd, write_fds)
&& (sock = cygheap->fdtab[fds[i].fd]->is_socket ())
&& sock->connect_state () == connect_failed)
fds[i].revents |= (POLLIN | POLLERR);
diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml
new file mode 100644
index 000000000..e8c97d601
--- /dev/null
+++ b/winsup/cygwin/posix.sgml
@@ -0,0 +1,1564 @@
+<sect1 id="std-susv4"><title>System interfaces compatible with the Single Unix Specification, Version 4:</title>
+
+<para>Note that the core of the Single Unix Specification, Version 4 is
+also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
+
+<screen>
+ FD_CLR
+ FD_ISSET
+ FD_SET
+ FD_ZERO
+ _Exit
+ _exit
+ _longjmp
+ _setjmp
+ _tolower
+ _toupper
+ a64l
+ abort
+ abs
+ accept
+ access
+ acos
+ acosf
+ acosh
+ acoshf
+ alarm
+ alphasort
+ asctime
+ asctime_r
+ asin
+ asinf
+ asinh
+ asinhf
+ atan
+ atan2
+ atan2f
+ atanf
+ atanh
+ atanhf
+ atexit
+ atof
+ atoff
+ atoi
+ atol
+ atoll
+ basename
+ bind
+ bsearch
+ btowc
+ cabs
+ cabsf
+ cacos
+ cacosf
+ cacosh
+ cacoshf
+ calloc
+ carg
+ cargf
+ casin
+ casinf
+ casinh
+ casinhf
+ casinhl
+ catan
+ catanf
+ catanh
+ catanhf
+ catclose (available in external "catgets" library)
+ catgets (available in external "catgets" library)
+ catopen (available in external "catgets" library)
+ cbrt
+ cbrtf
+ ccos
+ ccosf
+ ccosh
+ ccoshf
+ ceil
+ ceilf
+ cexp
+ cexpf
+ cfgetispeed
+ cfgetospeed
+ cfsetispeed
+ cfsetospeed
+ chdir
+ chmod
+ chown
+ cimag
+ cimagf
+ clearerr
+ clock
+ clock_getcpuclockid
+ clock_getres
+ clock_gettime
+ clock_nanosleep (see chapter "Implementation Notes")
+ clock_settime (see chapter "Implementation Notes")
+ clog
+ clogf
+ close
+ closedir
+ closelog
+ confstr
+ conj
+ conjf
+ connect
+ copysign
+ copysignf
+ cos
+ cosf
+ cosh
+ coshf
+ cpow
+ cpowf
+ cproj
+ cprojf
+ creal
+ crealf
+ creat
+ crypt (available in external "crypt" library)
+ csin
+ csinf
+ csinh
+ csinhf
+ csqrt
+ csqrtf
+ ctan
+ ctanf
+ ctanh
+ ctanhf
+ ctermid
+ ctime
+ ctime_r
+ daylight
+ dbm_clearerr (available in external "libgdbm" library)
+ dbm_close (available in external "libgdbm" library)
+ dbm_delete (available in external "libgdbm" library)
+ dbm_error (available in external "libgdbm" library)
+ dbm_fetch (available in external "libgdbm" library)
+ dbm_firstkey (available in external "libgdbm" library)
+ dbm_nextkey (available in external "libgdbm" library)
+ dbm_open (available in external "libgdbm" library)
+ dbm_store (available in external "libgdbm" library)
+ difftime
+ dirfd
+ dirname
+ div
+ dlclose
+ dlerror
+ dlopen
+ dlsym
+ dprintf
+ drand48
+ dup
+ dup2
+ encrypt (available in external "crypt" library)
+ endgrent
+ endhostent
+ endprotoent
+ endpwent
+ endservent
+ endutxent
+ environ
+ erand48
+ erf
+ erfc
+ erfcf
+ erff
+ errno
+ execl
+ execle
+ execlp
+ execv
+ execve
+ execvp
+ exit
+ exp
+ exp2
+ exp2f
+ expf
+ expm1
+ expm1f
+ fabs
+ fabsf
+ faccessat
+ fchdir
+ fchmod
+ fchmodat
+ fchown
+ fchownat
+ fclose
+ fcntl (see chapter "Implementation Notes")
+ fdatasync
+ fdim
+ fdimf
+ fdopen
+ fdopendir
+ feclearexcept
+ fegetenv
+ fegetexceptflag
+ fegetround
+ feholdexcept
+ feof
+ feraiseexcept
+ ferror
+ fesetenv
+ fesetexceptflag
+ fesetround
+ fetestexcept
+ feupdateenv
+ fexecve
+ fflush
+ ffs
+ fgetc
+ fgetpos
+ fgets
+ fgetwc
+ fgetws
+ fileno
+ flockfile
+ floor
+ floorf
+ fma
+ fmaf
+ fmax
+ fmaxf
+ fmemopen
+ fmin
+ fminf
+ fmod
+ fmodf
+ fnmatch
+ fopen
+ fork
+ fpathconf
+ fpclassify (see chapter "Implementation Notes")
+ fprintf
+ fputc
+ fputs
+ fputwc
+ fputws
+ fread
+ free
+ freeaddrinfo
+ freopen
+ frexp
+ frexpf
+ fscanf
+ fseek
+ fseeko
+ fsetpos
+ fstat
+ fstatat
+ fstatvfs
+ fsync
+ ftell
+ ftello
+ ftok
+ ftruncate
+ ftrylockfile
+ ftw
+ funlockfile
+ futimens
+ fwide
+ fwprintf
+ fwrite
+ fwscanf
+ gai_strerror
+ getaddrinfo
+ getc
+ getc_unlocked
+ getchar
+ getchar_unlocked
+ getcwd
+ getdelim
+ getdomainname
+ getegid
+ getenv
+ geteuid
+ getgid
+ getgrent
+ getgrgid
+ getgrgid_r
+ getgrnam
+ getgrnam_r
+ getgroups
+ gethostid
+ gethostname
+ getitimer (see chapter "Implementation Notes")
+ getline
+ getlogin
+ getlogin_r
+ getnameinfo
+ getopt
+ getpeername
+ getpgid
+ getpgrp
+ getpid
+ getppid
+ getpriority
+ getprotobyname
+ getprotobynumber
+ getprotoent
+ getpwent
+ getpwnam
+ getpwnam_r
+ getpwuid
+ getpwuid_r
+ getrlimit
+ getrusage
+ gets
+ getservbyname
+ getservbyport
+ getservent
+ getsid
+ getsockname
+ getsockopt
+ getsubopt
+ gettimeofday
+ getuid
+ getutxent
+ getutxid
+ getutxline
+ getwc
+ getwchar
+ glob
+ globfree
+ gmtime
+ gmtime_r
+ grantpt
+ hcreate
+ hdestroy
+ hsearch
+ htonl
+ htons
+ hypot
+ hypotf
+ iconv (available in external "libiconv" library)
+ iconv_close (available in external "libiconv" library)
+ iconv_open (available in external "libiconv" library)
+ if_freenameindex
+ if_indextoname
+ if_nameindex
+ if_nametoindex
+ ilogb
+ ilogbf
+ imaxabs
+ imaxdiv
+ inet_addr
+ inet_ntoa
+ inet_ntop
+ inet_pton
+ initstate
+ insque
+ ioctl
+ isalnum
+ isalpha
+ isascii
+ isatty
+ isblank
+ iscntrl
+ isdigit
+ isfinite (see chapter "Implementation Notes")
+ isgraph
+ isgreater (see chapter "Implementation Notes")
+ isgreaterequal (see chapter "Implementation Notes")
+ isinf (see chapter "Implementation Notes")
+ isless
+ islessequal (see chapter "Implementation Notes")
+ islessgreater (see chapter "Implementation Notes")
+ islower
+ isnan (see chapter "Implementation Notes")
+ isnormal (see chapter "Implementation Notes")
+ isprint
+ ispunct
+ isspace
+ isunordered (see chapter "Implementation Notes")
+ isupper
+ iswalnum
+ iswalpha
+ iswblank
+ iswcntrl
+ iswctype
+ iswdigit
+ iswgraph
+ iswlower
+ iswprint
+ iswpunct
+ iswspace
+ iswupper
+ iswxdigit
+ isxdigit
+ j0
+ j1
+ jn
+ jrand48
+ kill
+ killpg
+ l64a
+ labs
+ lchown
+ lcong48
+ ldexp
+ ldexpf
+ ldiv
+ lfind
+ lgamma
+ lgammaf
+ link
+ linkat
+ listen
+ llabs
+ lldiv
+ llrint
+ llrintf
+ llrintl
+ llround
+ llroundf
+ localeconv
+ localtime
+ localtime_r
+ lockf (see chapter "Implementation Notes")
+ log
+ log10
+ log10f
+ log1p
+ log1pf
+ log2
+ log2f
+ logb
+ logbf
+ logf
+ longjmp
+ lrand48
+ lrint
+ lrintf
+ lrintl
+ lround
+ lroundf
+ lsearch
+ lseek
+ lstat
+ malloc
+ mblen
+ mbrlen
+ mbrtowc
+ mbsinit
+ mbsnrtowcs
+ mbsrtowcs
+ mbstowcs
+ mbtowc
+ memccpy
+ memchr
+ memcmp
+ memcpy
+ memmove
+ memset
+ mkdir
+ mkdirat
+ mkdtemp
+ mkfifo
+ mkfifoat
+ mknod
+ mknodat
+ mkstemp
+ mktime
+ mlock
+ mmap
+ modf
+ modff
+ mprotect
+ mq_close
+ mq_getattr
+ mq_notify
+ mq_open
+ mq_receive
+ mq_send
+ mq_setattr
+ mq_timedreceive
+ mq_timedsend
+ mq_unlink
+ mrand48
+ msgctl (see chapter "Implementation Notes")
+ msgget (see chapter "Implementation Notes")
+ msgrcv (see chapter "Implementation Notes")
+ msgsnd (see chapter "Implementation Notes")
+ msync
+ munlock
+ munmap
+ nan
+ nanf
+ nanosleep
+ nearbyint
+ nearbyintf
+ nextafter
+ nextafterf
+ nftw
+ nice
+ nl_langinfo
+ nrand48
+ ntohl
+ ntohs
+ open
+ open_memstream
+ open_wmemstream
+ openat
+ opendir
+ openlog
+ optarg
+ opterr
+ optind
+ optopt
+ pathconf
+ pause
+ pclose
+ perror
+ pipe
+ poll
+ popen
+ posix_fadvise
+ posix_fallocate
+ posix_madvise
+ posix_memalign
+ posix_openpt
+ posix_spawn
+ posix_spawnattr_destroy
+ posix_spawnattr_init
+ posix_spawnattr_getflags
+ posix_spawnattr_getpgroup
+ posix_spawnattr_getschedparam
+ posix_spawnattr_getschedpolicy
+ posix_spawnattr_getsigdefault
+ posix_spawnattr_getsigmask
+ posix_spawnattr_setflags
+ posix_spawnattr_setpgroup
+ posix_spawnattr_setschedparam
+ posix_spawnattr_setschedpolicy
+ posix_spawnattr_setsigdefault
+ posix_spawnattr_setsigmask
+ posix_spawnp
+ posix_spawn_file_actions_destroy
+ posix_spawn_file_actions_init
+ posix_spawn_file_actions_addclose
+ posix_spawn_file_actions_adddup2
+ posix_spawn_file_actions_addopen
+ pow
+ powf
+ pread
+ printf
+ pselect
+ psiginfo
+ psignal
+ pthread_atfork
+ pthread_attr_destroy
+ pthread_attr_getdetachstate
+ pthread_attr_getguardsize
+ pthread_attr_getinheritsched
+ pthread_attr_getschedparam
+ pthread_attr_getschedpolicy
+ pthread_attr_getscope
+ pthread_attr_getstack
+ pthread_attr_getstacksize
+ pthread_attr_init
+ pthread_attr_setdetachstate
+ pthread_attr_setguardsize
+ pthread_attr_setinheritsched
+ pthread_attr_setschedparam
+ pthread_attr_setschedpolicy
+ pthread_attr_setscope
+ pthread_attr_setstack
+ pthread_attr_setstacksize
+ pthread_cancel
+ pthread_cond_broadcast
+ pthread_cond_destroy
+ pthread_cond_init
+ pthread_cond_signal
+ pthread_cond_timedwait
+ pthread_cond_wait
+ pthread_condattr_destroy
+ pthread_condattr_getclock
+ pthread_condattr_getpshared
+ pthread_condattr_init
+ pthread_condattr_setclock
+ pthread_condattr_setpshared
+ pthread_create
+ pthread_detach
+ pthread_equal
+ pthread_exit
+ pthread_getconcurrency
+ pthread_getcpuclockid
+ pthread_getschedparam
+ pthread_getspecific
+ pthread_join
+ pthread_key_create
+ pthread_key_delete
+ pthread_kill
+ pthread_mutex_destroy
+ pthread_mutex_getprioceiling
+ pthread_mutex_init
+ pthread_mutex_lock
+ pthread_mutex_setprioceiling
+ pthread_mutex_trylock
+ pthread_mutex_unlock
+ pthread_mutexattr_destroy
+ pthread_mutexattr_getprioceiling
+ pthread_mutexattr_getprotocol
+ pthread_mutexattr_getpshared
+ pthread_mutexattr_gettype
+ pthread_mutexattr_init
+ pthread_mutexattr_setprioceiling
+ pthread_mutexattr_setprotocol
+ pthread_mutexattr_setpshared
+ pthread_mutexattr_settype
+ pthread_once
+ pthread_rwlock_destroy
+ pthread_rwlock_init
+ pthread_rwlock_rdlock
+ pthread_rwlock_tryrdlock
+ pthread_rwlock_trywrlock
+ pthread_rwlock_unlock
+ pthread_rwlock_wrlock
+ pthread_rwlockattr_destroy
+ pthread_rwlockattr_getpshared
+ pthread_rwlockattr_init
+ pthread_rwlockattr_setpshared
+ pthread_self
+ pthread_setcancelstate
+ pthread_setcanceltype
+ pthread_setconcurrency
+ pthread_setschedparam
+ pthread_setschedprio
+ pthread_setspecific
+ pthread_sigmask
+ pthread_spin_destroy
+ pthread_spin_init
+ pthread_spin_lock
+ pthread_spin_trylock
+ pthread_spin_unlock
+ pthread_testcancel
+ ptsname
+ putc
+ putc_unlocked
+ putchar
+ putchar_unlocked
+ putenv
+ puts
+ pututxline
+ putwc
+ putwchar
+ pwrite
+ qsort
+ raise
+ rand
+ rand_r
+ random
+ read
+ readdir
+ readdir_r
+ readlink
+ readlinkat
+ readv
+ realloc
+ realpath
+ recv
+ recvfrom
+ recvmsg
+ regcomp
+ regerror
+ regexec
+ regfree
+ remainder
+ remainderf
+ remove
+ remque
+ remquo
+ remquof
+ rename
+ renameat
+ rewind
+ rewinddir
+ rint
+ rintf
+ rintl
+ rmdir
+ round
+ roundf
+ scalbln
+ scalblnf
+ scalbn
+ scalbnf
+ scandir
+ scanf
+ sched_get_priority_max
+ sched_get_priority_min
+ sched_getparam
+ sched_getscheduler
+ sched_rr_get_interval
+ sched_setparam
+ sched_setscheduler
+ sched_yield
+ seed48
+ seekdir
+ select
+ sem_close
+ sem_destroy
+ sem_getvalue
+ sem_init
+ sem_open
+ sem_post
+ sem_timedwait
+ sem_trywait
+ sem_unlink
+ sem_wait
+ semctl (see chapter "Implementation Notes")
+ semget (see chapter "Implementation Notes")
+ semop (see chapter "Implementation Notes")
+ send
+ sendmsg
+ sendto
+ setbuf
+ setegid
+ setenv
+ seteuid
+ setgid
+ setgrent
+ sethostent
+ setitimer (see chapter "Implementation Notes")
+ setjmp
+ setkey (available in external "crypt" library)
+ setlocale
+ setlogmask
+ setpgid
+ setpgrp
+ setpriority
+ setprotoent
+ setpwent
+ setregid
+ setreuid
+ setrlimit
+ setservent
+ setsid
+ setsockopt
+ setstate
+ setuid
+ setutxent
+ setvbuf
+ shm_open
+ shm_unlink
+ shmat (see chapter "Implementation Notes")
+ shmctl (see chapter "Implementation Notes")
+ shmdt (see chapter "Implementation Notes")
+ shmget (see chapter "Implementation Notes")
+ shutdown
+ sigaction
+ sigaddset
+ sigdelset
+ sigemptyset
+ sigfillset
+ sighold
+ sigignore
+ siginterrupt
+ sigismember
+ siglongjmp
+ signal
+ signbit (see chapter "Implementation Notes")
+ signgam
+ sigpause
+ sigpending
+ sigprocmask
+ sigqueue
+ sigrelse
+ sigset
+ sigsetjmp
+ sigsuspend
+ sigwait
+ sigwaitinfo
+ sin
+ sinf
+ sinh
+ sinhf
+ sleep
+ snprintf
+ socket
+ socketpair
+ sprintf
+ sqrt
+ sqrtf
+ srand
+ srand48
+ srandom
+ sscanf
+ stat
+ statvfs
+ stderr
+ stdin
+ stdout
+ stpcpy
+ stpncpy
+ strcasecmp
+ strcat
+ strchr
+ strcmp
+ strcoll
+ strcpy
+ strcspn
+ strdup
+ strerror
+ strerror_r
+ strfmon
+ strftime
+ strlen
+ strncasecmp
+ strncat
+ strncmp
+ strncpy
+ strndup
+ strnlen
+ strpbrk
+ strptime
+ strrchr
+ strsignal
+ strspn
+ strstr
+ strtod
+ strtof
+ strtoimax
+ strtok
+ strtok_r
+ strtol
+ strtoll
+ strtoul
+ strtoull
+ strtoumax
+ strxfrm
+ swab
+ swprintf
+ swscanf
+ symlink
+ symlinkat
+ sync
+ sysconf
+ syslog
+ system
+ tan
+ tanf
+ tanh
+ tanhf
+ tcdrain
+ tcflow
+ tcflush
+ tcgetattr
+ tcgetpgrp
+ tcsendbreak
+ tcsetattr
+ tcsetpgrp
+ tdelete
+ telldir
+ tempnam
+ tfind
+ tgamma
+ tgammaf
+ time
+ timer_create (see chapter "Implementation Notes")
+ timer_delete
+ timer_gettime
+ timer_settime
+ times
+ timezone
+ tmpfile
+ tmpnam
+ toascii
+ tolower
+ toupper
+ towctrans
+ towlower
+ towupper
+ trunc
+ truncate
+ truncf
+ tsearch
+ ttyname
+ ttyname_r
+ twalk
+ tzname
+ tzset
+ umask
+ uname
+ ungetc
+ ungetwc
+ unlink
+ unlinkat
+ unlockpt
+ unsetenv
+ utime
+ utimensat
+ utimes
+ va_arg
+ va_copy
+ va_end
+ va_start
+ vdprintf
+ vfprintf
+ vfscanf
+ vfwprintf
+ vfwscanf
+ vprintf
+ vscanf
+ vsnprintf
+ vsprintf
+ vsscanf
+ vswprintf
+ vswscanf
+ vwprintf
+ vwscanf
+ wait
+ waitpid
+ wcpcpy
+ wcpncpy
+ wcrtomb
+ wcscasecmp
+ wcscat
+ wcschr
+ wcscmp
+ wcscoll
+ wcscpy
+ wcscspn
+ wcsdup
+ wcsftime
+ wcslen
+ wcsncasecmp
+ wcsncat
+ wcsncmp
+ wcsncpy
+ wcsnlen
+ wcsnrtombs
+ wcspbrk
+ wcsrchr
+ wcsrtombs
+ wcsspn
+ wcsstr
+ wcstod
+ wcstof
+ wcstoimax
+ wcstok
+ wcstol
+ wcstoll
+ wcstombs
+ wcstoul
+ wcstoull
+ wcstoumax
+ wcswidth
+ wcsxfrm
+ wctob
+ wctomb
+ wctrans
+ wctype
+ wcwidth
+ wmemchr
+ wmemcmp
+ wmemcpy
+ wmemmove
+ wmemset
+ wordexp
+ wordfree
+ wprintf
+ write
+ writev
+ wscanf
+ y0
+ y1
+ yn
+</screen>
+
+</sect1>
+
+<sect1 id="std-bsd"><title>System interfaces compatible with BSD functions:</title>
+
+<screen>
+ __b64_ntop
+ __b64_pton
+ arc4random
+ arc4random_addrandom
+ arc4random_buf
+ arc4random_stir
+ arc4random_uniform
+ bindresvport
+ bindresvport_sa
+ cfmakeraw
+ cfsetspeed
+ daemon
+ dn_comp
+ dn_expand
+ dn_skipname
+ drem
+ eaccess
+ endusershell
+ err
+ errx
+ finite
+ finitef
+ fiprintf
+ flock (see chapter "Implementation Notes")
+ forkpty
+ fpurge
+ freeifaddrs
+ fstatfs
+ fts_children
+ fts_close
+ fts_get_clientptr
+ fts_get_stream
+ fts_open
+ fts_read
+ fts_set
+ fts_set_clientptr
+ funopen
+ futimes
+ gamma
+ gamma_r
+ gammaf
+ gammaf_r
+ getdtablesize
+ getgrouplist
+ getifaddrs
+ getpagesize
+ getpeereid
+ getprogname
+ getusershell
+ herror
+ hstrerror
+ inet_aton
+ inet_makeaddr
+ inet_netof
+ inet_network
+ initgroups
+ iruserok
+ iruserok_sa
+ login
+ login_tty
+ logout
+ logwtmp
+ madvise
+ mkstemps
+ openpty
+ rcmd
+ rcmd_af
+ reallocf
+ res_close
+ res_init
+ res_mkquery
+ res_nclose
+ res_ninit
+ res_nmkquery
+ res_nquery
+ res_nquerydomain
+ res_nsearch
+ res_nsend
+ res_query
+ res_querydomain
+ res_search
+ res_send
+ revoke
+ rexec
+ rresvport
+ rresvport_af
+ ruserok
+ sbrk
+ setbuffer
+ setgroups
+ setlinebuf
+ setpassent
+ setprogname
+ settimeofday
+ setusershell
+ statfs
+ strcasestr
+ strlcat
+ strlcpy
+ strsep
+ updwtmp
+ valloc
+ verr
+ verrx
+ vhangup (see chapter "Implementation Notes")
+ vsyslog
+ vwarn
+ vwarnx
+ wait3
+ wait4
+ warn
+ warnx
+ wcslcat
+ wcslcpy
+</screen>
+
+</sect1>
+
+<sect1 id="std-gnu"><title>System interfaces compatible with GNU or Linux extensions:</title>
+
+<screen>
+ accept4
+ argz_add
+ argz_add_sep
+ argz_append
+ argz_count
+ argz_create
+ argz_create_sep
+ argz_delete
+ argz_extract
+ argz_insert
+ argz_next
+ argz_replace
+ argz_stringify
+ asnprintf
+ asprintf
+ asprintf_r
+ canonicalize_file_name
+ dremf
+ dup3
+ envz_add
+ envz_entry
+ envz_get
+ envz_merge
+ envz_remove
+ envz_strip
+ error
+ error_at_line
+ euidaccess
+ execvpe
+ exp10
+ exp10f
+ fcloseall
+ fcloseall_r
+ fegetprec
+ fesetprec
+ feenableexcept
+ fedisableexcept
+ fegetexcept
+ ffsl
+ ffsll
+ fgetxattr
+ flistxattr
+ fopencookie
+ fremovexattr
+ fsetxattr
+ get_avphys_pages
+ get_current_dir_name
+ get_phys_pages
+ get_nprocs
+ get_nprocs_conf
+ getmntent_r
+ getopt_long
+ getopt_long_only
+ getpt
+ getxattr
+ lgetxattr
+ listxattr
+ llistxattr
+ lremovexattr
+ lsetxattr
+ memmem
+ mempcpy
+ memrchr
+ mkostemp
+ mkostemps
+ pipe2
+ pow10
+ pow10f
+ ppoll
+ pthread_getattr_np
+ pthread_sigqueue
+ ptsname_r
+ quotactl
+ rawmemchr
+ removexattr
+ scandirat
+ setxattr
+ strchrnul
+ sysinfo
+ tdestroy
+ timegm
+ timelocal
+ updwtmpx
+ utmpxname
+ vasnprintf
+ vasprintf
+ vasprintf_r
+</screen>
+
+</sect1>
+
+<sect1 id="std-solaris"><title>System interfaces compatible with Solaris or SunOS functions:</title>
+
+<screen>
+ __fpurge
+ acl
+ aclcheck
+ aclfrommode
+ aclfrompbits
+ aclfromtext
+ aclsort
+ acltomode
+ acltopbits
+ acltotext
+ endmntent
+ facl
+ futimesat
+ getmntent
+ memalign
+ setmntent
+ xdr_array
+ xdr_bool
+ xdr_bytes
+ xdr_char
+ xdr_double
+ xdr_enum
+ xdr_float
+ xdr_free
+ xdr_hyper
+ xdr_int
+ xdr_int16_t
+ xdr_int32_t
+ xdr_int64_t
+ xdr_int8_t
+ xdr_long
+ xdr_longlong_t
+ xdr_netobj
+ xdr_opaque
+ xdr_pointer
+ xdr_reference
+ xdr_short
+ xdr_sizeof
+ xdr_string
+ xdr_u_char
+ xdr_u_hyper
+ xdr_u_int
+ xdr_u_int16_t
+ xdr_u_int32_t
+ xdr_u_int64_t
+ xdr_u_int8_t
+ xdr_u_long
+ xdr_u_longlong_t
+ xdr_u_short
+ xdr_uint16_t
+ xdr_uint32_t
+ xdr_uint64_t
+ xdr_uint8_t
+ xdr_union
+ xdr_vector
+ xdr_void
+ xdr_wrapstring
+ xdrmem_create
+ xdrrec_create
+ xdrrec_endofrecord
+ xdrrec_eof
+ xdrrec_skiprecord
+ __xdrrec_getrec
+ __xdrrec_setnonblock
+ xdrstdio_create
+</screen>
+
+</sect1>
+
+<sect1 id="std-deprec"><title>Other UNIX system interfaces, deprecated or not in POSIX.1-2008:</title>
+
+<screen>
+ bcmp (POSIX.1-2001, SUSv3)
+ bcopy (SUSv3)
+ bzero (SUSv3)
+ chroot (SUSv2) (see chapter "Implementation Notes")
+ clock_setres (QNX, VxWorks) (see chapter "Implementation Notes")
+ cuserid (POSIX.1-1988, SUSv2)
+ ecvt (SUSv3)
+ endutent (XPG2)
+ fcvt (SUSv3)
+ ftime (SUSv3)
+ gcvt (SUSv3)
+ gethostbyaddr (SUSv3)
+ gethostbyname (SUSv3)
+ gethostbyname2 (first defined in BIND 4.9.4)
+ getpass (SUSv2)
+ getutent (XPG2)
+ getutid (XPG2)
+ getutline (XPG2)
+ getw (SVID)
+ getwd (SUSv3)
+ h_errno (SUSv3)
+ index (SUSv3)
+ mallinfo (SVID)
+ mallopt (SVID)
+ mktemp (SUSv3)
+ on_exit (SunOS)
+ pthread_attr_getstackaddr (SUSv3)
+ pthread_attr_setstackaddr (SUSv3)
+ pthread_continue (XPG2)
+ pthread_getsequence_np (Tru64)
+ pthread_suspend (XPG2)
+ pthread_yield (POSIX.1c drafts)
+ pututline (XPG2)
+ putw (SVID)
+ rindex (SUSv3)
+ scalb (SUSv3)
+ setutent (XPG2)
+ stime (SVID)
+ sys_errlist (BSD)
+ sys_nerr (BSD)
+ sys_siglist (BSD)
+ ttyslot (SUSv2)
+ ualarm (SUSv3)
+ usleep (SUSv3)
+ utmpname (XPG2)
+ vfork (SUSv3) (see chapter "Implementation Notes")
+</screen>
+
+</sect1>
+
+<sect1 id="std-notimpl"><title>NOT implemented system interfaces from the Single Unix Specification, Volume 4:</title>
+
+<screen>
+ acoshl
+ acosl
+ aio_cancel
+ aio_error
+ aio_fsync
+ aio_read
+ aio_return
+ aio_suspend
+ aio_write
+ asinhl
+ asinl
+ atan2l
+ atanhl
+ atanl
+ cabsl
+ cacoshl
+ cacosl
+ cargl
+ casinl
+ catanhl
+ catanl
+ cbrtl
+ ccoshl
+ ccosl
+ ceill
+ cexpl
+ cimagl
+ clogl
+ conjl
+ copysignl
+ coshl
+ cosl
+ cpowl
+ cprojl
+ creall
+ csinhl
+ csinl
+ csqrtl
+ ctanhl
+ ctanl
+ duplocale
+ endnetent
+ erfcl
+ erfl
+ exp2l
+ expl
+ expm1l
+ fabsl
+ fattach
+ fdiml
+ floorl
+ fmal
+ fmaxl
+ fminl
+ fmodl
+ fmtmsg
+ freelocale
+ frexpl
+ getdate
+ getdate_err
+ gethostent
+ getmsg
+ getnetbyaddr
+ getnetbyname
+ getnetent
+ getpmsg
+ hypotl
+ ilogbl
+ isalnum_l
+ isalpha_l
+ isastream
+ isblank_l
+ iscntrl_l
+ isdigit_l
+ isgraph_l
+ islower_l
+ isprint_l
+ ispunct_l
+ isspace_l
+ isupper_l
+ iswalnum_l
+ iswalpha_l
+ iswblank_l
+ iswcntrl_l
+ iswdigit_l
+ iswgraph_l
+ iswlower_l
+ iswprint_l
+ iswpunct_l
+ iswspace_l
+ iswupper_l
+ iswxdigit_l
+ isxdigit_l
+ ldexpl
+ lgammal
+ lio_listio
+ llroundl
+ log10l
+ log1pl
+ log2l
+ logbl
+ logl
+ lroundl
+ mlockall
+ modfl
+ munlockall
+ nanl
+ nearbyintl
+ newlocale
+ nextafterl
+ nexttoward
+ nexttowardf
+ nexttowardl
+ posix_mem_offset
+ posix_trace[...]
+ posix_typed_[...]
+ powl
+ pthread_barrier[...]
+ pthread_mutexattr_getrobust
+ pthread_mutexattr_setrobust
+ pthread_mutex_consistent
+ pthread_mutex_timedlock
+ pthread_rwlock_timedrdlock
+ pthread_rwlock_timedwrlock
+ putmsg
+ reminderl
+ remquol
+ roundl
+ scalblnl
+ scalbnl
+ setnetent
+ sigaltstack
+ sigtimedwait
+ sinhl
+ sinl
+ sockatmark
+ sqrtl
+ strcasecmp_l
+ strcoll_l
+ strfmon_l
+ strncasecmp_l
+ strtold
+ strxfrm_l
+ tanhl
+ tanl
+ tcgetsid
+ tgammal
+ timer_getoverrun
+ tolower_l
+ toupper_l
+ towctrans_l
+ truncl
+ ulimit
+ uselocale
+ waitid
+ wcscasecmp_l
+ wcsncasecmp_l
+ wcstold
+ wcsxfrm_l
+ wctrans_l
+ wctype_l
+</screen>
+
+</sect1>
+
+<sect1 id="std-notes"><title>Implementation Notes</title>
+
+<para><function>chroot</function> only emulates a chroot function call
+by keeping track of the current root and accomodating this in the file
+related function calls. A real chroot functionality is not supported by
+Windows however.</para>
+
+<para><function>clock_nanosleep</function> currently supports only
+CLOCK_REALTIME and CLOCK_MONOTONIC. <function>clock_setres</function>,
+<function>clock_settime</function>, and <function>timer_create</function>
+currently support only CLOCK_REALTIME.</para>
+
+<para>POSIX file locks via <function>fcntl</function> or
+<function>lockf</function>, as well as BSD <function>flock</function> locks
+are advisory locks. They don't interact with Windows mandatory locks, nor
+do POSIX fcntl locks interfere with BSD flock locks or vice versa.</para>
+
+<para>BSD file locks created via <function>flock</function> are only
+propagated to the direct parent process, not to grand parents or sibling
+processes. The locks are only valid in the creating process, its parent
+process, and subsequently started child processes sharing the same file
+descriptor.</para>
+
+<para>In very rare circumstances an application would want to use Windows
+mandatory locks to interact with non-Cygwin Windows processes accessing the
+same file (databases, etc). For these purposes, the entire locking mechanism
+(fcntl/flock/lockf) can be switched to Windows mandatory locks on a
+per-descriptor/per-process basis. For this purpose, use the call
+
+<screen>
+ fcntl (fd, F_LCK_MANDATORY, 1);
+</screen>
+
+After that, all file locks on this descriptor will follow Windows mandatory
+record locking semantics: Locks are per-descriptor/per-process; locks are not
+propagated to child processes, not even via <function>execve</function>;
+no atomic replacement of read locks with write locks and vice versa on the
+same descriptor; locks have to be unlocked exactly as they have been locked.
+</para>
+
+<para><function>fpclassify</function>, <function>isfinite</function>,
+<function>isgreater</function>, <function>isgreaterequal</function>,
+<function>isinf</function>, <function>isless</function>,
+<function>islessequal</function>, <function>islessgreater</function>,
+<function>isnan</function>, <function>isnormal</function>,
+<function>isunordered</function>, and <function>signbit</function>
+only support float and double arguments, not long double arguments.</para>
+
+<para><function>getitimer</function> and <function>setitimer</function>
+only support ITIMER_REAL for now.</para>
+
+<para><function>link</function> will fail on FAT, FAT32, and other filesystems
+not supporting hardlinks, just as on Linux.</para>
+
+<para><function>lseek</function> only works properly on files opened in
+binary mode. On files opened in textmode (via mount mode or explicit
+open flag) its positioning is potentially unreliable.</para>
+
+<para><function>setuid</function> is only safe against reverting the user
+switch after a call to one of the exec(2) functions took place. Windows
+doesn't support a non-revertable user switch within the context of Win32
+processes.</para>
+
+<para><function>vfork</function> just calls <function>fork</function>.</para>
+
+<para><function>vhangup</function> and <function>revoke</function> always
+return -1 and set errno to ENOSYS. <function>grantpt</function> and
+<function>unlockpt</function> always just return 0.</para>
+
+<para>The XSI IPC functions <function>semctl</function>,
+<function>semget</function>, <function>semop</function>,
+<function>shmat</function>, <function>shmctl</function>,
+<function>shmdt</function>, <function>shmget</function>,
+<function>msgctl</function>, <function>msgget</function>,
+<function>msgrcv</function> and <function>msgsnd</function> are only
+available when cygserver is running.</para>
+
+<para>The Linux-specific function <function>quotactl</function> only implements
+what works on Windows: Windows only supports user block quotas on NTFS, no
+group quotas, no inode quotas, no time constraints.</para>
+
+</sect1>
diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index dfeef5680..fe3c3f2a1 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -1,6 +1,6 @@
/* pwdgrp.h
- Copyright 2001, 2002, 2003, 2014 Red Hat inc.
+ Copyright 2001, 2002, 2003 Red Hat inc.
Stuff common to pwd and grp handling.
@@ -10,84 +10,42 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
-#pragma once
-
-#include "sync.h"
-#include "ldap.h"
-#include "miscfuncs.h"
-
/* These functions are needed to allow searching and walking through
the passwd and group lists */
-extern struct passwd *internal_getpwsid (cygpsid &, cyg_ldap * = NULL);
-extern struct passwd *internal_getpwsid_from_db (cygpsid &sid);
-extern struct passwd *internal_getpwnam (const char *, cyg_ldap * = NULL);
-extern struct passwd *internal_getpwuid (uid_t, cyg_ldap * = NULL);
-extern struct group *internal_getgrsid (cygpsid &, cyg_ldap * = NULL);
-extern struct group *internal_getgrsid_from_db (cygpsid &sid);
-extern struct group *internal_getgrgid (gid_t, cyg_ldap * = NULL);
-extern struct group *internal_getgrnam (const char *, cyg_ldap * = NULL);
-
-extern int internal_getgroups (int, gid_t *, cyg_ldap *);
-
-/* These functions are called from mkpasswd/mkgroup via cygwin_internal. */
-void *setpwent_filtered (int enums, PCWSTR enum_tdoms);
-void *getpwent_filtered (void *gr);
-void endpwent_filtered (void *gr);
-void *setgrent_filtered (int enums, PCWSTR enum_tdoms);
-void *getgrent_filtered (void *gr);
-void endgrent_filtered (void *gr);
-
-enum fetch_user_arg_type_t {
- SID_arg,
- NAME_arg,
- ID_arg
-};
-
-struct fetch_user_arg_t
-{
- fetch_user_arg_type_t type;
- union {
- cygpsid *sid;
- const char *name;
- uint32_t id;
- };
- /* Only used in fetch_account_from_file/line. */
- size_t len;
-};
-
-struct pg_pwd
-{
- struct passwd p;
- cygsid sid;
- size_t len;
-};
-
-struct pg_grp
-{
- struct group g;
- cygsid sid;
- size_t len;
-};
+extern struct passwd *internal_getpwsid (cygpsid &);
+extern struct passwd *internal_getpwnam (const char *, bool = FALSE);
+extern struct passwd *internal_getpwuid (uid_t, bool = FALSE);
+extern struct group *internal_getgrsid (cygpsid &);
+extern struct group *internal_getgrgid (gid_t gid, bool = FALSE);
+extern struct group *internal_getgrnam (const char *, bool = FALSE);
+extern struct group *internal_getgrent (int);
+int internal_getgroups (int, gid_t *, cygpsid * = NULL);
+#include "sync.h"
+#include "cygtls.h"
class pwdgrp
{
- friend class pg_ent;
- friend class pw_ent;
- friend class gr_ent;
-
unsigned pwdgrp_buf_elem_size;
- void *pwdgrp_buf;
+ union
+ {
+ passwd **passwd_buf;
+ group **group_buf;
+ void **pwdgrp_buf;
+ };
+ void (pwdgrp::*read) ();
bool (pwdgrp::*parse) ();
- UNICODE_STRING path;
- OBJECT_ATTRIBUTES attr;
- LARGE_INTEGER last_modified;
- char *lptr;
- ULONG curr_lines;
- ULONG max_lines;
+ int etc_ix;
+ UNICODE_STRING upath;
+ PWCHAR path;
+ char *buf, *lptr;
+ int max_lines;
+ bool initialized;
static muto pglock;
bool parse_passwd ();
bool parse_group ();
+ void read_passwd ();
+ void read_group ();
char *add_line (char *);
char *raw_ptr () const {return lptr;}
char *next_str (char);
@@ -106,157 +64,21 @@ class pwdgrp
i = (int) x;
return res;
}
- void *add_account_post_fetch (char *line, bool lock);
- void *add_account_from_file (cygpsid &sid);
- void *add_account_from_file (const char *name);
- void *add_account_from_file (uint32_t id);
- void *add_account_from_windows (cygpsid &sid, cyg_ldap *pldap = NULL);
- void *add_account_from_windows (const char *name, cyg_ldap *pldap = NULL);
- void *add_account_from_windows (uint32_t id, cyg_ldap *pldap = NULL);
- void *add_account_from_cygserver (cygpsid &sid);
- void *add_account_from_cygserver (const char *name);
- void *add_account_from_cygserver (uint32_t id);
- char *fetch_account_from_line (fetch_user_arg_t &arg, const char *line);
- char *fetch_account_from_file (fetch_user_arg_t &arg);
- char *fetch_account_from_windows (fetch_user_arg_t &arg,
- cyg_ldap *pldap = NULL);
- char *fetch_account_from_cygserver (fetch_user_arg_t &arg);
-
-public:
- ULONG cached_users () const { return curr_lines; }
- ULONG cached_groups () const { return curr_lines; }
- POBJECT_ATTRIBUTES file_attr () { return &attr; }
- bool check_file ();
-
- void init_pwd ();
- bool is_passwd () const { return pwdgrp_buf_elem_size == sizeof (pg_pwd); }
- pg_pwd *passwd () const { return (pg_pwd *) pwdgrp_buf; };
- struct passwd *add_user_from_cygserver (cygpsid &sid)
- { return (struct passwd *) add_account_from_cygserver (sid); }
- struct passwd *add_user_from_cygserver (const char *name)
- { return (struct passwd *) add_account_from_cygserver (name); }
- struct passwd *add_user_from_cygserver (uint32_t id)
- { return (struct passwd *) add_account_from_cygserver (id); }
- struct passwd *add_user_from_file (cygpsid &sid)
- { return (struct passwd *) add_account_from_file (sid); }
- struct passwd *add_user_from_file (const char *name)
- { return (struct passwd *) add_account_from_file (name); }
- struct passwd *add_user_from_file (uint32_t id)
- { return (struct passwd *) add_account_from_file (id); }
- struct passwd *add_user_from_windows (cygpsid &sid, cyg_ldap *pldap = NULL)
- { return (struct passwd *) add_account_from_windows (sid, pldap); }
- struct passwd *add_user_from_windows (const char *name,
- cyg_ldap* pldap = NULL)
- { return (struct passwd *) add_account_from_windows (name, pldap); }
- struct passwd *add_user_from_windows (uint32_t id, cyg_ldap *pldap = NULL)
- { return (struct passwd *) add_account_from_windows (id, pldap); }
- struct passwd *find_user (cygpsid &sid);
- struct passwd *find_user (const char *name);
- struct passwd *find_user (uid_t uid);
-
- void init_grp ();
- bool is_group () const { return pwdgrp_buf_elem_size == sizeof (pg_grp); }
- pg_grp *group () const { return (pg_grp *) pwdgrp_buf; };
- struct group *add_group_from_cygserver (cygpsid &sid)
- { return (struct group *) add_account_from_cygserver (sid); }
- struct group *add_group_from_cygserver (const char *name)
- { return (struct group *) add_account_from_cygserver (name); }
- struct group *add_group_from_cygserver (uint32_t id)
- { return (struct group *) add_account_from_cygserver (id); }
- struct group *add_group_from_file (cygpsid &sid)
- { return (struct group *) add_account_from_file (sid); }
- struct group *add_group_from_file (const char *name)
- { return (struct group *) add_account_from_file (name); }
- struct group *add_group_from_file (uint32_t id)
- { return (struct group *) add_account_from_file (id); }
- struct group *add_group_from_windows (cygpsid &sid, cyg_ldap *pldap = NULL)
- { return (struct group *) add_account_from_windows (sid, pldap); }
- struct group *add_group_from_windows (const char *name,
- cyg_ldap *pldap = NULL)
- { return (struct group *) add_account_from_windows (name, pldap); }
- struct group *add_group_from_windows (uint32_t id, cyg_ldap *pldap = NULL)
- { return (struct group *) add_account_from_windows (id, pldap); }
- struct group *find_group (cygpsid &sid);
- struct group *find_group (const char *name);
- struct group *find_group (gid_t gid);
-};
-
-class pg_ent
-{
-protected:
- pwdgrp pg;
- bool group;
- pg_pwd pwd;
- pg_grp grp;
- NT_readline rl;
- cyg_ldap cldap;
- PCHAR buf;
- ULONG cnt;
- ULONG max;
- ULONG_PTR resume;
- int enums; /* ENUM_xxx values defined in sys/cygwin.h. */
- PCWSTR enum_tdoms;
- bool from_files;
- bool from_db;
- enum {
- rewound = 0,
- from_cache,
- from_file,
- from_builtin,
- from_local,
- from_sam,
- from_ad,
- finished
- } state;
-
- void clear_cache ();
- inline bool nss_db_enum_caches () const { return !!(enums & ENUM_CACHE); }
- inline bool nss_db_enum_files () const { return !!(enums & ENUM_FILES); }
- inline bool nss_db_enum_builtin () const { return !!(enums & ENUM_BUILTIN); }
- inline bool nss_db_enum_local () const { return !!(enums & ENUM_LOCAL); }
- inline bool nss_db_enum_primary () const { return !!(enums & ENUM_PRIMARY); }
- inline bool nss_db_enum_tdom (PWCHAR domain)
- {
- if (enums & ENUM_TDOMS_ALL)
- return true;
- if (!(enums & ENUM_TDOMS) || !enum_tdoms || !domain)
- return false;
- for (PCWSTR td = enum_tdoms; td && *td; td = wcschr (td, L'\0'))
- if (!wcscasecmp (td, domain))
- return true;
- return false;
- }
- virtual void *enumerate_caches () = 0;
- virtual void *enumerate_file ();
- virtual void *enumerate_builtin ();
- virtual void *enumerate_local () = 0;
- virtual void *enumerate_sam ();
- virtual void *enumerate_ad ();
public:
- void setent (bool _group, int _enums = 0, PCWSTR _enum_tdoms = NULL);
- void *getent ();
- void endent (bool _group);
-};
+ int curr_lines;
-class pw_ent : public pg_ent
-{
- void *enumerate_caches ();
- void *enumerate_local ();
-public:
- inline void setpwent (int _enums = 0, PCWSTR _enum_tdoms = NULL)
- { setent (false, _enums, _enum_tdoms); }
- struct passwd *getpwent ();
- inline void endpwent () { endent (false); }
-};
+ void load (const wchar_t *);
+ inline void refresh (bool check)
+ {
+ if (!check && initialized)
+ return;
+ if (pglock.acquire () == 1 &&
+ (!initialized || (check && etc::file_changed (etc_ix))))
+ (this->*read) ();
+ pglock.release ();
+ }
-class gr_ent : public pg_ent
-{
- void *enumerate_caches ();
- void *enumerate_local ();
-public:
- inline void setgrent (int _enums = 0, PCWSTR _enum_tdoms = NULL)
- { setent (true, _enums, _enum_tdoms); }
- struct group *getgrent ();
- inline void endgrent () { endent (true); }
+ pwdgrp (passwd *&pbuf);
+ pwdgrp (group *&gbuf);
};
diff --git a/winsup/cygwin/quotactl.cc b/winsup/cygwin/quotactl.cc
index 96c6134e8..fbc66eed3 100644
--- a/winsup/cygwin/quotactl.cc
+++ b/winsup/cygwin/quotactl.cc
@@ -17,6 +17,7 @@ details. */
#include "cygheap.h"
#include "ntdll.h"
#include "tls_pbuf.h"
+#include "pwdgrp.h"
#include <sys/mount.h>
#include <sys/quota.h>
diff --git a/winsup/cygwin/release/1.7.33 b/winsup/cygwin/release/1.7.33
index 28eabfbb3..0875e48a9 100644
--- a/winsup/cygwin/release/1.7.33
+++ b/winsup/cygwin/release/1.7.33
@@ -1,18 +1,6 @@
What's new:
-----------
-- Cygwin can now generate passwd/group entries directly from Windows
- user databases (local SAM or Active Directory), thus allowing to run
- Cygwin without having to create /etc/passwd and /etc/group files.
- Introduce /etc/nsswitch.conf file to configure passwd/group handling.
-
- For bordercase which require to use /etc/passwd and /etc/group files,
- change mkpasswd/mkgroup to generate passwd/group entries compatible
- with the entries read from SAM/AD.
-
-- Add -b/--remove-all option to setfacl to reduce the ACL to only the
- entries representing POSIX permission bits.
-
- /proc/cygdrive is a new symlink pointing to the current cygdrive prefix.
This can be utilized in scripts to access paths via cygdrive prefix, even
if the cygdrive prefix has been changed by the user.
@@ -29,19 +17,12 @@ What's new:
- New API: stime (SVr4).
-- Provide Cygwin documentation (PDFs and HTML) for offline usage in
- /usr/share/doc/cygwin-${version}.
-
What changed:
-------------
- New internal exception handling based on SEH on 64 bit Cygwin.
-- Revamp Solaris ACL implementation to more closely work like POSIX ACLs
- are supposed to work. Finally implement a CLASS_OBJ emulation. Update
- getfacl(1)/setfacl(1) accordingly.
-
- When exec'ing applications, check if $PATH exists and is non-empty. If not,
add PATH variable with Cygwin installation directory as content to Windows
environment to allow loading of Cygwin system DLLs.
@@ -52,9 +33,6 @@ What changed:
- Doug Lea malloc implementation update from 2.8.3 to the latest 2.8.6.
-- The xdr functions are no longer exported for newly built executables.
- Use libtirpc-devel instead.
-
- atexit is now exported as statically linked function from libcygwin.a.
This allows reliable access to the DSO handle of the caller for newly
built executables. The former atexit entry point into the DLL remains
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 51f1c9964..2f7ac278d 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -1,7 +1,7 @@
/* sec_acl.cc: Sun compatible ACL functions.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011, 2012, 2014 Red Hat, Inc.
+ 2011, 2012 Red Hat, Inc.
Written by Corinna Vinschen <corinna@vinschen.de>
@@ -22,6 +22,7 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
+#include "pwdgrp.h"
#include "tls_pbuf.h"
static int
@@ -36,7 +37,6 @@ searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID)
return -1;
}
-/* This function *requires* an acl list sorted with aclsort{32}. */
int
setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
bool &writable)
@@ -48,8 +48,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
return -1;
NTSTATUS status;
- PACL acl;
- BOOLEAN acl_exists, dummy;
+ BOOLEAN dummy;
/* Get owner SID. */
PSID owner_sid;
@@ -71,32 +70,9 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
}
cygsid group (group_sid);
- /* Search for NULL ACE and store state of SUID, SGID and VTX bits. */
- DWORD null_mask = 0;
- if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &acl_exists, &acl,
- &dummy)))
- for (USHORT i = 0; i < acl->AceCount; ++i)
- {
- ACCESS_ALLOWED_ACE *ace;
- if (NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
- {
- cygpsid ace_sid ((PSID) &ace->SidStart);
- if (ace_sid == well_known_null_sid)
- {
- null_mask = ace->Mask;
- break;
- }
- }
- }
-
/* Initialize local security descriptor. */
SECURITY_DESCRIPTOR sd;
RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
-
- /* As in alloc_sd, set SE_DACL_PROTECTED to prevent the DACL from being
- modified by inheritable ACEs. */
- RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
-
status = RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
if (!NT_SUCCESS (status))
{
@@ -111,7 +87,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
}
/* Fill access control list. */
- acl = (PACL) tp.w_get ();
+ PACL acl = (PACL) tp.w_get ();
size_t acl_len = sizeof (ACL);
int ace_off = 0;
@@ -119,102 +95,22 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
struct passwd *pw;
struct group *gr;
int pos;
- cyg_ldap cldap;
RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION);
writable = false;
- /* Pre-compute owner, group, and other permissions to allow creating
- matching deny ACEs as in alloc_sd. */
- DWORD owner_allow = 0, group_allow = 0, other_allow = 0;
- PDWORD allow;
- for (int i = 0; i < nentries; ++i)
- {
- switch (aclbufp[i].a_type)
- {
- case USER_OBJ:
- allow = &owner_allow;
- *allow = STANDARD_RIGHTS_ALL;
- break;
- case GROUP_OBJ:
- allow = &group_allow;
- break;
- case OTHER_OBJ:
- allow = &other_allow;
- break;
- default:
- continue;
- }
- *allow |= STANDARD_RIGHTS_READ | SYNCHRONIZE
- | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
- if (aclbufp[i].a_perm & S_IROTH)
- *allow |= FILE_GENERIC_READ;
- if (aclbufp[i].a_perm & S_IWOTH)
- {
- *allow |= FILE_GENERIC_WRITE;
- writable = true;
- }
- if (aclbufp[i].a_perm & S_IXOTH)
- *allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
- /* Keep S_ISVTX rule in sync with alloc_sd. */
- if (pc.isdir ()
- && (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
- && (aclbufp[i].a_type == USER_OBJ
- || !(null_mask & FILE_READ_DATA)))
- *allow |= FILE_DELETE_CHILD;
- aclbufp[i].a_type = 0;
- }
- bool isownergroup = (owner_sid == group_sid);
- DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
- owner_deny &= ~(STANDARD_RIGHTS_READ
- | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES);
- DWORD group_deny = ~group_allow & other_allow;
- group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES);
-
- /* Set deny ACE for owner. */
- if (owner_deny
- && !add_access_denied_ace (acl, ace_off++, owner_deny,
- owner_sid, acl_len, NO_INHERITANCE))
- return -1;
- /* 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 -1;
- /* Set allow ACE for owner. */
- if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
- owner_sid, acl_len, NO_INHERITANCE))
- return -1;
- /* 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 -1;
- /* Set allow ACE for group. */
- if (!isownergroup
- && !add_access_allowed_ace (acl, ace_off++, group_allow,
- group_sid, acl_len, NO_INHERITANCE))
- return -1;
- /* Set allow ACE for everyone. */
- if (!add_access_allowed_ace (acl, ace_off++, other_allow,
- well_known_world_sid, acl_len, NO_INHERITANCE))
- return -1;
- /* If a NULL ACE exists, copy it verbatim. */
- if (null_mask)
- if (!add_access_allowed_ace (acl, ace_off++, null_mask, well_known_null_sid,
- acl_len, NO_INHERITANCE))
- return -1;
for (int i = 0; i < nentries; ++i)
{
DWORD allow;
- /* Skip invalidated entries. */
- if (!aclbufp[i].a_type)
- continue;
-
- allow = STANDARD_RIGHTS_READ
- | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
+ /* Owner has more standard rights set. */
+ if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
+ allow = STANDARD_RIGHTS_ALL
+ | (pc.fs_is_samba ()
+ ? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES));
+ else
+ allow = STANDARD_RIGHTS_READ
+ | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
if (aclbufp[i].a_perm & S_IROTH)
allow |= FILE_GENERIC_READ;
if (aclbufp[i].a_perm & S_IWOTH)
@@ -224,10 +120,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
}
if (aclbufp[i].a_perm & S_IXOTH)
allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
- /* Keep S_ISVTX rule in sync with alloc_sd. */
- if (pc.isdir ()
- && (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
- && !(null_mask & FILE_READ_DATA))
+ if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
allow |= FILE_DELETE_CHILD;
/* Set inherit property. */
DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
@@ -240,7 +133,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
* inheritance bits is created.
*/
if (!(aclbufp[i].a_type & ACL_DEFAULT)
- && aclbufp[i].a_type & (USER|GROUP)
+ && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
&& (pos = searchace (aclbufp + i + 1, nentries - i - 1,
aclbufp[i].a_type | ACL_DEFAULT,
(aclbufp[i].a_type & (USER|GROUP))
@@ -248,11 +141,16 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
&& aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
{
inheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
- /* invalidate the corresponding default entry. */
- aclbufp[i + 1 + pos].a_type = 0;
+ /* This invalidates the corresponding default entry. */
+ aclbufp[i + 1 + pos].a_type = USER|GROUP|ACL_DEFAULT;
}
switch (aclbufp[i].a_type)
{
+ case USER_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ owner, acl_len, inheritance))
+ return -1;
+ break;
case DEF_USER_OBJ:
if (!add_access_allowed_ace (acl, ace_off++, allow,
well_known_creator_owner_sid, acl_len, inheritance))
@@ -260,7 +158,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
break;
case USER:
case DEF_USER:
- if (!(pw = internal_getpwuid (aclbufp[i].a_id, &cldap))
+ if (!(pw = internal_getpwuid (aclbufp[i].a_id))
|| !sid.getfrompw (pw))
{
set_errno (EINVAL);
@@ -270,6 +168,11 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
sid, acl_len, inheritance))
return -1;
break;
+ case GROUP_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ group, acl_len, inheritance))
+ return -1;
+ break;
case DEF_GROUP_OBJ:
if (!add_access_allowed_ace (acl, ace_off++, allow,
well_known_creator_group_sid, acl_len, inheritance))
@@ -277,7 +180,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
break;
case GROUP:
case DEF_GROUP:
- if (!(gr = internal_getgrgid (aclbufp[i].a_id, &cldap))
+ if (!(gr = internal_getgrgid (aclbufp[i].a_id))
|| !sid.getfromgr (gr))
{
set_errno (EINVAL);
@@ -287,11 +190,13 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
sid, acl_len, inheritance))
return -1;
break;
+ case OTHER_OBJ:
case DEF_OTHER_OBJ:
if (!add_access_allowed_ace (acl, ace_off++, allow,
well_known_world_sid,
acl_len, inheritance))
return -1;
+ break;
}
}
/* Set AclSize to computed value. */
@@ -378,7 +283,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
BOOLEAN dummy;
uid_t uid;
gid_t gid;
- cyg_ldap cldap;
status = RtlGetOwnerSecurityDescriptor (sd, (PSID *) &owner_sid, &dummy);
if (!NT_SUCCESS (status))
@@ -386,7 +290,7 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
__seterrno_from_nt_status (status);
return -1;
}
- uid = owner_sid.get_uid (&cldap);
+ uid = owner_sid.get_uid ();
status = RtlGetGroupSecurityDescriptor (sd, (PSID *) &group_sid, &dummy);
if (!NT_SUCCESS (status))
@@ -394,7 +298,7 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
__seterrno_from_nt_status (status);
return -1;
}
- gid = group_sid.get_gid (&cldap);
+ gid = group_sid.get_gid ();
aclent_t lacl[MAX_ACL_ENTRIES];
memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t));
@@ -404,6 +308,9 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
lacl[1].a_id = gid;
lacl[2].a_type = OTHER_OBJ;
lacl[2].a_id = ILLEGAL_GID;
+ lacl[3].a_type = CLASS_OBJ;
+ lacl[3].a_id = ILLEGAL_GID;
+ lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
PACL acl;
BOOLEAN acl_exists;
@@ -416,11 +323,9 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
}
int pos, i, types_def = 0;
- int pgrp_pos = 1, def_pgrp_pos = -1;
- mode_t class_perm = 0, def_class_perm = 0;
if (!acl_exists || !acl)
- for (pos = 0; pos < 3; ++pos)
+ for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */
lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
else
{
@@ -435,11 +340,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
int id;
int type = 0;
- if (ace_sid == well_known_null_sid)
- {
- /* Simply ignore. */
- continue;
- }
if (ace_sid == well_known_world_sid)
{
type = OTHER_OBJ;
@@ -457,30 +357,25 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
}
else if (ace_sid == well_known_creator_group_sid)
{
- type = DEF_GROUP_OBJ;
+ type = GROUP_OBJ | ACL_DEFAULT;
types_def |= type;
id = ILLEGAL_GID;
}
else if (ace_sid == well_known_creator_owner_sid)
{
- type = DEF_USER_OBJ;
+ type = USER_OBJ | ACL_DEFAULT;
types_def |= type;
id = ILLEGAL_GID;
}
else
- id = ace_sid.get_id (TRUE, &type, &cldap);
+ id = ace_sid.get_id (true, &type);
if (!type)
continue;
if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE || type & ACL_DEFAULT))
{
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
- {
- getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
- /* Fix up CLASS_OBJ value. */
- if (type == USER || type == GROUP)
- class_perm |= lacl[pos].a_perm;
- }
+ getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
}
if ((ace->Header.AceFlags
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))
@@ -493,31 +388,13 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
type |= ACL_DEFAULT;
types_def |= type;
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
- {
- getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
- /* Fix up DEF_CLASS_OBJ value. */
- if (type == DEF_USER || type == DEF_GROUP)
- def_class_perm |= lacl[pos].a_perm;
- /* And note the position of the DEF_GROUP_OBJ entry. */
- else if (type == DEF_GROUP_OBJ)
- def_pgrp_pos = pos;
- }
+ getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
}
}
- /* If secondary user and group entries exist in the ACL, fake a matching
- CLASS_OBJ entry. The CLASS_OBJ permissions are the or'ed permissions
- of the primary group permissions and all secondary user and group
- permissions. */
- if (class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
- {
- lacl[pos].a_type = CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
- lacl[pos].a_perm = class_perm | lacl[pgrp_pos].a_perm;
- }
- /* Ensure that the default acl contains at least
- DEF_(USER|GROUP|OTHER)_OBJ entries. */
if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
{
+ /* Ensure that the default acl contains at
+ least DEF_(USER|GROUP|OTHER)_OBJ entries. */
if (!(types_def & USER_OBJ))
{
lacl[pos].a_type = DEF_USER_OBJ;
@@ -530,8 +407,6 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
lacl[pos].a_type = DEF_GROUP_OBJ;
lacl[pos].a_id = gid;
lacl[pos].a_perm = lacl[1].a_perm;
- /* Note the position of the DEF_GROUP_OBJ entry. */
- def_pgrp_pos = pos;
pos++;
}
if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
@@ -541,18 +416,13 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
lacl[pos].a_perm = lacl[2].a_perm;
pos++;
}
- }
- /* If secondary user default and group default entries exist in the ACL,
- fake a matching DEF_CLASS_OBJ entry. The DEF_CLASS_OBJ permissions are
- the or'ed permissions of the primary group default permissions and all
- secondary user and group default permissions. */
- if (def_class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
- {
- lacl[pos].a_type = DEF_CLASS_OBJ;
- lacl[pos].a_id = ILLEGAL_GID;
- lacl[pos].a_perm = def_class_perm;
- if (def_pgrp_pos >= 0)
- lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
+ /* Include DEF_CLASS_OBJ if any named default ace exists. */
+ if ((types_def & (USER|GROUP)) && pos < MAX_ACL_ENTRIES)
+ {
+ lacl[pos].a_type = DEF_CLASS_OBJ;
+ lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
+ }
}
}
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
@@ -628,7 +498,6 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
bool has_other_obj = false;
bool has_class_obj = false;
bool has_ug_objs __attribute__ ((unused)) = false;
- bool has_def_objs __attribute__ ((unused)) = false;
bool has_def_user_obj __attribute__ ((unused)) = false;
bool has_def_group_obj = false;
bool has_def_other_obj = false;
@@ -693,7 +562,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
*which = pos;
return USER_ERROR;
}
- has_def_objs = has_def_user_obj = true;
+ has_def_user_obj = true;
break;
case DEF_GROUP_OBJ:
if (has_def_group_obj)
@@ -702,7 +571,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
*which = pos;
return GRP_ERROR;
}
- has_def_objs = has_def_group_obj = true;
+ has_def_group_obj = true;
break;
case DEF_OTHER_OBJ:
if (has_def_other_obj)
@@ -711,7 +580,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
*which = pos;
return OTHER_ERROR;
}
- has_def_objs = has_def_other_obj = true;
+ has_def_other_obj = true;
break;
case DEF_CLASS_OBJ:
if (has_def_class_obj)
@@ -720,7 +589,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
*which = pos;
return CLASS_ERROR;
}
- has_def_objs = has_def_class_obj = true;
+ has_def_class_obj = true;
break;
case DEF_USER:
case DEF_GROUP:
@@ -731,7 +600,7 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
*which = pos2;
return DUPLICATE_ERROR;
}
- has_def_objs = has_def_ug_objs = true;
+ has_def_ug_objs = true;
break;
default:
return ENTRY_ERROR;
@@ -739,10 +608,11 @@ aclcheck32 (aclent_t *aclbufp, int nentries, int *which)
if (!has_user_obj
|| !has_group_obj
|| !has_other_obj
- || (has_def_objs
- && (!has_def_user_obj || !has_def_group_obj || !has_def_other_obj))
+#if 0
+ /* These checks are not ok yet since CLASS_OBJ isn't fully implemented. */
|| (has_ug_objs && !has_class_obj)
|| (has_def_ug_objs && !has_def_class_obj)
+#endif
)
{
if (which)
@@ -767,10 +637,7 @@ extern "C" int
aclsort32 (int nentries, int, aclent_t *aclbufp)
{
if (aclcheck32 (aclbufp, nentries, NULL))
- {
- set_errno (EINVAL);
- return -1;
- }
+ return -1;
if (!aclbufp || nentries < 1)
{
set_errno (EINVAL);
@@ -970,7 +837,6 @@ aclfromtext32 (char *acltextp, int *)
int pos = 0;
strcpy (buf, acltextp);
char *lasts;
- cyg_ldap cldap;
for (char *c = strtok_r (buf, ",", &lasts);
c;
c = strtok_r (NULL, ",", &lasts))
@@ -990,7 +856,7 @@ aclfromtext32 (char *acltextp, int *)
c += 5;
if (isalpha (*c))
{
- struct passwd *pw = internal_getpwnam (c, &cldap);
+ struct passwd *pw = internal_getpwnam (c);
if (!pw)
{
set_errno (EINVAL);
@@ -1018,7 +884,7 @@ aclfromtext32 (char *acltextp, int *)
c += 5;
if (isalpha (*c))
{
- struct group *gr = internal_getgrnam (c, &cldap);
+ struct group *gr = internal_getgrnam (c);
if (!gr)
{
set_errno (EINVAL);
diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc
index 3615588ef..2cdce8bd4 100644
--- a/winsup/cygwin/sec_auth.cc
+++ b/winsup/cygwin/sec_auth.cc
@@ -14,6 +14,7 @@ details. */
#include <wchar.h>
#include <wininet.h>
#include <ntsecapi.h>
+#include <dsgetdc.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
@@ -24,6 +25,7 @@ details. */
#include "tls_pbuf.h"
#include <lm.h>
#include <iptypes.h>
+#include "pwdgrp.h"
#include "cyglsa.h"
#include "cygserver_setpwd.h"
#include <cygwin/version.h>
@@ -219,27 +221,28 @@ lsa_close_policy (HANDLE lsa)
}
bool
-get_logon_server (PWCHAR domain, WCHAR *server, ULONG flags)
+get_logon_server (PWCHAR domain, WCHAR *server, bool rediscovery)
{
DWORD ret;
PDOMAIN_CONTROLLER_INFOW pci;
+ DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
/* Empty domain is interpreted as local system */
- if (cygheap->dom.init ()
- && (!domain[0]
- || !wcscasecmp (domain, cygheap->dom.account_flat_name ())))
+ if ((GetComputerNameW (server + 2, &size)) &&
+ (!wcscasecmp (domain, server + 2) || !domain[0]))
{
- wcpcpy (wcpcpy (server, L"\\\\"), cygheap->dom.account_flat_name ());
+ server[0] = server[1] = L'\\';
return true;
}
/* Try to get any available domain controller for this domain */
- ret = DsGetDcNameW (NULL, domain, NULL, NULL, flags, &pci);
+ ret = DsGetDcNameW (NULL, domain, NULL, NULL,
+ rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
if (ret == ERROR_SUCCESS)
{
wcscpy (server, pci->DomainControllerName);
NetApiBufferFree (pci);
- debug_printf ("DC: server: %W", server);
+ debug_printf ("DC: rediscovery: %d, server: %W", rediscovery, server);
return true;
}
__seterrno_from_win_error (ret);
@@ -278,7 +281,7 @@ get_user_groups (WCHAR *logonserver, cygsidlist &grp_list,
for (DWORD i = 0; i < cnt; ++i)
{
cygsid gsid;
- DWORD glen = SECURITY_MAX_SID_SIZE;
+ DWORD glen = MAX_SID_LEN;
WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
DWORD dlen = sizeof (dom);
SID_NAME_USE use = SidTypeInvalid;
@@ -326,7 +329,7 @@ get_user_local_groups (PWCHAR logonserver, PWCHAR domain,
for (DWORD i = 0; i < cnt; ++i)
{
cygsid gsid;
- DWORD glen = SECURITY_MAX_SID_SIZE;
+ DWORD glen = MAX_SID_LEN;
WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
DWORD domlen = MAX_DOMAIN_NAME_LEN + 1;
@@ -362,7 +365,7 @@ get_user_local_groups (PWCHAR logonserver, PWCHAR domain,
if (bg_ptr)
{
wcscpy (bg_ptr, dg_ptr);
- glen = SECURITY_MAX_SID_SIZE;
+ glen = MAX_SID_LEN;
domlen = MAX_DOMAIN_NAME_LEN + 1;
if (LookupAccountNameW (NULL, builtin_grp, gsid, &glen,
dom, &domlen, &use))
@@ -395,6 +398,28 @@ sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
}
static void
+get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
+{
+ struct group *gr;
+ cygsid gsid;
+
+ for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+ {
+ if (gr->gr_gid == 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 += gsid;
+
+ }
+}
+
+static void
get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
LUID auth_luid, int &auth_pos)
{
@@ -455,6 +480,7 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
if (well_known_system_sid == usersid)
{
grp_list *= well_known_admins_sid;
+ get_unix_group_sidlist (pw, grp_list);
return true;
}
@@ -466,16 +492,12 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
__seterrno ();
return false;
}
- /* If the SID does NOT start with S-1-5-21, the domain is some builtin
- domain. The search for a logon server and fetching group accounts
- is moot. */
- if (sid_id_auth (usersid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (usersid, 0) == SECURITY_NT_NON_UNIQUE
- && get_logon_server (domain, server, DS_IS_FLAT_NAME))
- {
- get_user_groups (server, grp_list, user, domain);
- get_user_local_groups (server, domain, grp_list, user);
- }
+ if (get_logon_server (domain, server, false)
+ && !get_user_groups (server, grp_list, user, domain)
+ && get_logon_server (domain, server, true))
+ get_user_groups (server, grp_list, user, domain);
+ get_user_local_groups (server, domain, grp_list, user);
+ get_unix_group_sidlist (pw, grp_list);
return true;
}
@@ -683,7 +705,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
*pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
}
/* Verify usersid */
- cygsid tok_usersid (NO_SID);
+ cygsid tok_usersid = NO_SID;
status = NtQueryInformationToken (token, TokenUser, &tok_usersid,
sizeof tok_usersid, &size);
if (!NT_SUCCESS (status))
@@ -695,8 +717,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
is not well_known_null_sid, it must match pgrpsid */
if (intern && !groups.issetgroups ())
{
- const DWORD sd_buf_siz = SECURITY_MAX_SID_SIZE
- + sizeof (SECURITY_DESCRIPTOR);
+ 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);
NTSTATUS status;
@@ -737,26 +758,35 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
if (groups.issetgroups ()) /* setgroups was called */
{
- cygpsid gsid;
+ cygsid gsid;
+ struct group *gr;
bool saw[groups.sgsids.count ()];
-
- /* Check that all groups in the setgroups () list are in the token.
- A token created through ADVAPI should be allowed to contain more
- groups than requested through setgroups(), especially since Vista
- and the addition of integrity groups. */
memset (saw, 0, sizeof(saw));
- for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
- {
- gsid = groups.sgsids.sids[gidx];
- if (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;
- }
- }
+
+ /* 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;
+#if 0
+ /* With this `else', verify_token returns false if we find
+ groups in the token, which are not in the group list set
+ with setgroups(). That's rather dangerous. What we're
+ really interested in is that all groups in the setgroups()
+ list are in the token. A token created through ADVAPI
+ should be allowed to contain more groups than requested
+ through setgroups(), esecially since Vista and the
+ addition of integrity groups. So we disable this statement
+ for now. */
+ else if (gsid != well_known_world_sid
+ && gsid != usersid)
+ goto done;
+#endif
+ }
/* user.sgsids groups must be in the token, except for builtin groups.
These can be different on domain member machines compared to
domain controllers, so these builtin groups may be validly missing
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index 946e78a8e..2d81cbd38 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -1,7 +1,7 @@
/* sec_helper.cc: NT security helper functions
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2011, 2012, 2013 Red Hat, Inc.
Written by Corinna Vinschen <corinna@vinschen.de>
@@ -22,8 +22,8 @@ details. */
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
+#include "pwdgrp.h"
#include "ntdll.h"
-#include "ldap.h"
/* General purpose security attribute objects for global use. */
static NO_COPY_RO SECURITY_DESCRIPTOR null_sdp =
@@ -66,10 +66,6 @@ MKSID (well_known_this_org_sid, "S-1-5-15",
SECURITY_NT_AUTHORITY, 1, 15);
MKSID (well_known_system_sid, "S-1-5-18",
SECURITY_NT_AUTHORITY, 1, SECURITY_LOCAL_SYSTEM_RID);
-MKSID (well_known_local_service_sid, "S-1-5-19",
- SECURITY_NT_AUTHORITY, 1, SECURITY_LOCAL_SERVICE_RID);
-MKSID (well_known_network_service_sid, "S-1-5-20",
- SECURITY_NT_AUTHORITY, 1, SECURITY_NETWORK_SERVICE_RID);
MKSID (well_known_builtin_sid, "S-1-5-32",
SECURITY_NT_AUTHORITY, 1, SECURITY_BUILTIN_DOMAIN_RID);
MKSID (well_known_admins_sid, "S-1-5-32-544",
@@ -78,11 +74,6 @@ MKSID (well_known_admins_sid, "S-1-5-32-544",
MKSID (well_known_users_sid, "S-1-5-32-545",
SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_USERS);
-MKSID (trusted_installer_sid,
- "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464",
- SECURITY_NT_AUTHORITY, SECURITY_SERVICE_ID_RID_COUNT,
- SECURITY_SERVICE_ID_BASE_RID, 956008885U, 3418522649U, 1831038044U,
- 1853292631U, 2271478464U);
MKSID (mandatory_medium_integrity_sid, "S-1-16-8192",
SECURITY_MANDATORY_LABEL_AUTHORITY, 1, SECURITY_MANDATORY_MEDIUM_RID);
MKSID (mandatory_high_integrity_sid, "S-1-16-12288",
@@ -102,7 +93,7 @@ cygpsid::operator== (const char *nsidstr) const
}
uid_t
-cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
+cygpsid::get_id (BOOL search_grp, int *type)
{
/* First try to get SID from group, then passwd */
uid_t id = ILLEGAL_UID;
@@ -112,27 +103,9 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
struct group *gr;
if (cygheap->user.groups.pgsid == psid)
id = myself->gid;
- else if (sid_id_auth (psid) == 22)
- {
- /* Samba UNIX group. Try to map to Cygwin gid. If there's no
- mapping in the cache, try to fetch it from the configured
- RFC 2307 domain (see last comment in cygheap_domain_info::init()
- for more information) and add it to the mapping cache. */
- gid_t gid = sid_sub_auth_rid (psid);
- gid_t map_gid = cygheap->ugid_cache.get_gid (gid);
- if (map_gid == ILLEGAL_GID)
- {
- if (pldap->open (cygheap->dom.get_rfc2307_domain ()) == NO_ERROR)
- map_gid = pldap->remap_gid (gid);
- if (map_gid == ILLEGAL_GID)
- map_gid = MAP_UNIX_TO_CYGWIN_ID (gid);
- cygheap->ugid_cache.add_gid (gid, map_gid);
- }
- id = (uid_t) map_gid;
- }
- else if ((gr = internal_getgrsid (*this, pldap)))
+ else if ((gr = internal_getgrsid (*this)))
id = gr->gr_gid;
- if ((gid_t) id != ILLEGAL_GID)
+ if (id != ILLEGAL_UID)
{
if (type)
*type = GROUP;
@@ -144,22 +117,7 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
struct passwd *pw;
if (*this == cygheap->user.sid ())
id = myself->uid;
- else if (sid_id_auth (psid) == 22)
- {
- /* Samba UNIX user. See comment above. */
- uid_t uid = sid_sub_auth_rid (psid);
- uid_t map_uid = cygheap->ugid_cache.get_uid (uid);
- if (map_uid == ILLEGAL_UID)
- {
- if (pldap->open (cygheap->dom.get_rfc2307_domain ()) == NO_ERROR)
- map_uid = pldap->remap_uid (uid);
- if (map_uid == ILLEGAL_UID)
- map_uid = MAP_UNIX_TO_CYGWIN_ID (uid);
- cygheap->ugid_cache.add_uid (uid, map_uid);
- }
- id = map_uid;
- }
- else if ((pw = internal_getpwsid (*this, pldap)))
+ else if ((pw = internal_getpwsid (*this)))
id = pw->pw_uid;
if (id != ILLEGAL_UID && type)
*type = USER;
@@ -168,7 +126,7 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
}
PWCHAR
-cygpsid::pstring (PWCHAR nsidstr) const
+cygpsid::string (PWCHAR nsidstr) const
{
UNICODE_STRING sid;
@@ -176,19 +134,11 @@ cygpsid::pstring (PWCHAR nsidstr) const
return NULL;
RtlInitEmptyUnicodeString (&sid, nsidstr, 256);
RtlConvertSidToUnicodeString (&sid, psid, FALSE);
- return nsidstr + sid.Length / sizeof (WCHAR);
-}
-
-PWCHAR
-cygpsid::string (PWCHAR nsidstr) const
-{
- if (pstring (nsidstr))
- return nsidstr;
- return NULL;
+ return nsidstr;
}
char *
-cygpsid::pstring (char *nsidstr) const
+cygpsid::string (char *nsidstr) const
{
char *t;
DWORD i;
@@ -197,18 +147,10 @@ cygpsid::pstring (char *nsidstr) const
return NULL;
strcpy (nsidstr, "S-1-");
t = nsidstr + sizeof ("S-1-") - 1;
- t += __small_sprintf (t, "%u", sid_id_auth (psid));
- for (i = 0; i < sid_sub_auth_count (psid); ++i)
- t += __small_sprintf (t, "-%lu", sid_sub_auth (psid, i));
- return t;
-}
-
-char *
-cygpsid::string (char *nsidstr) const
-{
- if (pstring (nsidstr))
- return nsidstr;
- return NULL;
+ t += __small_sprintf (t, "%u", RtlIdentifierAuthoritySid (psid)->Value[5]);
+ for (i = 0; i < *RtlSubAuthorityCountSid (psid); ++i)
+ t += __small_sprintf (t, "-%lu", *RtlSubAuthoritySid (psid, i));
+ return nsidstr;
}
PSID
@@ -218,7 +160,7 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known)
SID_IDENTIFIER_AUTHORITY sid_auth = { SECURITY_NULL_SID_AUTHORITY };
# define SECURITY_NT_AUTH 5
- if (s > 255 || cnt < 1 || cnt > SID_MAX_SUB_AUTHORITIES)
+ if (s > 255 || cnt < 1 || cnt > 8)
{
psid = NO_SID;
return NULL;
@@ -226,9 +168,8 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known)
sid_auth.Value[5] = s;
set ();
RtlInitializeSid (psid, &sid_auth, cnt);
- PISID dsid = (PISID) psid;
for (i = 0; i < cnt; ++i)
- dsid->SubAuthority[i] = r[i];
+ memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD));
/* If the well_known flag isn't set explicitely, we check the SID
for being a well-known SID ourselves. That's necessary because this
cygsid is created from a SID string, usually from /etc/passwd or
@@ -244,34 +185,16 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known)
}
const PSID
-cygsid::getfromstr (PCWSTR nsidstr, bool well_known)
-{
- PWCHAR lasts;
- DWORD s, cnt = 0;
- DWORD r[SID_MAX_SUB_AUTHORITIES];
-
- if (nsidstr && !wcsncmp (nsidstr, L"S-1-", 4))
- {
- s = wcstoul (nsidstr + 4, &lasts, 10);
- while (cnt < SID_MAX_SUB_AUTHORITIES && *lasts == '-')
- r[cnt++] = wcstoul (lasts + 1, &lasts, 10);
- if (!*lasts)
- return get_sid (s, cnt, r, well_known);
- }
- return psid = NO_SID;
-}
-
-const PSID
cygsid::getfromstr (const char *nsidstr, bool well_known)
{
char *lasts;
DWORD s, cnt = 0;
- DWORD r[SID_MAX_SUB_AUTHORITIES];
+ DWORD r[8];
if (nsidstr && !strncmp (nsidstr, "S-1-", 4))
{
s = strtoul (nsidstr + 4, &lasts, 10);
- while (cnt < SID_MAX_SUB_AUTHORITIES && *lasts == '-')
+ while (cnt < 8 && *lasts == '-')
r[cnt++] = strtoul (lasts + 1, &lasts, 10);
if (!*lasts)
return get_sid (s, cnt, r, well_known);
@@ -338,24 +261,41 @@ cygsidlist::add (const PSID nsi, bool well_known)
bool
get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gidret)
{
- BOOL ret = false;
- cyg_ldap cldap;
+ struct passwd *pw;
+ struct group *gr = NULL;
+ bool ret = false;
owner_sid.debug_print ("get_sids_info: owner SID =");
group_sid.debug_print ("get_sids_info: group SID =");
- *uidret = owner_sid.get_uid (&cldap);
- *gidret = group_sid.get_gid (&cldap);
- if (*uidret == myself->uid)
+ if (group_sid == cygheap->user.groups.pgsid)
+ *gidret = myself->gid;
+ else if ((gr = internal_getgrsid (group_sid)))
+ *gidret = gr->gr_gid;
+ else
+ *gidret = ILLEGAL_GID;
+
+ if (owner_sid == cygheap->user.sid ())
{
+ *uidret = myself->uid;
if (*gidret == myself->gid)
- ret = TRUE;
+ ret = true;
else
- CheckTokenMembership (cygheap->user.issetuid ()
- ? cygheap->user.imp_token () : NULL,
- group_sid, &ret);
+ ret = (internal_getgroups (0, NULL, &group_sid) > 0);
+ }
+ else if ((pw = internal_getpwsid (owner_sid)))
+ {
+ *uidret = pw->pw_uid;
+ if (gr || (*gidret != ILLEGAL_GID
+ && (gr = internal_getgrgid (*gidret))))
+ for (int idx = 0; gr->gr_mem[idx]; ++idx)
+ if ((ret = strcasematch (pw->pw_name, gr->gr_mem[idx])))
+ break;
}
- return (bool) ret;
+ else
+ *uidret = ILLEGAL_UID;
+
+ return ret;
}
PSECURITY_DESCRIPTOR
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 4c46e05d9..606920da0 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -1,7 +1,7 @@
/* security.cc: NT file access control functions
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
@@ -23,6 +23,7 @@ details. */
#include "pinfo.h"
#include "cygheap.h"
#include "ntdll.h"
+#include "pwdgrp.h"
#include "tls_pbuf.h"
#include <aclapi.h>
@@ -314,21 +315,6 @@ get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
*flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
| ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
}
- else if (flags == &allow)
- {
- /* Simplified computation of additional group permissions based on
- the CLASS_OBJ value. CLASS_OBJ represents the or'ed value of
- the primary group permissions and all secondary user and group
- permissions. FIXME: This only takes ACCESS_ALLOWED_ACEs into
- account. The computation with additional ACCESS_DENIED_ACE
- handling is much more complicated. */
- if (ace->Mask & FILE_READ_BITS)
- *flags |= S_IRGRP;
- if (ace->Mask & FILE_WRITE_BITS)
- *flags |= S_IWGRP;
- if (ace->Mask & FILE_EXEC_BITS)
- *flags |= S_IXGRP;
- }
}
*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
if (owner_sid && group_sid && RtlEqualSid (owner_sid, group_sid)
@@ -1062,95 +1048,6 @@ check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
return ret;
}
-/* Samba override. Check security descriptor for Samba UNIX user and group
- accounts and check if we have an RFC 2307 mapping to a Windows account.
- Create a new security descriptor with all of the UNIX accounts with
- valid mapping replaced with their Windows counterpart. */
-static void
-convert_samba_sd (security_descriptor &sd_ret)
-{
- NTSTATUS status;
- BOOLEAN dummy;
- PSID sid;
- cygsid owner;
- cygsid group;
- SECURITY_DESCRIPTOR sd;
- cyg_ldap cldap;
- tmp_pathbuf tp;
- PACL acl, oacl;
- size_t acl_len;
- PACCESS_ALLOWED_ACE ace;
-
- if (!NT_SUCCESS (RtlGetOwnerSecurityDescriptor (sd_ret, &sid, &dummy)))
- return;
- owner = sid;
- if (!NT_SUCCESS (RtlGetGroupSecurityDescriptor (sd_ret, &sid, &dummy)))
- return;
- group = sid;
-
- if (sid_id_auth (owner) == 22)
- {
- struct passwd *pwd;
- uid_t uid = owner.get_uid (&cldap);
- if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
- owner.getfrompw (pwd);
- }
- if (sid_id_auth (group) == 22)
- {
- struct group *grp;
- gid_t gid = group.get_gid (&cldap);
- if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
- group.getfromgr (grp);
- }
-
- if (!NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &dummy,
- &oacl, &dummy)))
- return;
- acl = (PACL) tp.w_get ();
- RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION);
- acl_len = sizeof (ACL);
-
- for (DWORD i = 0; i < oacl->AceCount; ++i)
- if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace)))
- {
- cygsid ace_sid ((PSID) &ace->SidStart);
- if (sid_id_auth (ace_sid) == 22)
- {
- if (sid_sub_auth (ace_sid, 0) == 1) /* user */
- {
- struct passwd *pwd;
- uid_t uid = ace_sid.get_uid (&cldap);
- if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
- ace_sid.getfrompw (pwd);
- }
- else /* group */
- {
- struct group *grp;
- gid_t gid = ace_sid.get_gid (&cldap);
- if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
- ace_sid.getfromgr (grp);
- }
- if (!add_access_allowed_ace (acl, i, ace->Mask, ace_sid, acl_len,
- ace->Header.AceFlags))
- return;
- }
- }
- acl->AclSize = acl_len;
-
- RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
- RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
- RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
- RtlSetGroupSecurityDescriptor (&sd, group, FALSE);
-
- status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl, FALSE);
- if (!NT_SUCCESS (status))
- return;
- DWORD sd_size = 0;
- status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
- if (sd_size > 0 && sd_ret.malloc (sd_size))
- RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
-}
-
int
check_file_access (path_conv &pc, int flags, bool effective)
{
@@ -1164,12 +1061,7 @@ check_file_access (path_conv &pc, int flags, bool effective)
if (flags & X_OK)
desired |= FILE_EXECUTE;
if (!get_file_sd (pc.handle (), pc, sd, false))
- {
- /* Tweak Samba security descriptor as necessary. */
- if (pc.fs_is_samba ())
- convert_samba_sd (sd);
- ret = check_access (sd, file_mapping, desired, flags, effective);
- }
+ ret = check_access (sd, file_mapping, desired, flags, effective);
debug_printf ("flags %y, ret %d", flags, ret);
return ret;
}
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index eb3e0f1e5..940afc5d7 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -12,51 +12,18 @@ details. */
#pragma once
#include <accctrl.h>
-#include <dsgetdc.h>
/* Special file attribute set, for instance, in open() and mkdir() to
flag that a file has just been created. Used in alloc_sd, see there. */
#define S_JUSTCREATED 0x80000000
-/* UID/GID */
-void uinfo_init ();
-
-#define ILLEGAL_UID ((uid_t)-1)
-#define ILLEGAL_GID ((gid_t)-1)
-
-/* Offset for accounts in the primary domain of the machine. */
-#define PRIMARY_POSIX_OFFSET (0x00100000)
-
-/* Fake POSIX offsets used in scenarios in which the account has no permission
- to fetch the POSIX offset, or when the admins have set the offset to an
- unreasonable low value. The values are chosen in the hope that they won't
- collide with "real" offsets. */
-#define NOACCESS_POSIX_OFFSET (0xfe500000)
-#define UNUSABLE_POSIX_OFFSET (0xfea00000)
-
-/* For UNIX accounts not mapped to Windows accounts via winbind, Samba returns
- SIDs of the form S-1-22-x-y, with x == 1 for users and x == 2 for groups,
- and y == UNIX uid/gid. NFS returns no SIDs at all, but the plain UNIX
- uid/gid values.
-
- UNIX uid/gid values are mapped to Cygwin uid/gid values 0xff000000 +
- unix uid/gid. This *might* collide with a posix_offset of some trusted
- domain, but it's *very* unlikely. Define the mapping as macro. */
-#define UNIX_POSIX_OFFSET (0xff000000)
-#define UNIX_POSIX_MASK (0x00ffffff)
-#define MAP_UNIX_TO_CYGWIN_ID(id) (UNIX_POSIX_OFFSET \
- | ((id) & UNIX_POSIX_MASK))
-
-#ifndef __x86_64__
-#define ILLEGAL_UID16 ((__uid16_t)-1)
-#define ILLEGAL_GID16 ((__gid16_t)-1)
-#define uid16touid32(u16) ((u16)==ILLEGAL_UID16?ILLEGAL_UID:(uid_t)(u16))
-#define gid16togid32(g16) ((g16)==ILLEGAL_GID16?ILLEGAL_GID:(gid_t)(g16))
-#endif
+#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) \
- + SECURITY_MAX_SID_SIZE))
+ + (n) * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + MAX_SID_LEN))
#define SD_MIN_SIZE (sizeof (SECURITY_DESCRIPTOR) + MAX_DACL_LEN (1))
#define ACL_MAXIMUM_SIZE 65532 /* Yeah, right. 64K - sizeof (DWORD). */
#define SD_MAXIMUM_SIZE 65536
@@ -108,7 +75,7 @@ typedef struct {
BYTE Revision;
BYTE SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
- DWORD SubAuthority[SID_MAX_SUB_AUTHORITIES];
+ DWORD SubAuthority[8];
} DBGSID, *PDBGSID;
/* Macro to define variable length SID structures */
@@ -125,16 +92,6 @@ cygpsid NO_COPY name = (PSID) &name##_struct;
#define FILE_WRITE_BITS (FILE_WRITE_DATA | GENERIC_WRITE | GENERIC_ALL)
#define FILE_EXEC_BITS (FILE_EXECUTE | GENERIC_EXECUTE | GENERIC_ALL)
-/* Convenience macros. The Windows SID access functions are crude. */
-#define sid_id_auth(s) \
- (RtlIdentifierAuthoritySid (s)->Value[5])
-#define sid_sub_auth_count(s) \
- (*RtlSubAuthorityCountSid ((s)))
-#define sid_sub_auth(s,i) \
- (*RtlSubAuthoritySid ((s),(i)))
-#define sid_sub_auth_rid(s) \
- (*RtlSubAuthoritySid ((s), (*RtlSubAuthorityCountSid ((s)) - 1)))
-
#ifdef __cplusplus
extern "C"
{
@@ -147,8 +104,6 @@ extern "C"
}
#endif
-class cyg_ldap;
-
class cygpsid {
protected:
PSID psid;
@@ -157,13 +112,11 @@ public:
cygpsid (PSID nsid) { psid = nsid; }
operator PSID () const { return psid; }
const PSID operator= (PSID nsid) { return psid = nsid;}
- uid_t get_id (BOOL search_grp, int *type, cyg_ldap *pldap);
- int get_uid (cyg_ldap *pldap) { return get_id (FALSE, NULL, pldap); }
- int get_gid (cyg_ldap *pldap) { return get_id (TRUE, NULL, pldap); }
+ uid_t get_id (BOOL search_grp, int *type = NULL);
+ int get_uid () { return get_id (FALSE); }
+ int get_gid () { return get_id (TRUE); }
- PWCHAR pstring (PWCHAR nsidstr) const;
PWCHAR string (PWCHAR nsidstr) const;
- char *pstring (char *nsidstr) const;
char *string (char *nsidstr) const;
bool operator== (const PSID nsid) const
@@ -186,10 +139,9 @@ public:
};
class cygsid : public cygpsid {
- char sbuf[SECURITY_MAX_SID_SIZE];
+ char sbuf[MAX_SID_LEN];
bool well_known_sid;
- const PSID getfromstr (PCWSTR nsidstr, bool well_known);
const PSID getfromstr (const char *nsidstr, bool well_known);
PSID get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known);
@@ -200,7 +152,7 @@ class cygsid : public cygpsid {
else
{
psid = (PSID) sbuf;
- RtlCopySid (SECURITY_MAX_SID_SIZE, psid, nsid);
+ RtlCopySid (MAX_SID_LEN, psid, nsid);
well_known_sid = well_known;
}
return psid;
@@ -217,23 +169,18 @@ public:
{ return assign (nsid, nsid.well_known_sid); }
inline const PSID operator= (const PSID nsid)
{ return assign (nsid, false); }
- inline const PSID operator= (PCWSTR nsidstr)
- { return getfromstr (nsidstr, false); }
inline const PSID operator= (const char *nsidstr)
{ return getfromstr (nsidstr, false); }
inline const PSID operator*= (cygsid &nsid)
{ return assign (nsid, true); }
inline const PSID operator*= (const PSID nsid)
{ return assign (nsid, true); }
- inline const PSID operator*= (PCWSTR nsidstr)
- { return getfromstr (nsidstr, true); }
inline const PSID operator*= (const char *nsidstr)
{ return getfromstr (nsidstr, true); }
inline cygsid () : cygpsid ((PSID) sbuf), well_known_sid (false) {}
inline cygsid (const PSID nsid) { *this = nsid; }
inline cygsid (const char *nstrsid) { *this = nstrsid; }
- inline cygsid (cygsid &nsid) { *this = nsid; }
inline PSID set () { return psid = (PSID) sbuf; }
@@ -394,12 +341,9 @@ extern cygpsid well_known_service_sid;
extern cygpsid well_known_authenticated_users_sid;
extern cygpsid well_known_this_org_sid;
extern cygpsid well_known_system_sid;
-extern cygpsid well_known_local_service_sid;
-extern cygpsid well_known_network_service_sid;
extern cygpsid well_known_builtin_sid;
extern cygpsid well_known_admins_sid;
extern cygpsid well_known_users_sid;
-extern cygpsid trusted_installer_sid;
extern cygpsid mandatory_medium_integrity_sid;
extern cygpsid mandatory_high_integrity_sid;
extern cygpsid mandatory_system_integrity_sid;
@@ -470,7 +414,7 @@ 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, PWCHAR domain, PWCHAR user);
/* Get default logonserver for a domain. */
-bool get_logon_server (PWCHAR domain, PWCHAR wserver, ULONG flags);
+bool get_logon_server (PWCHAR domain, PWCHAR wserver, bool rediscovery);
HANDLE lsa_open_policy (PWCHAR server, ACCESS_MASK access);
void lsa_close_policy (HANDLE lsa);
diff --git a/winsup/cygwin/security.sgml b/winsup/cygwin/security.sgml
new file mode 100644
index 000000000..b286ef540
--- /dev/null
+++ b/winsup/cygwin/security.sgml
@@ -0,0 +1,45 @@
+<sect1 id="func-cygwin-logon_user">
+<title>cygwin_logon_user</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" HANDLE
+<function>cygwin_logon_user</function></funcdef>
+<paramdef>const struct passwd *<parameter>passwd_entry</parameter></paramdef>
+<paramdef>const char *<parameter>password</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>Given a pointer ot a passwd entry of a user and a cleartext password,
+returns a HANDLE to an impersonation token for this user which can be used
+in a subsequent call to <function>cygwin_set_impersonation_token</function>
+to impersonate that user. This function can only be called from a process
+which has the required NT user rights to perform a logon.</para>
+
+<para>See also the chapter "New setuid concept" in the Cygwin user's guide.
+</para>
+
+<para>See also <link linkend="func-cygwin-set-impersonation-token">cygwin_set_impersonation_token</link></para>
+
+</sect1>
+
+<sect1 id="func-cygwin-set-impersonation-token">
+<title>cygwin_set_impersonation_token</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" void
+<function>cygwin_set_impersonation_token</function></funcdef>
+<paramdef>const HANDLE <parameter>token</parameter></paramdef>
+</funcprototype></funcsynopsis>
+
+<para>Use this function to enable the token given as parameter as
+impersonation token for the next call to <function>setuid</function> or
+<function>seteuid</function>. Use
+<function>cygwin_set_impersonation_token</function> together with
+<function>cygwin_logon_user</function> to impersonate users using
+password authentication.</para>
+
+<para>See also the chapter "New setuid concept" in the Cygwin user's guide.
+</para>
+
+<para>See also <link linkend="func-cygwin-logon_user">cygwin_logon_user</link></para>
+
+</sect1>
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index c72cd0c76..75eb72637 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -473,6 +473,9 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
if (me->read_selected && me->read_ready)
{
UNIX_FD_SET (me->fd, readfds);
+ /* Special AF_LOCAL handling. */
+ if ((sock = me->fh->is_socket ()) && sock->connect_state () == connect_pending)
+ sock->connect_state (connected);
ready++;
}
if (me->write_selected && me->write_ready)
@@ -480,10 +483,16 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
UNIX_FD_SET (me->fd, writefds);
if (me->except_on_write && (sock = me->fh->is_socket ()))
{
- /* Set readfds entry in case of a failed connect. */
- if (!me->read_ready && me->read_selected
- && sock->connect_state () == connect_failed)
- UNIX_FD_SET (me->fd, readfds);
+ /* Special AF_LOCAL handling. */
+ if (!me->read_ready && sock->connect_state () == connect_pending
+ && sock->af_local_connect ())
+ {
+ if (me->read_selected)
+ UNIX_FD_SET (me->fd, readfds);
+ sock->connect_state (connect_failed);
+ }
+ else
+ sock->connect_state (connected);
}
ready++;
}
diff --git a/winsup/cygwin/setlsapwd.cc b/winsup/cygwin/setlsapwd.cc
index eb3b9e6bf..a906412ca 100644
--- a/winsup/cygwin/setlsapwd.cc
+++ b/winsup/cygwin/setlsapwd.cc
@@ -17,6 +17,7 @@ details. */
#include "cygheap.h"
#include "security.h"
#include "cygserver_setpwd.h"
+#include "pwdgrp.h"
#include "ntdll.h"
#include <ntsecapi.h>
#include <stdlib.h>
@@ -50,7 +51,7 @@ setlsapwd (const char *passwd, const char *username)
if (username)
{
cygsid psid;
- struct passwd *pw = internal_getpwnam (username);
+ struct passwd *pw = internal_getpwnam (username, false);
if (!pw || !psid.getfrompw (pw))
{
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 4510d02ab..2f5a45376 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -22,6 +22,7 @@ details. */
#include "shared_info_magic.h"
#include "registry.h"
#include "cygwin_version.h"
+#include "pwdgrp.h"
#include "spinlock.h"
#include <alloca.h>
#include <wchar.h>
@@ -343,8 +344,16 @@ shared_info::initialize ()
}
void
-memory_init ()
+memory_init (bool init_cygheap)
{
+ /* Initialize the Cygwin heap, if necessary */
+ if (init_cygheap)
+ {
+ cygheap_init ();
+ cygheap->user.init ();
+ cygheap->init_installation_root (); /* Requires user.init! */
+ }
+
shared_info::create (); /* Initialize global shared memory */
user_info::create (false); /* Initialize per-user shared memory */
/* Initialize tty list session stuff. Doesn't really belong here but
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index 90b386fe6..6733b3636 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -75,7 +75,7 @@ enum shared_locations
};
-void memory_init ();
+void __reg1 memory_init (bool);
void __stdcall shared_destroy ();
#define shared_align_past(p) \
diff --git a/winsup/cygwin/stackdump.sgml b/winsup/cygwin/stackdump.sgml
new file mode 100644
index 000000000..1969e2e6f
--- /dev/null
+++ b/winsup/cygwin/stackdump.sgml
@@ -0,0 +1,13 @@
+<sect1 id="func-cygwin-stackdump">
+<title>cygwin_stackdump</title>
+
+<funcsynopsis><funcprototype>
+<funcdef>extern "C" void
+<function>cygwin_stackdump</function></funcdef>
+<void />
+</funcprototype></funcsynopsis>
+
+<para> Outputs a stackdump to stderr from the called location.
+</para>
+
+</sect1>
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 933bfe464..544169d78 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -58,6 +58,7 @@ details. */
#include "pinfo.h"
#include "shared_info.h"
#include "cygheap.h"
+#include "pwdgrp.h"
#include "registry.h"
#include "environ.h"
#include "tls_pbuf.h"
diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h
index 572dfb7b7..402638e59 100644
--- a/winsup/cygwin/tlsoffsets.h
+++ b/winsup/cygwin/tlsoffsets.h
@@ -3,115 +3,115 @@
//; $tls::start_offset = -12700;
//; $tls::locals = -12700;
//; $tls::plocals = 0;
-//; $tls::local_clib = -10980;
-//; $tls::plocal_clib = 1720;
-//; $tls::__dontuse = -10980;
-//; $tls::p__dontuse = 1720;
-//; $tls::func = -9892;
-//; $tls::pfunc = 2808;
-//; $tls::saved_errno = -9888;
-//; $tls::psaved_errno = 2812;
-//; $tls::sa_flags = -9884;
-//; $tls::psa_flags = 2816;
-//; $tls::oldmask = -9880;
-//; $tls::poldmask = 2820;
-//; $tls::deltamask = -9876;
-//; $tls::pdeltamask = 2824;
-//; $tls::errno_addr = -9872;
-//; $tls::perrno_addr = 2828;
-//; $tls::sigmask = -9868;
-//; $tls::psigmask = 2832;
-//; $tls::sigwait_mask = -9864;
-//; $tls::psigwait_mask = 2836;
-//; $tls::sigwait_info = -9860;
-//; $tls::psigwait_info = 2840;
-//; $tls::signal_arrived = -9856;
-//; $tls::psignal_arrived = 2844;
-//; $tls::will_wait_for_signal = -9852;
-//; $tls::pwill_wait_for_signal = 2848;
-//; $tls::thread_context = -9848;
-//; $tls::pthread_context = 2852;
-//; $tls::thread_id = -9636;
-//; $tls::pthread_id = 3064;
-//; $tls::infodata = -9632;
-//; $tls::pinfodata = 3068;
-//; $tls::tid = -9484;
-//; $tls::ptid = 3216;
-//; $tls::_ctinfo = -9480;
-//; $tls::p_ctinfo = 3220;
-//; $tls::andreas = -9476;
-//; $tls::pandreas = 3224;
-//; $tls::wq = -9472;
-//; $tls::pwq = 3228;
-//; $tls::sig = -9444;
-//; $tls::psig = 3256;
-//; $tls::incyg = -9440;
-//; $tls::pincyg = 3260;
-//; $tls::spinning = -9436;
-//; $tls::pspinning = 3264;
-//; $tls::stacklock = -9432;
-//; $tls::pstacklock = 3268;
-//; $tls::stackptr = -9428;
-//; $tls::pstackptr = 3272;
-//; $tls::stack = -9424;
-//; $tls::pstack = 3276;
-//; $tls::initialized = -8400;
-//; $tls::pinitialized = 4300;
+//; $tls::local_clib = -10940;
+//; $tls::plocal_clib = 1760;
+//; $tls::__dontuse = -10940;
+//; $tls::p__dontuse = 1760;
+//; $tls::func = -9852;
+//; $tls::pfunc = 2848;
+//; $tls::saved_errno = -9848;
+//; $tls::psaved_errno = 2852;
+//; $tls::sa_flags = -9844;
+//; $tls::psa_flags = 2856;
+//; $tls::oldmask = -9840;
+//; $tls::poldmask = 2860;
+//; $tls::deltamask = -9836;
+//; $tls::pdeltamask = 2864;
+//; $tls::errno_addr = -9832;
+//; $tls::perrno_addr = 2868;
+//; $tls::sigmask = -9828;
+//; $tls::psigmask = 2872;
+//; $tls::sigwait_mask = -9824;
+//; $tls::psigwait_mask = 2876;
+//; $tls::sigwait_info = -9820;
+//; $tls::psigwait_info = 2880;
+//; $tls::signal_arrived = -9816;
+//; $tls::psignal_arrived = 2884;
+//; $tls::will_wait_for_signal = -9812;
+//; $tls::pwill_wait_for_signal = 2888;
+//; $tls::thread_context = -9808;
+//; $tls::pthread_context = 2892;
+//; $tls::thread_id = -9596;
+//; $tls::pthread_id = 3104;
+//; $tls::infodata = -9592;
+//; $tls::pinfodata = 3108;
+//; $tls::tid = -9444;
+//; $tls::ptid = 3256;
+//; $tls::_ctinfo = -9440;
+//; $tls::p_ctinfo = 3260;
+//; $tls::andreas = -9436;
+//; $tls::pandreas = 3264;
+//; $tls::wq = -9432;
+//; $tls::pwq = 3268;
+//; $tls::sig = -9404;
+//; $tls::psig = 3296;
+//; $tls::incyg = -9400;
+//; $tls::pincyg = 3300;
+//; $tls::spinning = -9396;
+//; $tls::pspinning = 3304;
+//; $tls::stacklock = -9392;
+//; $tls::pstacklock = 3308;
+//; $tls::stackptr = -9388;
+//; $tls::pstackptr = 3312;
+//; $tls::stack = -9384;
+//; $tls::pstack = 3316;
+//; $tls::initialized = -8360;
+//; $tls::pinitialized = 4340;
//; __DATA__
#define tls_locals (-12700)
#define tls_plocals (0)
-#define tls_local_clib (-10980)
-#define tls_plocal_clib (1720)
-#define tls___dontuse (-10980)
-#define tls_p__dontuse (1720)
-#define tls_func (-9892)
-#define tls_pfunc (2808)
-#define tls_saved_errno (-9888)
-#define tls_psaved_errno (2812)
-#define tls_sa_flags (-9884)
-#define tls_psa_flags (2816)
-#define tls_oldmask (-9880)
-#define tls_poldmask (2820)
-#define tls_deltamask (-9876)
-#define tls_pdeltamask (2824)
-#define tls_errno_addr (-9872)
-#define tls_perrno_addr (2828)
-#define tls_sigmask (-9868)
-#define tls_psigmask (2832)
-#define tls_sigwait_mask (-9864)
-#define tls_psigwait_mask (2836)
-#define tls_sigwait_info (-9860)
-#define tls_psigwait_info (2840)
-#define tls_signal_arrived (-9856)
-#define tls_psignal_arrived (2844)
-#define tls_will_wait_for_signal (-9852)
-#define tls_pwill_wait_for_signal (2848)
-#define tls_thread_context (-9848)
-#define tls_pthread_context (2852)
-#define tls_thread_id (-9636)
-#define tls_pthread_id (3064)
-#define tls_infodata (-9632)
-#define tls_pinfodata (3068)
-#define tls_tid (-9484)
-#define tls_ptid (3216)
-#define tls__ctinfo (-9480)
-#define tls_p_ctinfo (3220)
-#define tls_andreas (-9476)
-#define tls_pandreas (3224)
-#define tls_wq (-9472)
-#define tls_pwq (3228)
-#define tls_sig (-9444)
-#define tls_psig (3256)
-#define tls_incyg (-9440)
-#define tls_pincyg (3260)
-#define tls_spinning (-9436)
-#define tls_pspinning (3264)
-#define tls_stacklock (-9432)
-#define tls_pstacklock (3268)
-#define tls_stackptr (-9428)
-#define tls_pstackptr (3272)
-#define tls_stack (-9424)
-#define tls_pstack (3276)
-#define tls_initialized (-8400)
-#define tls_pinitialized (4300)
+#define tls_local_clib (-10940)
+#define tls_plocal_clib (1760)
+#define tls___dontuse (-10940)
+#define tls_p__dontuse (1760)
+#define tls_func (-9852)
+#define tls_pfunc (2848)
+#define tls_saved_errno (-9848)
+#define tls_psaved_errno (2852)
+#define tls_sa_flags (-9844)
+#define tls_psa_flags (2856)
+#define tls_oldmask (-9840)
+#define tls_poldmask (2860)
+#define tls_deltamask (-9836)
+#define tls_pdeltamask (2864)
+#define tls_errno_addr (-9832)
+#define tls_perrno_addr (2868)
+#define tls_sigmask (-9828)
+#define tls_psigmask (2872)
+#define tls_sigwait_mask (-9824)
+#define tls_psigwait_mask (2876)
+#define tls_sigwait_info (-9820)
+#define tls_psigwait_info (2880)
+#define tls_signal_arrived (-9816)
+#define tls_psignal_arrived (2884)
+#define tls_will_wait_for_signal (-9812)
+#define tls_pwill_wait_for_signal (2888)
+#define tls_thread_context (-9808)
+#define tls_pthread_context (2892)
+#define tls_thread_id (-9596)
+#define tls_pthread_id (3104)
+#define tls_infodata (-9592)
+#define tls_pinfodata (3108)
+#define tls_tid (-9444)
+#define tls_ptid (3256)
+#define tls__ctinfo (-9440)
+#define tls_p_ctinfo (3260)
+#define tls_andreas (-9436)
+#define tls_pandreas (3264)
+#define tls_wq (-9432)
+#define tls_pwq (3268)
+#define tls_sig (-9404)
+#define tls_psig (3296)
+#define tls_incyg (-9400)
+#define tls_pincyg (3300)
+#define tls_spinning (-9396)
+#define tls_pspinning (3304)
+#define tls_stacklock (-9392)
+#define tls_pstacklock (3308)
+#define tls_stackptr (-9388)
+#define tls_pstackptr (3312)
+#define tls_stack (-9384)
+#define tls_pstack (3316)
+#define tls_initialized (-8360)
+#define tls_pinitialized (4340)
diff --git a/winsup/cygwin/tlsoffsets64.h b/winsup/cygwin/tlsoffsets64.h
index 991280663..7df2c988b 100644
--- a/winsup/cygwin/tlsoffsets64.h
+++ b/winsup/cygwin/tlsoffsets64.h
@@ -3,115 +3,115 @@
//; $tls::start_offset = -12800;
//; $tls::locals = -12800;
//; $tls::plocals = 0;
-//; $tls::local_clib = -10624;
-//; $tls::plocal_clib = 2176;
-//; $tls::__dontuse = -10624;
-//; $tls::p__dontuse = 2176;
-//; $tls::func = -8736;
-//; $tls::pfunc = 4064;
-//; $tls::saved_errno = -8728;
-//; $tls::psaved_errno = 4072;
-//; $tls::sa_flags = -8724;
-//; $tls::psa_flags = 4076;
-//; $tls::oldmask = -8720;
-//; $tls::poldmask = 4080;
-//; $tls::deltamask = -8712;
-//; $tls::pdeltamask = 4088;
-//; $tls::errno_addr = -8704;
-//; $tls::perrno_addr = 4096;
-//; $tls::sigmask = -8696;
-//; $tls::psigmask = 4104;
-//; $tls::sigwait_mask = -8688;
-//; $tls::psigwait_mask = 4112;
-//; $tls::sigwait_info = -8680;
-//; $tls::psigwait_info = 4120;
-//; $tls::signal_arrived = -8672;
-//; $tls::psignal_arrived = 4128;
-//; $tls::will_wait_for_signal = -8664;
-//; $tls::pwill_wait_for_signal = 4136;
-//; $tls::thread_context = -8656;
-//; $tls::pthread_context = 4144;
-//; $tls::thread_id = -7824;
-//; $tls::pthread_id = 4976;
-//; $tls::infodata = -7820;
-//; $tls::pinfodata = 4980;
-//; $tls::tid = -7672;
-//; $tls::ptid = 5128;
-//; $tls::_ctinfo = -7664;
-//; $tls::p_ctinfo = 5136;
-//; $tls::andreas = -7656;
-//; $tls::pandreas = 5144;
-//; $tls::wq = -7648;
-//; $tls::pwq = 5152;
-//; $tls::sig = -7600;
-//; $tls::psig = 5200;
-//; $tls::incyg = -7596;
-//; $tls::pincyg = 5204;
-//; $tls::spinning = -7592;
-//; $tls::pspinning = 5208;
-//; $tls::stacklock = -7588;
-//; $tls::pstacklock = 5212;
-//; $tls::stackptr = -7584;
-//; $tls::pstackptr = 5216;
-//; $tls::stack = -7576;
-//; $tls::pstack = 5224;
-//; $tls::initialized = -5528;
-//; $tls::pinitialized = 7272;
+//; $tls::local_clib = -10560;
+//; $tls::plocal_clib = 2240;
+//; $tls::__dontuse = -10560;
+//; $tls::p__dontuse = 2240;
+//; $tls::func = -8672;
+//; $tls::pfunc = 4128;
+//; $tls::saved_errno = -8664;
+//; $tls::psaved_errno = 4136;
+//; $tls::sa_flags = -8660;
+//; $tls::psa_flags = 4140;
+//; $tls::oldmask = -8656;
+//; $tls::poldmask = 4144;
+//; $tls::deltamask = -8648;
+//; $tls::pdeltamask = 4152;
+//; $tls::errno_addr = -8640;
+//; $tls::perrno_addr = 4160;
+//; $tls::sigmask = -8632;
+//; $tls::psigmask = 4168;
+//; $tls::sigwait_mask = -8624;
+//; $tls::psigwait_mask = 4176;
+//; $tls::sigwait_info = -8616;
+//; $tls::psigwait_info = 4184;
+//; $tls::signal_arrived = -8608;
+//; $tls::psignal_arrived = 4192;
+//; $tls::will_wait_for_signal = -8600;
+//; $tls::pwill_wait_for_signal = 4200;
+//; $tls::thread_context = -8592;
+//; $tls::pthread_context = 4208;
+//; $tls::thread_id = -7760;
+//; $tls::pthread_id = 5040;
+//; $tls::infodata = -7756;
+//; $tls::pinfodata = 5044;
+//; $tls::tid = -7608;
+//; $tls::ptid = 5192;
+//; $tls::_ctinfo = -7600;
+//; $tls::p_ctinfo = 5200;
+//; $tls::andreas = -7592;
+//; $tls::pandreas = 5208;
+//; $tls::wq = -7584;
+//; $tls::pwq = 5216;
+//; $tls::sig = -7536;
+//; $tls::psig = 5264;
+//; $tls::incyg = -7532;
+//; $tls::pincyg = 5268;
+//; $tls::spinning = -7528;
+//; $tls::pspinning = 5272;
+//; $tls::stacklock = -7524;
+//; $tls::pstacklock = 5276;
+//; $tls::stackptr = -7520;
+//; $tls::pstackptr = 5280;
+//; $tls::stack = -7512;
+//; $tls::pstack = 5288;
+//; $tls::initialized = -5464;
+//; $tls::pinitialized = 7336;
//; __DATA__
#define tls_locals (-12800)
#define tls_plocals (0)
-#define tls_local_clib (-10624)
-#define tls_plocal_clib (2176)
-#define tls___dontuse (-10624)
-#define tls_p__dontuse (2176)
-#define tls_func (-8736)
-#define tls_pfunc (4064)
-#define tls_saved_errno (-8728)
-#define tls_psaved_errno (4072)
-#define tls_sa_flags (-8724)
-#define tls_psa_flags (4076)
-#define tls_oldmask (-8720)
-#define tls_poldmask (4080)
-#define tls_deltamask (-8712)
-#define tls_pdeltamask (4088)
-#define tls_errno_addr (-8704)
-#define tls_perrno_addr (4096)
-#define tls_sigmask (-8696)
-#define tls_psigmask (4104)
-#define tls_sigwait_mask (-8688)
-#define tls_psigwait_mask (4112)
-#define tls_sigwait_info (-8680)
-#define tls_psigwait_info (4120)
-#define tls_signal_arrived (-8672)
-#define tls_psignal_arrived (4128)
-#define tls_will_wait_for_signal (-8664)
-#define tls_pwill_wait_for_signal (4136)
-#define tls_thread_context (-8656)
-#define tls_pthread_context (4144)
-#define tls_thread_id (-7824)
-#define tls_pthread_id (4976)
-#define tls_infodata (-7820)
-#define tls_pinfodata (4980)
-#define tls_tid (-7672)
-#define tls_ptid (5128)
-#define tls__ctinfo (-7664)
-#define tls_p_ctinfo (5136)
-#define tls_andreas (-7656)
-#define tls_pandreas (5144)
-#define tls_wq (-7648)
-#define tls_pwq (5152)
-#define tls_sig (-7600)
-#define tls_psig (5200)
-#define tls_incyg (-7596)
-#define tls_pincyg (5204)
-#define tls_spinning (-7592)
-#define tls_pspinning (5208)
-#define tls_stacklock (-7588)
-#define tls_pstacklock (5212)
-#define tls_stackptr (-7584)
-#define tls_pstackptr (5216)
-#define tls_stack (-7576)
-#define tls_pstack (5224)
-#define tls_initialized (-5528)
-#define tls_pinitialized (7272)
+#define tls_local_clib (-10560)
+#define tls_plocal_clib (2240)
+#define tls___dontuse (-10560)
+#define tls_p__dontuse (2240)
+#define tls_func (-8672)
+#define tls_pfunc (4128)
+#define tls_saved_errno (-8664)
+#define tls_psaved_errno (4136)
+#define tls_sa_flags (-8660)
+#define tls_psa_flags (4140)
+#define tls_oldmask (-8656)
+#define tls_poldmask (4144)
+#define tls_deltamask (-8648)
+#define tls_pdeltamask (4152)
+#define tls_errno_addr (-8640)
+#define tls_perrno_addr (4160)
+#define tls_sigmask (-8632)
+#define tls_psigmask (4168)
+#define tls_sigwait_mask (-8624)
+#define tls_psigwait_mask (4176)
+#define tls_sigwait_info (-8616)
+#define tls_psigwait_info (4184)
+#define tls_signal_arrived (-8608)
+#define tls_psignal_arrived (4192)
+#define tls_will_wait_for_signal (-8600)
+#define tls_pwill_wait_for_signal (4200)
+#define tls_thread_context (-8592)
+#define tls_pthread_context (4208)
+#define tls_thread_id (-7760)
+#define tls_pthread_id (5040)
+#define tls_infodata (-7756)
+#define tls_pinfodata (5044)
+#define tls_tid (-7608)
+#define tls_ptid (5192)
+#define tls__ctinfo (-7600)
+#define tls_p_ctinfo (5200)
+#define tls_andreas (-7592)
+#define tls_pandreas (5208)
+#define tls_wq (-7584)
+#define tls_pwq (5216)
+#define tls_sig (-7536)
+#define tls_psig (5264)
+#define tls_incyg (-7532)
+#define tls_pincyg (5268)
+#define tls_spinning (-7528)
+#define tls_pspinning (5272)
+#define tls_stacklock (-7524)
+#define tls_pstacklock (5276)
+#define tls_stackptr (-7520)
+#define tls_pstackptr (5280)
+#define tls_stack (-7512)
+#define tls_pstack (5288)
+#define tls_initialized (-5464)
+#define tls_pinitialized (7336)
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index 8b9266f9d..bb75850a0 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -1,7 +1,7 @@
/* uinfo.cc: user info (uid, gid, etc...)
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012, 2014 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
This file is part of Cygwin.
@@ -10,14 +10,12 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <iptypes.h>
-#include <lm.h>
-#include <ntsecapi.h>
-#include <wininet.h>
#include <unistd.h>
+#include <wininet.h>
#include <stdlib.h>
-#include <stdio.h>
#include <wchar.h>
+#include <lm.h>
+#include <iptypes.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "pinfo.h"
@@ -29,11 +27,9 @@ details. */
#include "registry.h"
#include "child_info.h"
#include "environ.h"
+#include "pwdgrp.h"
#include "tls_pbuf.h"
-#include "miscfuncs.h"
#include "ntdll.h"
-#include "ldap.h"
-#include "cygserver_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.
@@ -85,7 +81,7 @@ cygheap_user::init ()
status = NtSetInformationToken (hProcToken, TokenOwner, &effec_cygsid,
sizeof (cygsid));
if (!NT_SUCCESS (status))
- debug_printf ("NtSetInformationToken (TokenOwner), %y", status);
+ debug_printf ("NtSetInformationToken(TokenOwner), %y", status);
/* Standard way to build a security descriptor with the usual DACL */
PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
@@ -116,63 +112,41 @@ cygheap_user::init ()
void
internal_getlogin (cygheap_user &user)
{
- struct passwd *pwd;
- struct group *pgrp, *grp, *grp2;
- cyg_ldap cldap;
-
- /* Fetch (and potentially generate) passwd and group entries for the user
- and the primary group in the token. */
- pwd = internal_getpwsid (user.sid (), &cldap);
- pgrp = internal_getgrsid (user.groups.pgsid, &cldap);
- if (!cygheap->pg.nss_cygserver_caching ())
- internal_getgroups (0, NULL, &cldap);
- if (!pwd)
- debug_printf ("user not found in passwd DB");
+ struct passwd *pw = NULL;
+
+ 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
{
cygsid gsid;
- user.set_name (pwd->pw_name);
- myself->uid = pwd->pw_uid;
- myself->gid = pwd->pw_gid;
- /* If the primary group in the passwd DB is different from the primary
- group in the user token, we have to find the SID of that group and
- try to override the token primary group. */
- if (!pgrp || myself->gid != pgrp->gr_gid)
+ myself->uid = pw->pw_uid;
+ myself->gid = pw->pw_gid;
+ user.set_name (pw->pw_name);
+ if (gsid.getfromgr (internal_getgrgid (pw->pw_gid)))
{
- if (gsid.getfromgr (grp = internal_getgrgid (pwd->pw_gid, &cldap)))
+ if (gsid != user.groups.pgsid)
{
- /* We might have a group file with a group entry for the current
- user's primary group, but the current user has no entry in
- passwd. If so, pw_gid is taken from windows and might
- disagree with gr_gid from the group file. Overwrite it. */
- if ((grp2 = internal_getgrsid (gsid, &cldap)) && grp2 != grp)
- myself->gid = pwd->pw_gid = grp2->gr_gid;
/* Set primary group to the group in /etc/passwd. */
- if (gsid != user.groups.pgsid)
- {
- NTSTATUS status = NtSetInformationToken (hProcToken,
- TokenPrimaryGroup,
- &gsid, sizeof gsid);
- if (!NT_SUCCESS (status))
- {
- debug_printf ("NtSetInformationToken (TokenPrimaryGroup),"
- " %y", status);
- /* Revert the primary group setting and override the
- setting in the passwd entry. */
- if (pgrp)
- myself->gid = pwd->pw_gid = pgrp->gr_gid;
- }
- else
- user.groups.pgsid = gsid;
- clear_procimptoken ();
- }
+ NTSTATUS status = NtSetInformationToken (hProcToken,
+ TokenPrimaryGroup,
+ &gsid, sizeof gsid);
+ if (!NT_SUCCESS (status))
+ debug_printf ("NtSetInformationToken (TokenPrimaryGroup), %y",
+ status);
+ else
+ user.groups.pgsid = gsid;
+ clear_procimptoken ();
}
- else
- debug_printf ("group not found in group DB");
}
+ else
+ debug_printf ("gsid not found in augmented /etc/group");
}
- cygheap->user.ontherange (CH_HOME, pwd);
+ cygheap->user.ontherange (CH_HOME, pw);
}
void
@@ -339,7 +313,7 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw)
{
if (pw && pw->pw_dir && *pw->pw_dir)
{
- debug_printf ("Set HOME (from account db) to %s", pw->pw_dir);
+ debug_printf ("Set HOME (from /etc/passwd) to %s", pw->pw_dir);
setenv ("HOME", pw->pw_dir, 1);
}
else
@@ -446,7 +420,7 @@ cygheap_user::env_logsrv (const char *name, size_t namelen)
WCHAR wlogsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
sys_mbstowcs (wdomain, MAX_DOMAIN_NAME_LEN + 1, mydomain);
cfree_and_set (plogsrv, almost_null);
- if (get_logon_server (wdomain, wlogsrv, DS_IS_FLAT_NAME))
+ if (get_logon_server (wdomain, wlogsrv, false))
sys_wcstombs_alloc (&plogsrv, HEAP_STR, wlogsrv);
return plogsrv;
}
@@ -556,13 +530,21 @@ 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 = crealloc_abort (pwdgrp_buf,
- max_lines * pwdgrp_buf_elem_size);
+ *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
}
- lptr = eptr;
if ((this->*parse) ())
curr_lines++;
}
@@ -570,1460 +552,82 @@ pwdgrp::add_line (char *eptr)
}
void
-cygheap_pwdgrp::init ()
-{
- pwd_cache.cygserver.init_pwd ();
- pwd_cache.file.init_pwd ();
- pwd_cache.win.init_pwd ();
- grp_cache.cygserver.init_grp ();
- grp_cache.file.init_grp ();
- grp_cache.win.init_grp ();
- /* Default settings:
-
- passwd: files db
- group: files db
- db_prefix: auto DISABLED
- db_separator: + DISABLED
- db_enum: cache builtin
- */
- pwd_src = (NSS_FILES | NSS_DB);
- grp_src = (NSS_FILES | NSS_DB);
- prefix = NSS_AUTO;
- separator[0] = L'+';
- enums = (ENUM_CACHE | ENUM_BUILTIN);
- enum_tdoms = NULL;
- caching = true; /* INTERNAL ONLY */
-}
-
-/* The /etc/nsswitch.conf file is read exactly once by the root process of a
- process tree. We can't afford methodical changes during the lifetime of a
- process tree. */
-void
-cygheap_pwdgrp::nss_init_line (const char *line)
-{
- const char *c = line + strspn (line, " \t");
- switch (*c)
- {
- case 'p':
- case 'g':
- {
- int *src = NULL;
- if (!strncmp (c, "passwd:", 7))
- {
- src = &pwd_src;
- c += 7;
- }
- else if (!strncmp (c, "group:", 6))
- {
- src = &grp_src;
- c += 6;
- }
- if (src)
- {
- *src = 0;
- while (*c)
- {
- c += strspn (c, " \t");
- if (!*c || *c == '#')
- break;
- if (!strncmp (c, "files", 5) && strchr (" \t", c[5]))
- {
- *src |= NSS_FILES;
- c += 5;
- }
- else if (!strncmp (c, "db", 2) && strchr (" \t", c[2]))
- {
- *src |= NSS_DB;
- c += 2;
- }
- else
- {
- c += strcspn (c, " \t");
- debug_printf ("Invalid nsswitch.conf content: %s", line);
- }
- }
- if (*src == 0)
- *src = (NSS_FILES | NSS_DB);
- }
- }
- break;
- case 'd':
- if (strncmp (c, "db_", 3))
- {
- debug_printf ("Invalid nsswitch.conf content: %s", line);
- break;
- }
- c += 3;
-#if 0 /* Disable setting prefix and separator from nsswitch.conf for now.
- Remove if nobody complains too loudly. */
- if (!strncmp (c, "prefix:", 7))
- {
- c += 7;
- c += strspn (c, " \t");
- if (!strncmp (c, "auto", 4) && strchr (" \t", c[4]))
- prefix = NSS_AUTO;
- else if (!strncmp (c, "primary", 7) && strchr (" \t", c[7]))
- prefix = NSS_PRIMARY;
- else if (!strncmp (c, "always", 6) && strchr (" \t", c[6]))
- prefix = NSS_ALWAYS;
- else
- debug_printf ("Invalid nsswitch.conf content: %s", line);
- }
- else if (!strncmp (c, "separator:", 10))
- {
- c += 10;
- c += strspn (c, " \t");
- if ((unsigned char) *c <= 0x7f && *c != ':' && strchr (" \t", c[1]))
- separator[0] = (unsigned char) *c;
- else
- debug_printf ("Invalid nsswitch.conf content: %s", line);
- }
- else
-#endif
- if (!strncmp (c, "enum:", 5))
- {
- tmp_pathbuf tp;
- char *tdoms = tp.c_get ();
- char *td = tdoms;
- int new_enums = ENUM_NONE;
-
- td[0] = '\0';
- c += 5;
- c += strspn (c, " \t");
- while (!strchr (" \t", *c))
- {
- const char *e = c + strcspn (c, " \t");
- if (!strncmp (c, "none", 4) && strchr (" \t", c[4]))
- new_enums = ENUM_NONE;
- else if (!strncmp (c, "builtin", 7) && strchr (" \t", c[7]))
- new_enums |= ENUM_BUILTIN;
- else if (!strncmp (c, "cache", 5) && strchr (" \t", c[5]))
- new_enums |= ENUM_CACHE;
- else if (!strncmp (c, "files", 5) && strchr (" \t", c[5]))
- new_enums |= ENUM_FILES;
- else if (!strncmp (c, "local", 5) && strchr (" \t", c[5]))
- new_enums |= ENUM_LOCAL;
- else if (!strncmp (c, "primary", 7) && strchr (" \t", c[7]))
- new_enums |= ENUM_PRIMARY;
- else if (!strncmp (c, "alltrusted", 10) && strchr (" \t", c[10]))
- new_enums |= ENUM_TDOMS | ENUM_TDOMS_ALL;
- else if (!strncmp (c, "all", 3) && strchr (" \t", c[3]))
- new_enums |= ENUM_ALL;
- else
- {
- td = stpcpy (stpncpy (td, c, e - c), " ");
- new_enums |= ENUM_TDOMS;
- }
- c = e;
- c += strspn (c, " \t");
- }
- if ((new_enums & (ENUM_TDOMS | ENUM_TDOMS_ALL)) == ENUM_TDOMS)
- {
- if (td > tdoms)
- {
- PWCHAR spc;
- sys_mbstowcs_alloc (&enum_tdoms, HEAP_BUF, tdoms);
- /* Convert string to REG_MULTI_SZ-style. */
- while ((spc = wcsrchr (enum_tdoms, L' ')))
- *spc = L'\0';
- }
- else
- new_enums &= ~(ENUM_TDOMS | ENUM_TDOMS_ALL);
- }
- enums = new_enums;
- }
- break;
- case '\0':
- case '#':
- break;
- default:
- debug_printf ("Invalid nsswitch.conf content: %s", line);
- break;
- }
-}
-
-void
-cygheap_pwdgrp::_nss_init ()
+pwdgrp::load (const wchar_t *rel_path)
{
- UNICODE_STRING path;
- OBJECT_ATTRIBUTES attr;
- NT_readline rl;
- tmp_pathbuf tp;
- char *buf = tp.c_get ();
-
- PCWSTR rel_path = L"\\etc\\nsswitch.conf";
- path.Length = (wcslen (cygheap->installation_root) + wcslen (rel_path))
- * sizeof (WCHAR);
- path.MaximumLength = path.Length + sizeof (WCHAR);
- path.Buffer = (PWCHAR) alloca (path.MaximumLength);
- wcpcpy (wcpcpy (path.Buffer, cygheap->installation_root), rel_path);
- InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE,
- NULL, NULL);
- if (rl.init (&attr, buf, NT_MAX_PATH))
- while ((buf = rl.gets ()))
- nss_init_line (buf);
- nss_inited = true;
-}
-
-/* Override the ParentIndex value of the PDS_DOMAIN_TRUSTSW entry with the
- PosixOffset. */
-#define PosixOffset ParentIndex
+ static const char failed[] = "failed";
+ static const char succeeded[] = "succeeded";
+ const char *res = failed;
+ HANDLE fh = NULL;
-bool
-cygheap_domain_info::init ()
-{
- HANDLE lsa;
NTSTATUS status;
- ULONG ret;
- /* We *have* to copy the information. Apart from our wish to have the
- stuff in the cygheap, even when not calling LsaFreeMemory on the result,
- the data will be overwritten later. From what I gather, the information
- is, in fact, stored on the stack. */
- PPOLICY_DNS_DOMAIN_INFO pdom;
- PPOLICY_ACCOUNT_DOMAIN_INFO adom;
- PDS_DOMAIN_TRUSTSW td;
- ULONG tdom_cnt;
-
- if (adom_name)
- return true;
- lsa = lsa_open_policy (NULL, POLICY_VIEW_LOCAL_INFORMATION);
- if (!lsa)
- {
- system_printf ("lsa_open_policy(NULL) failed");
- return false;
- }
- /* Fetch primary domain information from local LSA. */
- status = LsaQueryInformationPolicy (lsa, PolicyDnsDomainInformation,
- (PVOID *) &pdom);
- if (status != STATUS_SUCCESS)
- {
- system_printf ("LsaQueryInformationPolicy(Primary) %y", status);
- return false;
- }
- /* Copy primary domain info to cygheap. */
- pdom_name = cwcsdup (pdom->Name.Buffer);
- pdom_dns_name = pdom->DnsDomainName.Length
- ? cwcsdup (pdom->DnsDomainName.Buffer) : NULL;
- pdom_sid = pdom->Sid;
- LsaFreeMemory (pdom);
- /* Fetch account domain information from local LSA. */
- status = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation,
- (PVOID *) &adom);
- if (status != STATUS_SUCCESS)
- {
- system_printf ("LsaQueryInformationPolicy(Account) %y", status);
- return false;
- }
- /* Copy account domain info to cygheap. If we're running on a DC the account
- domain is identical to the primary domain. This leads to confusion when
- trying to compute the uid/gid values. Therefore we invalidate the account
- domain name if we're running on a DC. */
- adom_sid = adom->DomainSid;
- adom_name = cwcsdup (pdom_sid == adom_sid ? L"@" : adom->DomainName.Buffer);
- LsaFreeMemory (adom);
- lsa_close_policy (lsa);
- if (cygheap->dom.member_machine ())
- {
- ret = DsEnumerateDomainTrustsW (NULL, DS_DOMAIN_DIRECT_INBOUND
- | DS_DOMAIN_DIRECT_OUTBOUND
- | DS_DOMAIN_IN_FOREST,
- &td, &tdom_cnt);
- if (ret != ERROR_SUCCESS)
- {
- SetLastError (ret);
- debug_printf ("DsEnumerateDomainTrusts: %E");
- return true;
- }
- if (tdom_cnt == 0)
- {
- return true;
- }
- /* Copy trusted domain info to cygheap, setting PosixOffset on the fly. */
- tdom = (PDS_DOMAIN_TRUSTSW)
- cmalloc_abort (HEAP_BUF, tdom_cnt * sizeof (DS_DOMAIN_TRUSTSW));
- memcpy (tdom, td, tdom_cnt * sizeof (DS_DOMAIN_TRUSTSW));
- for (ULONG idx = 0; idx < tdom_cnt; ++idx)
- {
- /* Copy... */
- tdom[idx].NetbiosDomainName = cwcsdup (td[idx].NetbiosDomainName);
- /* DnsDomainName as well as DomainSid can be NULL. The reason is
- usually a domain of type TRUST_TYPE_DOWNLEVEL. This can be an
- old pre-AD domain, or a Netware domain, etc. If DnsDomainName
- is NULL, just set it to NetbiosDomainName. This simplifies
- subsequent code which doesn't have to check for a NULL pointer. */
- tdom[idx].DnsDomainName = td[idx].DnsDomainName
- ? cwcsdup (td[idx].DnsDomainName)
- : tdom[idx].NetbiosDomainName;
- if (td[idx].DomainSid)
- {
- ULONG len = RtlLengthSid (td[idx].DomainSid);
- tdom[idx].DomainSid = cmalloc_abort(HEAP_BUF, len);
- RtlCopySid (len, tdom[idx].DomainSid, td[idx].DomainSid);
- }
- /* ...and set PosixOffset to 0. This */
- tdom[idx].PosixOffset = 0;
- }
- NetApiBufferFree (td);
- tdom_count = tdom_cnt;
- }
- /* If we have Microsoft Client for NFS installed, we make use of a name
- mapping server. This can be either Active Directory to map uids/gids
- directly to Windows SIDs, or an AD LDS or other RFC 2307 compatible
- identity store. The name of the mapping domain can be fetched from the
- registry key created by the NFS client installation and entered by the
- user via nfsadmin or the "Services For NFS" MMC snap-in.
-
- Reference:
- http://blogs.technet.com/b/filecab/archive/2012/10/09/nfs-identity-mapping-in-windows-server-2012.aspx
- Note that we neither support UNMP nor local passwd/group file mapping,
- nor UUUA.
-
- This function returns the mapping server from the aforementioned registry
- key, or, if none is configured, NULL, which will be resolved to the
- primary domain of the machine by the ldap_init function.
-
- The latter is useful to get an RFC 2307 mapping for Samba UNIX accounts,
- even if no NFS name mapping is configured on the machine. Fortunately,
- the posixAccount and posixGroup schemas are already available in the
- Active Directory default setup since Windows Server 2003 R2. */
- reg_key reg (HKEY_LOCAL_MACHINE, KEY_READ | KEY_WOW64_64KEY,
- L"SOFTWARE", L"Microsoft", L"ServicesForNFS", NULL);
- if (!reg.error ())
- {
- DWORD rfc2307 = reg.get_dword (L"Rfc2307", 0);
- if (rfc2307)
- {
- rfc2307_domain_buf = (PWCHAR) ccalloc_abort (HEAP_STR, 257,
- sizeof (WCHAR));
- reg.get_string (L"Rfc2307Domain", rfc2307_domain_buf, 257, L"");
- if (!rfc2307_domain_buf[0])
- {
- cfree (rfc2307_domain_buf);
- rfc2307_domain_buf = NULL;
- }
- }
- }
- return true;
-}
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ FILE_STANDARD_INFORMATION fsi;
-/* Per session, so it changes potentially when switching the user context. */
-static cygsid logon_sid ("");
+ if (buf)
+ free (buf);
+ buf = NULL;
+ curr_lines = 0;
-static void
-get_logon_sid ()
-{
- if (PSID (logon_sid) == NO_SID)
+ if (!path &&
+ !(path = (PWCHAR) malloc ((wcslen (cygheap->installation_root)
+ + wcslen (rel_path) + 1) * sizeof (WCHAR))))
{
- NTSTATUS status;
- ULONG size;
- tmp_pathbuf tp;
- PTOKEN_GROUPS groups = (PTOKEN_GROUPS) tp.c_get ();
-
- status = NtQueryInformationToken (hProcToken, TokenGroups, groups,
- NT_MAX_PATH, &size);
- if (!NT_SUCCESS (status))
- debug_printf ("NtQueryInformationToken() %y", status);
- else
- {
- for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
- if (groups->Groups[pg].Attributes & SE_GROUP_LOGON_ID)
- {
- logon_sid = groups->Groups[pg].Sid;
- break;
- }
- }
+ paranoid_printf ("malloc (%W) failed", rel_path);
+ goto out;
}
-}
-
-void *
-pwdgrp::add_account_post_fetch (char *line, bool lock)
-{
- if (line)
- {
- void *ret;
- if (lock)
- pglock.init ("pglock")->acquire ();
- add_line (line);
- ret = ((char *) pwdgrp_buf) + (curr_lines - 1) * pwdgrp_buf_elem_size;
- if (lock)
- pglock.release ();
- return ret;
- }
- return NULL;
-}
-
-void *
-pwdgrp::add_account_from_file (cygpsid &sid)
-{
- if (!path.MaximumLength)
- return NULL;
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = fetch_account_from_file (arg);
- return (struct passwd *) add_account_post_fetch (line, true);
-}
+ wcpcpy (wcpcpy (path, cygheap->installation_root), rel_path);
+ RtlInitUnicodeString (&upath, path);
-void *
-pwdgrp::add_account_from_file (const char *name)
-{
- if (!path.MaximumLength)
- return NULL;
- fetch_user_arg_t arg;
- arg.type = NAME_arg;
- arg.name = name;
- char *line = fetch_account_from_file (arg);
- return (struct passwd *) add_account_post_fetch (line, true);
-}
+ InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ etc_ix = etc::init (etc_ix, &attr);
-void *
-pwdgrp::add_account_from_file (uint32_t id)
-{
- if (!path.MaximumLength)
- return NULL;
- fetch_user_arg_t arg;
- arg.type = ID_arg;
- arg.id = id;
- char *line = fetch_account_from_file (arg);
- return (struct passwd *) add_account_post_fetch (line, true);
-}
+ paranoid_printf ("%S", &upath);
-void *
-pwdgrp::add_account_from_windows (cygpsid &sid, cyg_ldap *pldap)
-{
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = fetch_account_from_windows (arg, pldap);
- if (!line)
- return NULL;
- return add_account_post_fetch (line, true);
-}
-
-void *
-pwdgrp::add_account_from_windows (const char *name, cyg_ldap *pldap)
-{
- fetch_user_arg_t arg;
- arg.type = NAME_arg;
- arg.name = name;
- char *line = fetch_account_from_windows (arg, pldap);
- if (!line)
- return NULL;
- return add_account_post_fetch (line, true);
-}
-
-void *
-pwdgrp::add_account_from_windows (uint32_t id, cyg_ldap *pldap)
-{
- fetch_user_arg_t arg;
- arg.type = ID_arg;
- arg.id = id;
- char *line = fetch_account_from_windows (arg, pldap);
- if (!line)
- return NULL;
- return add_account_post_fetch (line, true);
-}
-
-/* Check if file exists and if it has been written to since last checked.
- If file has been changed, invalidate the current cache.
-
- If the file doesn't exist when this function is called the first time,
- by the first Cygwin process in a process tree, the file will never be
- visited again by any process in this process tree. This is important,
- because we cannot allow a change of UID/GID values for the lifetime
- of a process tree.
-
- If the file gets deleted or unreadable, the file cache will stay in
- place, but we won't try to read new accounts from the file.
-
- The return code indicates to the calling function if the file exists. */
-bool
-pwdgrp::check_file ()
-{
- FILE_BASIC_INFORMATION fbi;
- NTSTATUS status;
-
- if (!path.Buffer)
- {
- PCWSTR rel_path = is_group () ? L"\\etc\\group" : L"\\etc\\passwd";
- path.Length = (wcslen (cygheap->installation_root) + wcslen (rel_path))
- * sizeof (WCHAR);
- path.MaximumLength = path.Length + sizeof (WCHAR);
- path.Buffer = (PWCHAR) cmalloc_abort (HEAP_BUF, path.MaximumLength);
- wcpcpy (wcpcpy (path.Buffer, cygheap->installation_root), rel_path);
- InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE,
- NULL, NULL);
- }
- else if (path.MaximumLength == 0) /* Indicates that the file doesn't exist. */
- return false;
- status = NtQueryAttributesFile (&attr, &fbi);
+ status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
- if (last_modified.QuadPart)
- last_modified.QuadPart = 0LL;
- else
- path.MaximumLength = 0;
- return false;
- }
- if (fbi.LastWriteTime.QuadPart > last_modified.QuadPart)
- {
- last_modified.QuadPart = fbi.LastWriteTime.QuadPart;
- if (curr_lines > 0)
- {
- pglock.init ("pglock")->acquire ();
- int curr = curr_lines;
- curr_lines = 0;
- for (int i = 0; i < curr; ++i)
- cfree (is_group () ? this->group ()[i].g.gr_name
- : this->passwd ()[i].p.pw_name);
- pglock.release ();
- }
- }
- return true;
-}
-
-char *
-pwdgrp::fetch_account_from_line (fetch_user_arg_t &arg, const char *line)
-{
- char *p, *e;
-
- switch (arg.type)
- {
- case SID_arg:
- /* Ignore fields, just scan for SID string. */
- if (!(p = strstr (line, arg.name)) || p[arg.len] != ':')
- return NULL;
- break;
- case NAME_arg:
- /* First field is always name. */
- if (!strncasematch (line, arg.name, arg.len) || line[arg.len] != ':')
- return NULL;
- break;
- case ID_arg:
- /* Skip to third field. */
- if (!(p = strchr (line, ':')) || !(p = strchr (p + 1, ':')))
- return NULL;
- if (strtoul (p + 1, &e, 10) != arg.id || !e || *e != ':')
- return NULL;
- break;
- }
- return cstrdup (line);
-}
-
-char *
-pwdgrp::fetch_account_from_file (fetch_user_arg_t &arg)
-{
- NT_readline rl;
- tmp_pathbuf tp;
- char *buf = tp.c_get ();
- char str[128];
- char *ret = NULL;
-
- /* Create search string. */
- switch (arg.type)
- {
- case SID_arg:
- /* Override SID with SID string. */
- arg.sid->string (str);
- arg.name = str;
- /*FALLTHRU*/
- case NAME_arg:
- arg.len = strlen (arg.name);
- break;
- case ID_arg:
- break;
- }
- if (rl.init (&attr, buf, NT_MAX_PATH))
- while ((buf = rl.gets ()))
- if ((ret = fetch_account_from_line (arg, buf)))
- return ret;
- return NULL;
-}
-
-static ULONG
-fetch_posix_offset (PDS_DOMAIN_TRUSTSW td, cyg_ldap *cldap)
-{
- uint32_t id_val = UINT32_MAX;
-
- if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY) && td->DomainSid)
- {
- if (cldap->open (NULL) == NO_ERROR)
- id_val = cldap->fetch_posix_offset_for_domain (td->DnsDomainName);
- if (id_val < PRIMARY_POSIX_OFFSET)
- {
- /* If the offset is less than the primay domain offset, we're bound
- to suffer collisions with system and local accounts. Move offset
- to a fixed replacement fake offset. This may result in collisions
- between other domains all of which were moved to this replacement
- offset, but we can't fix all problems caused by careless admins. */
- id_val = UNUSABLE_POSIX_OFFSET;
- }
- else if (id_val == UINT32_MAX)
- {
- /* We're probably running under a local account, so we're not allowed
- to fetch any information from AD beyond the most obvious. Fake a
- reasonable posix offset as above and hope for the best. */
- id_val = NOACCESS_POSIX_OFFSET;
- }
- td->PosixOffset = id_val;
- }
- return td->PosixOffset;
-}
-
-/* Helper function to replace colons with semicolons in pw_gecos field. */
-static PWCHAR
-colon_to_semicolon (PWCHAR str)
-{
- PWCHAR cp = str;
- while ((cp = wcschr (cp, L':')) != NULL)
- *cp++ = L';';
- return str;
-}
-
-/* CV 2014-05-08: USER_INFO_24 is not yet defined in Mingw64, but will be in
- the next release. For the time being, define the structure here with
- another name which won't collide with the upcoming correct definition
- in lmaccess.h. */
-struct cyg_USER_INFO_24
-{
- BOOL usri24_internet_identity;
- DWORD usri24_flags;
- LPWSTR usri24_internet_provider_name;
- LPWSTR usri24_internet_principal_name;
- PSID usri24_user_sid;
-};
-
-char *
-pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
-{
- /* Used in LookupAccount calls. */
- WCHAR namebuf[UNLEN + 1], *name = namebuf;
- WCHAR dom[DNLEN + 1] = L"";
- cygsid csid;
- DWORD nlen = UNLEN + 1;
- DWORD dlen = DNLEN + 1;
- DWORD slen = SECURITY_MAX_SID_SIZE;
- cygpsid sid (NO_SID);
- SID_NAME_USE acc_type;
- BOOL ret = false;
- /* Cygwin user name style. */
- bool fully_qualified_name = false;
- /* Computed stuff. */
- uid_t uid = ILLEGAL_UID;
- gid_t gid = ILLEGAL_GID;
- bool is_domain_account = true;
- PCWSTR domain = NULL;
- PWCHAR shell = NULL;
- PWCHAR home = NULL;
- PWCHAR gecos = NULL;
- /* Temporary stuff. */
- PWCHAR p;
- WCHAR sidstr[128];
- ULONG posix_offset = 0;
- uint32_t id_val;
- cyg_ldap loc_ldap;
- cyg_ldap *cldap = pldap ?: &loc_ldap;
-
- /* Initialize */
- if (!cygheap->dom.init ())
- return NULL;
-
- switch (arg.type)
- {
- case SID_arg:
- sid = *arg.sid;
- ret = LookupAccountSidW (NULL, sid, name, &nlen, dom, &dlen, &acc_type);
- if (!ret
- && cygheap->dom.member_machine ()
- && sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_BUILTIN_DOMAIN_RID)
- {
- /* LookupAccountSid called on a non-DC cannot resolve aliases which
- are not defined in the local SAM. If we encounter an alias which
- can't be resolved, and if we're a domain member machine, ask a DC.
- Do *not* use LookupAccountSidW. It can take ages when called on a
- DC for some weird reason. Use LDAP instead. */
- PWCHAR val;
-
- if (cldap->open (NULL) == NO_ERROR
- && cldap->fetch_ad_account (sid, is_group ())
- && (val = cldap->get_group_name ()))
- {
- wcpcpy (name, val);
- wcpcpy (dom, L"BUILTIN");
- acc_type = SidTypeAlias;
- ret = true;
- }
- }
- if (!ret)
- debug_printf ("LookupAccountSid(%W), %E", sid.string (sidstr));
- break;
- case NAME_arg:
- bool fq_name;
-
- fq_name = false;
- /* Copy over to wchar for search. */
- sys_mbstowcs (name, UNLEN + 1, arg.name);
- /* Replace domain separator char with backslash and make sure p is NULL
- or points to the backslash. */
- if ((p = wcschr (name, cygheap->pg.nss_separator ()[0])))
- {
- fq_name = true;
- *p = L'\\';
- }
- sid = csid;
- ret = LookupAccountNameW (NULL, name, sid, &slen, dom, &dlen, &acc_type);
- /* If this is a name-only S-1-5-21 account *and* it's a machine account
- on a domain member machine, then we found the wrong one. Another
- weird, but perfectly valid case is, if the group name is identical
- to the domain name. Try again with domain name prepended. */
- if (ret
- && !fq_name
- && sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_NT_NON_UNIQUE
- && cygheap->dom.member_machine ()
- && (wcscasecmp (dom, cygheap->dom.account_flat_name ()) == 0
- || acc_type == SidTypeDomain))
- {
- p = wcpcpy (name, cygheap->dom.primary_flat_name ());
- *p = L'\\';
- sys_mbstowcs (p + 1, UNLEN + 1, arg.name);
- slen = SECURITY_MAX_SID_SIZE;
- dlen = DNLEN + 1;
- sid = csid;
- ret = LookupAccountNameW (NULL, name, sid, &slen, dom, &dlen,
- &acc_type);
- }
- if (!ret)
- {
- debug_printf ("LookupAccountNameW (%W), %E", name);
- return NULL;
- }
- /* We can skip the backslash in the rest of this function. */
- if (p)
- name = p + 1;
- /* Last but not least, some validity checks on the name style. */
- if (!fq_name)
- {
- /* name_only only if db_prefix is auto. */
- if (!cygheap->pg.nss_prefix_auto ())
- {
- debug_printf ("Invalid account name <%s> (name only/"
- "db_prefix not auto)", arg.name);
- return NULL;
- }
- /* name_only account is either builtin or primary domain, or
- account domain on non-domain machines. */
- if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_NT_NON_UNIQUE)
- {
- if (cygheap->dom.member_machine ())
- {
- if (wcscasecmp (dom, cygheap->dom.primary_flat_name ()) != 0)
- {
- debug_printf ("Invalid account name <%s> (name only/"
- "non primary on domain machine)", arg.name);
- return NULL;
- }
- }
- else if (wcscasecmp (dom, cygheap->dom.account_flat_name ()) != 0)
- {
- debug_printf ("Invalid account name <%s> (name only/"
- "non machine on non-domain machine)", arg.name);
- return NULL;
- }
- }
- }
- else
- {
- /* All is well if db_prefix is always. */
- if (cygheap->pg.nss_prefix_always ())
- break;
- /* Otherwise, no fully_qualified for builtin accounts. */
- if (sid_id_auth (sid) != 5 /* SECURITY_NT_AUTHORITY */
- || sid_sub_auth (sid, 0) != SECURITY_NT_NON_UNIQUE)
- {
- debug_printf ("Invalid account name <%s> (fully qualified/"
- "not NON_UNIQUE)", arg.name);
- return NULL;
- }
- /* All is well if db_prefix is primary. */
- if (cygheap->pg.nss_prefix_primary ())
- break;
- /* Domain member and domain == primary domain? */
- if (cygheap->dom.member_machine ())
- {
- if (!wcscasecmp (dom, cygheap->dom.primary_flat_name ()))
- {
- debug_printf ("Invalid account name <%s> (fully qualified/"
- "primary domain account)", arg.name);
- return NULL;
- }
- }
- /* Not domain member and domain == account domain? */
- else if (!wcscasecmp (dom, cygheap->dom.account_flat_name ()))
- {
- debug_printf ("Invalid account name <%s> (fully qualified/"
- "local account)", arg.name);
- return NULL;
- }
- }
- break;
- case ID_arg:
- /* Construct SID from ID using the SFU rules, just like the code below
- goes the opposite route. */
-#ifndef INTERIX_COMPATIBLE
- /* Except for Builtin and Alias groups in the SECURITY_NT_AUTHORITY.
- We create uid/gid values compatible with the old values generated
- by mkpasswd/mkgroup. */
- if (arg.id < 0x200)
- __small_swprintf (sidstr, L"S-1-5-%u", arg.id & 0x1ff);
- else if (arg.id == 0x3e8) /* Special case "Other Organization" */
- wcpcpy (sidstr, L"S-1-5-1000");
- else if (arg.id <= 0x7ff)
- __small_swprintf (sidstr, L"S-1-5-32-%u", arg.id & 0x7ff);
- else
-#endif
- if (arg.id == 0xffe)
- {
- /* OtherSession != Logon SID. */
- get_logon_sid ();
- /* LookupAccountSidW will fail. */
- sid = csid = logon_sid;
- sid_sub_auth_rid (sid) = 0;
- break;
- }
- else if (arg.id == 0xfff)
- {
- /* CurrentSession == Logon SID. */
- get_logon_sid ();
- /* LookupAccountSidW will fail. */
- sid = logon_sid;
- break;
- }
- else if (arg.id < 0x10000)
- {
- /* Nothing. */
- debug_printf ("Invalid POSIX id %u", arg.id);
- return NULL;
- }
- else if (arg.id < 0x20000)
- {
- /* Well-Known Group */
- arg.id -= 0x10000;
- /* SECURITY_APP_PACKAGE_AUTHORITY */
- if (arg.id >= 0xf20 && arg.id <= 0xf3f)
- __small_swprintf (sidstr, L"S-1-15-%u-%u", (arg.id >> 4) & 0xf,
- arg.id & 0xf);
- else
- __small_swprintf (sidstr, L"S-1-%u-%u", arg.id >> 8, arg.id & 0xff);
- }
- else if (arg.id >= 0x30000 && arg.id < 0x40000)
- {
- /* Account domain user or group. */
- PWCHAR s = cygheap->dom.account_sid ().pstring (sidstr);
- __small_swprintf (s, L"-%u", arg.id & 0xffff);
- }
- else if (arg.id < 0x60000)
- {
- /* Builtin Alias */
- __small_swprintf (sidstr, L"S-1-5-%u-%u",
- arg.id >> 12, arg.id & 0xffff);
- }
- else if (arg.id < 0x70000)
- {
- /* Mandatory Label. */
- __small_swprintf (sidstr, L"S-1-16-%u", arg.id & 0xffff);
- }
- else if (arg.id < 0x80000)
- {
- /* Identity assertion SIDs. */
- __small_swprintf (sidstr, L"S-1-18-%u", arg.id & 0xffff);
- }
- else if (arg.id < PRIMARY_POSIX_OFFSET)
- {
- /* Nothing. */
- debug_printf ("Invalid POSIX id %u", arg.id);
- return NULL;
- }
- else if (arg.id == ILLEGAL_UID)
- {
- /* Just some fake. */
- sid = csid = "S-1-99-0";
- break;
- }
- else if (arg.id >= UNIX_POSIX_OFFSET)
- {
- /* UNIX (unknown NFS or Samba) user account. */
- __small_swprintf (sidstr, L"S-1-22-%u-%u",
- is_group () ? 2 : 1, arg.id & UNIX_POSIX_MASK);
- /* LookupAccountSidW will fail. */
- sid = csid = sidstr;
- break;
- }
- else
- {
- /* Some trusted domain? */
- PDS_DOMAIN_TRUSTSW td = NULL, this_td = NULL;
-
- for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)
- {
- fetch_posix_offset (td, &loc_ldap);
- if (td->PosixOffset > posix_offset && td->PosixOffset <= arg.id)
- posix_offset = (this_td = td)->PosixOffset;
- }
- if (this_td)
- {
- cygpsid tsid (this_td->DomainSid);
- PWCHAR s = tsid.pstring (sidstr);
- __small_swprintf (s, L"-%u", arg.id - posix_offset);
- }
- else
- {
- /* Primary domain */
- PWCHAR s = cygheap->dom.primary_sid ().pstring (sidstr);
- __small_swprintf (s, L"-%u", arg.id - PRIMARY_POSIX_OFFSET);
- }
- posix_offset = 0;
- }
- sid = csid = sidstr;
- ret = LookupAccountSidW (NULL, sid, name, &nlen, dom, &dlen, &acc_type);
- if (!ret)
- {
- debug_printf ("LookupAccountSidW (%W), %E", sidstr);
- return NULL;
- }
- break;
- }
- if (ret)
- {
- /* Builtin account? SYSTEM, for instance, is returned as SidTypeUser,
- if a process is running as LocalSystem service.
- Microsoft Account? These show up in the user's group list, using the
- undocumented security authority 11. Even though this is officially a
- user account, it only matters as part of the group list, so we convert
- it to a well-known group here. */
- if (acc_type == SidTypeUser
- && (sid_sub_auth_count (sid) <= 3 || sid_id_auth (sid) == 11))
- acc_type = SidTypeWellKnownGroup;
- switch (acc_type)
- {
- case SidTypeUser:
- /* Don't allow users as group. While this is technically possible,
- it doesn't make sense in a POSIX scenario. It *is* used for
- Microsoft Accounts, but those are converted to well-known groups
- above. */
- if (is_group ())
- return NULL;
- /*FALLTHRU*/
- case SidTypeGroup:
- case SidTypeAlias:
- /* Predefined alias? */
- if (acc_type == SidTypeAlias
- && sid_sub_auth (sid, 0) != SECURITY_NT_NON_UNIQUE)
- {
-#ifdef INTERIX_COMPATIBLE
- posix_offset = 0x30000;
- uid = 0x1000 * sid_sub_auth (sid, 0)
- + (sid_sub_auth_rid (sid) & 0xffff);
-#else
- posix_offset = 0;
-#endif
- fully_qualified_name = cygheap->pg.nss_prefix_always ();
- is_domain_account = false;
- }
- /* Account domain account? */
- else if (!wcscasecmp (dom, cygheap->dom.account_flat_name ()))
- {
- posix_offset = 0x30000;
- if (cygheap->dom.member_machine ()
- || !cygheap->pg.nss_prefix_auto ())
- fully_qualified_name = true;
- is_domain_account = false;
- }
- /* Domain member machine? */
- else if (cygheap->dom.member_machine ())
- {
- /* Primary domain account? */
- if (!wcscasecmp (dom, cygheap->dom.primary_flat_name ()))
- {
- posix_offset = PRIMARY_POSIX_OFFSET;
- /* In theory domain should have been set to
- cygheap->dom.primary_dns_name (), but it turns out that
- not setting the domain here has advantages. We open the
- ldap connection to NULL (== some DC of our primary domain)
- anyway. So the domain is only used later on. So, don't
- set domain here to non-NULL, unless you're sure you have
- also changed subsequent assumptions that domain is NULL
- if it's a primary domain account. */
- if (!cygheap->pg.nss_prefix_auto ())
- fully_qualified_name = true;
- }
- else
- {
- /* No, fetch POSIX offset. */
- PDS_DOMAIN_TRUSTSW td = NULL;
-
- fully_qualified_name = true;
- for (ULONG idx = 0;
- (td = cygheap->dom.trusted_domain (idx));
- ++idx)
- if (!wcscasecmp (dom, td->NetbiosDomainName))
- {
- domain = td->DnsDomainName;
- posix_offset =
- fetch_posix_offset (td, &loc_ldap);
- break;
- }
-
- if (!domain)
- {
- debug_printf ("Unknown domain %W", dom);
- return NULL;
- }
- }
- }
- /* If the domain returned by LookupAccountSid is not our machine
- name, and if our machine is no domain member, we lose. We have
- nobody to ask for the POSIX offset. */
- else
- {
- debug_printf ("Unknown domain %W", dom);
- return NULL;
- }
- /* Generate values. */
- if (uid == ILLEGAL_UID)
- uid = posix_offset + sid_sub_auth_rid (sid);
-
- /* We only care for extended user information if we're creating a
- passwd entry and the account is a user or alias. */
- if (is_group () || acc_type == SidTypeGroup)
- break;
-
- if (acc_type == SidTypeUser)
- {
- /* Default primary group. If the sid is the current user, fetch
- the default group from the current user token, otherwise make
- the educated guess that the user is in group "Domain Users"
- or "None". */
- if (sid == cygheap->user.sid ())
- gid = posix_offset
- + sid_sub_auth_rid (cygheap->user.groups.pgsid);
- else
- gid = posix_offset + DOMAIN_GROUP_RID_USERS;
- }
-
- if (is_domain_account)
- {
- /* Use LDAP to fetch domain account infos. */
- if (cldap->open (NULL) != NO_ERROR)
- break;
- if (cldap->fetch_ad_account (sid, is_group (), domain))
- {
- PWCHAR val;
-
- if ((id_val = cldap->get_primary_gid ()) != ILLEGAL_GID)
- gid = posix_offset + id_val;
- if ((val = cldap->get_gecos ()))
- gecos = colon_to_semicolon (
- wcscpy ((PWCHAR) alloca ((wcslen (val) + 1)
- * sizeof (WCHAR)), val));
- if ((val = cldap->get_home ()))
- home = wcscpy ((PWCHAR) alloca ((wcslen (val) + 1)
- * sizeof (WCHAR)), val);
- if ((val = cldap->get_shell ()))
- shell = wcscpy ((PWCHAR) alloca ((wcslen (val) + 1)
- * sizeof (WCHAR)), val);
- /* Check and, if necessary, add unix<->windows id mapping on
- the fly, unless we're called from getpwent. */
- if (!pldap)
- {
- id_val = cldap->get_unix_uid ();
- if (id_val != ILLEGAL_UID
- && cygheap->ugid_cache.get_uid (id_val)
- == ILLEGAL_UID)
- cygheap->ugid_cache.add_uid (id_val, uid);
- }
- }
- }
- /* Otherwise check account domain (local SAM).*/
- else
- {
- NET_API_STATUS nas;
- PUSER_INFO_4 ui;
- PLOCALGROUP_INFO_1 gi;
- PCWSTR comment;
- PWCHAR pgrp = NULL;
- PWCHAR uxid = NULL;
- struct {
- PCWSTR str;
- size_t len;
- PWCHAR *tgt;
- bool group;
- } search[] = {
- { L"unix=\"", 6, &uxid, true },
- { L"home=\"", 6, &home, false },
- { L"shell=\"", 7, &shell, false },
- { L"group=\"", 7, &pgrp, false },
- { NULL, 0, NULL }
- };
- PWCHAR s, e;
-
- if (acc_type == SidTypeUser)
- {
- nas = NetUserGetInfo (NULL, name, 4, (PBYTE *) &ui);
- if (nas != NERR_Success)
- {
- debug_printf ("NetUserGetInfo(%W) %u", name, nas);
- break;
- }
- /* Set comment variable for below attribute loop. */
- comment = ui->usri4_comment;
- /* Logging in with a Microsoft Account, the user's primary
- group SID is the user's SID. Security sensitive tools
- expecting tight file permissions choke on that. We need
- an explicit primary group which is not identical to the
- user account. Unfortunately, while the default primary
- group of the account in SAM is still "None", "None" is not
- in the user token group list. So, what we do here is to
- use "Users" as a sane default primary group instead. */
- if (wincap.has_microsoft_accounts ())
- {
- struct cyg_USER_INFO_24 *ui24;
- nas = NetUserGetInfo (NULL, name, 24, (PBYTE *) &ui24);
- if (nas == NERR_Success)
- {
- if (ui24->usri24_internet_identity)
- gid = DOMAIN_ALIAS_RID_USERS;
- NetApiBufferFree (ui24);
- }
- }
- }
- else /* acc_type == SidTypeAlias */
- {
- nas = NetLocalGroupGetInfo (NULL, name, 1, (PBYTE *) &gi);
- if (nas != NERR_Success)
- {
- debug_printf ("NetLocalGroupGetInfo(%W) %u", name, nas);
- break;
- }
- /* Set comment variable for below attribute loop. */
- comment = gi->lgrpi1_comment;
- }
- /* Local SAM accounts have only a handful attributes
- available to home users. Therefore, fetch additional
- passwd/group attributes from the "Description" field
- in XML short style. */
- if ((s = wcsstr (comment, L"<cygwin "))
- && (e = wcsstr (s + 8, L"/>")))
- {
- s += 8;
- *e = L'\0';
- while (*s)
- {
- bool found = false;
-
- while (*s == L' ')
- ++s;
- for (size_t i = 0; search[i].str; ++i)
- if ((acc_type == SidTypeUser || search[i].group)
- && !wcsncmp (s, search[i].str, search[i].len))
- {
- s += search[i].len;
- if ((e = wcschr (s, L'"'))
- && (i > 0 || wcsncmp (name, s, e - s)))
- {
- *search[i].tgt =
- (PWCHAR) alloca ((e - s + 1)
- * sizeof (WCHAR));
- *wcpncpy (*search[i].tgt, s, e - s) = L'\0';
- s = e + 1;
- found = true;
- }
- else
- break;
- }
- if (!found)
- break;
- }
- }
- if (acc_type == SidTypeUser)
- NetApiBufferFree (ui);
- else
- NetApiBufferFree (gi);
- if (pgrp)
- {
- /* Set primary group from the "Description" field. Prepend
- account domain if this is a domain member machine or the
- db_prefix setting requires it. */
- char gname[2 * (DNLEN + UNLEN) + 2], *gp = gname;
- struct group *gr;
-
- if (cygheap->dom.member_machine ()
- || !cygheap->pg.nss_prefix_auto ())
- {
- gp = gname
- + sys_wcstombs (gname, sizeof gname,
- cygheap->dom.account_flat_name ());
- *gp++ = cygheap->pg.nss_separator ()[0];
- }
- sys_wcstombs (gp, sizeof gname - (gp - gname), pgrp);
- if ((gr = internal_getgrnam (gname, cldap)))
- gid = gr->gr_gid;
- }
- if (!pldap && uxid && ((id_val = wcstoul (uxid, &e, 10)), !*e))
- {
- if (acc_type == SidTypeUser)
- {
- if (cygheap->ugid_cache.get_uid (id_val) == ILLEGAL_UID)
- cygheap->ugid_cache.add_uid (id_val, uid);
- }
- else if (cygheap->ugid_cache.get_gid (id_val) == ILLEGAL_GID)
- cygheap->ugid_cache.add_gid (id_val, uid);
- }
- }
- break;
- case SidTypeWellKnownGroup:
- fully_qualified_name = (cygheap->pg.nss_prefix_always ()
- /* Microsoft Account */
- || sid_id_auth (sid) == 11);
-#ifdef INTERIX_COMPATIBLE
- if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth_count (sid) > 1)
- {
- uid = 0x1000 * sid_sub_auth (sid, 0)
- + (sid_sub_auth_rid (sid) & 0xffff);
- fully_qualified_name = true;
- }
- else
- uid = 0x10000 + 0x100 * sid_id_auth (sid)
- + (sid_sub_auth_rid (sid) & 0xff);
-#else
- if (sid_id_auth (sid) == 15 /* SECURITY_APP_PACKAGE_AUTHORITY */)
- uid = 0x10000 + 0x100 * sid_id_auth (sid)
- + 0x10 * sid_sub_auth (sid, 0)
- + (sid_sub_auth_rid (sid) & 0xf);
- else if (sid_id_auth (sid) != 5 /* SECURITY_NT_AUTHORITY */)
- uid = 0x10000 + 0x100 * sid_id_auth (sid)
- + (sid_sub_auth_rid (sid) & 0xff);
- else if (sid_sub_auth (sid, 0) < SECURITY_PACKAGE_BASE_RID
- || sid_sub_auth (sid, 0) > SECURITY_MAX_BASE_RID)
- uid = sid_sub_auth_rid (sid) & 0x7ff;
- else
- {
- uid = 0x1000 * sid_sub_auth (sid, 0)
- + (sid_sub_auth_rid (sid) & 0xffff);
- }
-#endif
- /* Special case for "NULL SID", S-1-0-0 and "Everyone", S-1-1-0.
- Never return "NULL SID" or Everyone as user or group. */
- if (uid == 0x10000 || uid == 0x10100)
- return NULL;
- break;
- case SidTypeLabel:
- uid = 0x60000 + sid_sub_auth_rid (sid);
- fully_qualified_name = cygheap->pg.nss_prefix_always ();
- break;
- default:
- return NULL;
- }
- }
- else if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_LOGON_IDS_RID)
- {
- /* Logon ID. Mine or other? */
- get_logon_sid ();
- if (PSID (logon_sid) == NO_SID)
- return NULL;
- if (RtlEqualSid (sid, logon_sid))
- {
- uid = 0xfff;
- wcpcpy (name = namebuf, L"CurrentSession");
- }
- else
- {
- uid = 0xffe;
- wcpcpy (name = namebuf, L"OtherSession");
- }
- acc_type = SidTypeUnknown;
- }
- else if (sid_id_auth (sid) == 18)
- {
- /* Authentication assertion SIDs.
-
- Available when using a 2012R2 DC, but not supported by
- LookupAccountXXX on pre Windows 8/2012 machines */
- uid = 0x11200 + sid_sub_auth_rid (sid);
- wcpcpy (name = namebuf, sid_sub_auth_rid (sid) == 1
- ? (PWCHAR) L"Authentication authority asserted identity"
- : (PWCHAR) L"Service asserted identity");
- fully_qualified_name = false;
- acc_type = SidTypeUnknown;
+ paranoid_printf ("NtOpenFile(%S) failed, status %y", &upath, status);
+ goto out;
}
- else if (sid_id_auth (sid) == 22)
+ status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi,
+ FileStandardInformation);
+ if (!NT_SUCCESS (status))
{
- /* Samba UNIX Users/Groups
-
- This *might* collide with a posix_offset of some trusted domain.
- It's just very unlikely. */
- uid = MAP_UNIX_TO_CYGWIN_ID (sid_sub_auth_rid (sid));
- /* Unfortunately we have no access to the file server from here,
- so we can't generate correct user names. */
- p = wcpcpy (dom, L"Unix_");
- wcpcpy (p, sid_sub_auth (sid, 0) == 1 ? L"User" : L"Group");
- __small_swprintf (name = namebuf, L"%d", uid & UNIX_POSIX_MASK);
- fully_qualified_name = true;
- acc_type = SidTypeUnknown;
+ paranoid_printf ("NtQueryInformationFile(%S) failed, status %y",
+ &upath, status);
+ goto out;
}
- else
+ /* FIXME: Should we test for HighPart set? If so, the
+ passwd or group file is way beyond what we can handle. */
+ /* FIXME 2: It's still ugly that we keep the file in memory.
+ Big organizations have naturally large passwd files. */
+ buf = (char *) malloc (fsi.EndOfFile.LowPart + 1);
+ if (!buf)
{
- if (cygheap->dom.member_machine ()
- && sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_NT_NON_UNIQUE)
- {
- /* Check if we know the domain. If so, create a passwd/group
- entry with domain prefix and RID as username. */
- PDS_DOMAIN_TRUSTSW td = NULL;
-
- sid_sub_auth_count (sid) = sid_sub_auth_count (sid) - 1;
- if (RtlEqualSid (sid, cygheap->dom.primary_sid ()))
- {
- domain = cygheap->dom.primary_flat_name ();
- posix_offset = PRIMARY_POSIX_OFFSET;
- }
- else
- for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)
- if (td->DomainSid && RtlEqualSid (sid, td->DomainSid))
- {
- domain = td->NetbiosDomainName;
- posix_offset = fetch_posix_offset (td, &loc_ldap);
- break;
- }
- }
- if (domain)
- {
- sid_sub_auth_count (sid) = sid_sub_auth_count (sid) + 1;
- wcscpy (dom, domain);
- __small_swprintf (name = namebuf, L"%W(%u)",
- is_group () ? L"Group" : L"User",
- sid_sub_auth_rid (sid));
- uid = posix_offset + sid_sub_auth_rid (sid);
- }
- else
- {
- wcpcpy (dom, L"Unknown");
- wcpcpy (name = namebuf, is_group () ? L"Group" : L"User");
- }
- fully_qualified_name = true;
- acc_type = SidTypeUnknown;
+ paranoid_printf ("malloc (%u) failed", fsi.EndOfFile.LowPart);
+ goto out;
}
-
- tmp_pathbuf tp;
- PWCHAR linebuf = tp.w_get ();
- char *line = NULL;
-
- WCHAR posix_name[UNLEN + 1 + DNLEN + 1];
- p = posix_name;
- if (gid == ILLEGAL_GID)
- gid = uid;
- if (fully_qualified_name)
- p = wcpcpy (wcpcpy (p, dom), cygheap->pg.nss_separator ());
- wcpcpy (p, name);
-
- if (is_group ())
- __small_swprintf (linebuf, L"%W:%W:%u:",
- posix_name, sid.string (sidstr), uid);
- /* For non-users, create a passwd entry which doesn't allow interactive
- logon. Unless it's the SYSTEM account. This conveniently allows to
- logon interactively as SYSTEM for debugging purposes. */
- else if (acc_type != SidTypeUser && sid != well_known_system_sid)
- __small_swprintf (linebuf, L"%W:*:%u:%u:,%W:/:/sbin/nologin",
- posix_name, uid, gid, sid.string (sidstr));
- else
- __small_swprintf (linebuf, L"%W:*:%u:%u:%W%WU-%W\\%W,%W:%W%W:%W",
- posix_name, uid, gid,
- gecos ?: L"", gecos ? L"," : L"",
- dom, name,
- sid.string (sidstr),
- home ? L"" : L"/home/", home ?: name,
- shell ?: L"/bin/bash");
- sys_wcstombs_alloc (&line, HEAP_BUF, linebuf);
- debug_printf ("line: <%s>", line);
- return line;
-}
-
-client_request_pwdgrp::client_request_pwdgrp (fetch_user_arg_t &arg, bool group)
- : client_request (CYGSERVER_REQUEST_PWDGRP, &_parameters, sizeof (_parameters))
-{
- size_t len = 0;
- char *p;
-
- _parameters.in.group = group;
- _parameters.in.type = arg.type;
- switch (arg.type)
- {
- case SID_arg:
- RtlCopySid (sizeof (DBGSID), (PSID) &_parameters.in.arg.sid, *arg.sid);
- len = RtlLengthSid (*arg.sid);
- break;
- case NAME_arg:
- p = stpcpy (_parameters.in.arg.name, arg.name);
- len = p - _parameters.in.arg.name + 1;
- break;
- case ID_arg:
- _parameters.in.arg.id = arg.id;
- len = sizeof (uint32_t);
- }
- msglen (__builtin_offsetof (struct _pwdgrp_param_t::_pwdgrp_in_t, arg) + len);
-}
-
-char *
-pwdgrp::fetch_account_from_cygserver (fetch_user_arg_t &arg)
-{
- client_request_pwdgrp request (arg, is_group ());
- if (request.make_request () == -1 || request.error_code ())
+ status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
+ NULL, NULL);
+ if (!NT_SUCCESS (status))
{
- /* Cygserver not running? Don't try again. This will automatically
- avoid an endless loop in cygserver itself. */
- if (request.error_code () == ENOSYS)
- cygheap->pg.nss_disable_cygserver_caching ();
- return NULL;
- }
- if (!request.line ())
- return NULL;
- return cstrdup (request.line ());
-}
-
-void *
-pwdgrp::add_account_from_cygserver (cygpsid &sid)
-{
- /* No, Everyone is no group in terms of POSIX. */
- if (sid_id_auth (sid) == 1 /* SECURITY_WORLD_SID_AUTHORITY */
- && sid_sub_auth (sid, 0) == SECURITY_WORLD_RID)
- return NULL;
- fetch_user_arg_t arg;
- arg.type = SID_arg;
- arg.sid = &sid;
- char *line = fetch_account_from_cygserver (arg);
- return add_account_post_fetch (line, true);
-}
-
-void *
-pwdgrp::add_account_from_cygserver (const char *name)
-{
- fetch_user_arg_t arg;
- arg.type = NAME_arg;
- arg.name = name;
- char *line = fetch_account_from_cygserver (arg);
- return add_account_post_fetch (line, true);
-}
-
-void *
-pwdgrp::add_account_from_cygserver (uint32_t id)
-{
- fetch_user_arg_t arg;
- arg.type = ID_arg;
- arg.id = id;
- char *line = fetch_account_from_cygserver (arg);
- return add_account_post_fetch (line, true);
+ paranoid_printf ("NtReadFile(%S) failed, status %y", &upath, status);
+ free (buf);
+ goto out;
+ }
+ buf[fsi.EndOfFile.LowPart] = '\0';
+ for (char *eptr = buf; (eptr = add_line (eptr)); )
+ continue;
+ debug_printf ("%W curr_lines %d", rel_path, curr_lines);
+ res = succeeded;
+
+out:
+ if (fh)
+ NtClose (fh);
+ debug_printf ("%W load %s", rel_path, res);
+ initialized = true;
}
diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc
index b586e6374..2990a01da 100644
--- a/winsup/cygwin/uname.cc
+++ b/winsup/cygwin/uname.cc
@@ -45,7 +45,12 @@ uname (struct utsname *name)
cygwin_version.dll_major / 1000,
cygwin_version.dll_major % 1000,
cygwin_version.dll_minor,
+#if 0
snp ? "s" : "",
+#else
+ /* Add a hint to allow to recognize updates */
+ "-2",
+#endif
cygwin_version.api_major,
cygwin_version.api_minor,
cygwin_version.shared_data,
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index f6faa03b6..cdbb1c37e 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -2,7 +2,7 @@
capability class to the appropriate values.
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- 2012, 2013, 2014 Red Hat, Inc.
+ 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -49,7 +49,6 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_pipe_reject_remote_clients:false,
terminate_thread_frees_stack:false,
has_precise_system_time:false,
- has_microsoft_accounts:false,
};
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -78,7 +77,6 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_pipe_reject_remote_clients:false,
terminate_thread_frees_stack:false,
has_precise_system_time:false,
- has_microsoft_accounts:false,
};
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -107,7 +105,6 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
has_precise_system_time:false,
- has_microsoft_accounts:false,
};
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -136,7 +133,6 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
has_precise_system_time:false,
- has_microsoft_accounts:false,
};
wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -165,7 +161,6 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
has_precise_system_time:true,
- has_microsoft_accounts:true,
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 43c72b648..98fef2656 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -1,7 +1,7 @@
/* wincap.h: Header for OS capability class.
Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
- 2012, 2013, 2014 Red Hat, Inc.
+ 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -39,7 +39,6 @@ struct wincaps
unsigned has_pipe_reject_remote_clients : 1;
unsigned terminate_thread_frees_stack : 1;
unsigned has_precise_system_time : 1;
- unsigned has_microsoft_accounts : 1;
};
class wincapc
@@ -90,7 +89,6 @@ public:
bool IMPLEMENT (has_pipe_reject_remote_clients)
bool IMPLEMENT (terminate_thread_frees_stack)
bool IMPLEMENT (has_precise_system_time)
- bool IMPLEMENT (has_microsoft_accounts)
#undef IMPLEMENT
};
diff --git a/winsup/cygwin/winlean.h b/winsup/cygwin/winlean.h
index 63cebdb96..64e689dd4 100644
--- a/winsup/cygwin/winlean.h
+++ b/winsup/cygwin/winlean.h
@@ -1,6 +1,6 @@
/* winlean.h - Standard "lean" windows include
- Copyright 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
+ Copyright 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 2be96f8ef..99b3e0763 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -177,8 +177,20 @@ void __reg1 do_exit (int) __attribute__ ((noreturn));
/* libstdc++ malloc operator wrapper support. */
extern struct per_process_cxx_malloc default_cygwin_cxx_malloc;
+/* UID/GID */
+void uinfo_init ();
+
+#define ILLEGAL_UID ((uid_t)-1)
+#define ILLEGAL_GID ((gid_t)-1)
#define ILLEGAL_SEEK ((off_t)-1)
+#ifndef __x86_64__
+#define ILLEGAL_UID16 ((__uid16_t)-1)
+#define ILLEGAL_GID16 ((__gid16_t)-1)
+#define uid16touid32(u16) ((u16)==ILLEGAL_UID16?ILLEGAL_UID:(uid_t)(u16))
+#define gid16togid32(g16) ((g16)==ILLEGAL_GID16?ILLEGAL_GID:(gid_t)(g16))
+#endif
+
/* Convert LARGE_INTEGER into long long */
#define get_ll(pl) (((long long) (pl).HighPart << 32) | (pl).LowPart)
@@ -290,17 +302,6 @@ extern "C" char _data_start__, _data_end__, _bss_start__, _bss_end__;
extern "C" void (*__CTOR_LIST__) (void);
extern "C" void (*__DTOR_LIST__) (void);
-#ifdef NEEDED
-/* This was inexplicably needed after updating a toolchain.
- The need disappeared when updating further but I'm keeping
- it around temporarily in case the issue crops up again.
- This manifests as SEGVs in one of the Interlocked functions below
- in kernel32.dll. */
-#define InterlockedDecrement _InterlockedDecrement
-#define InterlockedExchange _InterlockedExchange
-#define InterlockedIncrement _InterlockedIncrement
-#endif /*NEEDED*/
-
#ifndef NO_GLOBALS_H
#define _RDATA /* See globals.h */
#include "globals.h"