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:
authorCorinna Vinschen <corinna@vinschen.de>2014-02-09 23:44:56 +0400
committerCorinna Vinschen <corinna@vinschen.de>2014-02-09 23:44:56 +0400
commit1ca20a1cd208e95f5e38ed8b8bcc6a2dad376228 (patch)
tree0c90ef25cc428eed933d882d3d73c333a42c6319 /winsup/cygwin
parent01fc6f8d21299ef8e196d2155cd35973d08f398e (diff)
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.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/ChangeLog144
-rw-r--r--winsup/cygwin/Makefile.in4
-rw-r--r--winsup/cygwin/autoload.cc25
-rw-r--r--winsup/cygwin/cygheap.h83
-rw-r--r--winsup/cygwin/cygtls.h21
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc47
-rw-r--r--winsup/cygwin/fhandler_process.cc3
-rw-r--r--winsup/cygwin/fhandler_procsysvipc.cc3
-rw-r--r--winsup/cygwin/fhandler_registry.cc4
-rw-r--r--winsup/cygwin/grp.cc294
-rw-r--r--winsup/cygwin/ldap.cc443
-rw-r--r--winsup/cygwin/ldap.h68
-rw-r--r--winsup/cygwin/passwd.cc213
-rw-r--r--winsup/cygwin/path.cc136
-rw-r--r--winsup/cygwin/path.h17
-rw-r--r--winsup/cygwin/pinfo.cc4
-rw-r--r--winsup/cygwin/pwdgrp.h168
-rw-r--r--winsup/cygwin/sec_acl.cc3
-rw-r--r--winsup/cygwin/sec_auth.cc88
-rw-r--r--winsup/cygwin/sec_helper.cc88
-rw-r--r--winsup/cygwin/security.cc3
-rw-r--r--winsup/cygwin/security.h49
-rw-r--r--winsup/cygwin/setlsapwd.cc3
-rw-r--r--winsup/cygwin/shared.cc2
-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.cc1194
-rw-r--r--winsup/cygwin/winsup.h14
29 files changed, 2717 insertions, 837 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 644930c36..a53aad0e8 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,144 @@
+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
@@ -21,6 +162,9 @@
* net.cc (cygwin_gethostname): Call GetComputerNameExA rather than
GetComputerNameA if gethostname failed.
* shared.cc (user_info::initialize): Fix formatting.
+
+2014-02-06 Corinna Vinschen <corinna@vinschen.de>
+
* include/sys/file.h: Define flock and accompanying macros if not
already defined in sys/_default_fcntl.h.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index b47330379..6065d120c 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -1,6 +1,6 @@
# Makefile.in for Cygwin.
# Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
+# 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
#
# This file is part of Cygwin.
#
@@ -166,7 +166,7 @@ DLL_OFILES:=advapi32.o arc4random.o assert.o autoload.o base64.o bsdlib.o ctype.
fhandler_termios.o fhandler_tty.o fhandler_virtual.o fhandler_windows.o \
fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \
glob_pattern_p.o globals.o grp.o heap.o hookapi.o inet_addr.o \
- inet_network.o init.o ioctl.o ipc.o kernel32.o libstdcxx_wrapper.o \
+ inet_network.o init.o ioctl.o ipc.o kernel32.o ldap.o libstdcxx_wrapper.o \
localtime.o lsearch.o malloc_wrapper.o minires-os-if.o minires.o \
miscfuncs.o mktemp.o mmap.o msg.o mount.o net.o netdb.o nfs.o nftw.o \
nlsfuncs.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o \
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 0199cc553..15d185a84 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 Red Hat, Inc.
+ 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -580,14 +580,37 @@ 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_valuesW, 0, wldap32)
+LoadDLLfunc (ldap_first_entry, 0, wldap32)
+LoadDLLfunc (ldap_get_valuesW, 0, wldap32)
+LoadDLLfunc (ldap_get_values_lenW, 0, wldap32)
+LoadDLLfunc (ldap_initW, 0, wldap32)
+LoadDLLfunc (ldap_memfreeW, 0, wldap32)
+LoadDLLfunc (ldap_next_entry, 0, wldap32)
+LoadDLLfunc (ldap_search_stW, 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)
+#pragma pop_macro ("mangle")
+
LoadDLLfunc (WNetCloseEnum, 4, mpr)
LoadDLLfunc (WNetEnumResourceA, 16, mpr)
LoadDLLfunc (WNetGetProviderNameA, 12, mpr)
LoadDLLfunc (WNetGetResourceInformationA, 16, mpr)
LoadDLLfunc (WNetOpenEnumA, 20, mpr)
+LoadDLLfunc (DsEnumerateDomainTrustsW, 16, netapi32)
LoadDLLfunc (DsGetDcNameW, 24, netapi32)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
+LoadDLLfunc (NetGroupGetInfo, 16, netapi32)
LoadDLLfunc (NetUseGetInfo, 16, netapi32)
LoadDLLfunc (NetUserGetGroups, 28, netapi32)
LoadDLLfunc (NetUserGetInfo, 16, netapi32)
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 164a87090..a6cfd9d44 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -1,7 +1,7 @@
/* cygheap.h: Cygwin heap manager.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011, 2012, 2013 Red Hat, Inc.
+ 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,6 +11,7 @@ details. */
#include "hires.h"
#include "cygheap_malloc.h"
+#include "pwdgrp.h"
#define incygheap(s) (cygheap && ((char *) (s) >= (char *) cygheap) && ((char *) (s) <= ((char *) cygheap_max)))
@@ -355,6 +356,84 @@ 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:
+ ULONG lowest_tdo_posix_offset;
+
+ 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;
+
+ void nss_init_line (const char *line);
+ void _nss_init ();
+
+public:
+ struct {
+ pwdgrp file;
+ pwdgrp win;
+ } pwd_cache;
+ struct {
+ 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_db_caching () const { return caching; }
+};
+
struct hook_chain
{
void **loc;
@@ -378,6 +457,8 @@ 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_user user;
user_heap_info user_heap;
mode_t umask;
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index d475508e2..2c4f921a8 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -1,7 +1,7 @@
/* cygtls.h
- Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
- Red Hat, Inc.
+ Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
+ 2014 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@@ -79,20 +79,19 @@ public:
struct _local_storage
{
- /*
- Needed for the group functions
- */
- int grp_pos;
+ /* passwd.cc */
+ void *pwbuf;
+ char pass[_PASSWORD_LEN];
+ ULONG pw_pos;
+
+ /* grp.cc */
+ void *grbuf;
+ ULONG 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/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 8f4720e99..aea390508 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -10,6 +10,8 @@ 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>
@@ -23,10 +25,8 @@ 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,6 +323,9 @@ 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 ())
{
@@ -340,14 +343,36 @@ 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;
- /* 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
+ /* 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 = ugid_cache.get_uid (nfs_attr->uid);
+ buf->st_gid = 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)))
+ map_uid = cldap.remap_uid (nfs_attr->uid);
+ if (map_uid == ILLEGAL_UID)
+ map_uid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->uid);
+ 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)))
+ map_gid = cldap.remap_gid (nfs_attr->gid);
+ if (map_gid == ILLEGAL_GID)
+ map_gid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->gid);
+ ugid_cache.add_gid (nfs_attr->gid, map_gid);
+ buf->st_gid = map_gid;
+ }
buf->st_rdev = makedev (nfs_attr->rdev.specdata1,
nfs_attr->rdev.specdata2);
buf->st_size = nfs_attr->size;
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index 8776702a6..fa628a65e 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -1,7 +1,7 @@
/* fhandler_process.cc: fhandler for /proc/<pid> virtual filesystem
Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
- 2013 Red Hat, Inc.
+ 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -24,7 +24,6 @@ details. */
#include "cygheap.h"
#include "ntdll.h"
#include "cygtls.h"
-#include "pwdgrp.h"
#include "mount.h"
#include "tls_pbuf.h"
#include <sys/sysmacros.h>
diff --git a/winsup/cygwin/fhandler_procsysvipc.cc b/winsup/cygwin/fhandler_procsysvipc.cc
index 6c2aa4006..c285f5536 100644
--- a/winsup/cygwin/fhandler_procsysvipc.cc
+++ b/winsup/cygwin/fhandler_procsysvipc.cc
@@ -1,6 +1,6 @@
/* fhandler_procsysvipc.cc: fhandler for /proc/sysvipc virtual filesystem
- Copyright 2011, 2012, 2013 Red Hat, Inc.
+ Copyright 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -24,7 +24,6 @@ details. */
#include "cygheap.h"
#include "ntdll.h"
#include "cygtls.h"
-#include "pwdgrp.h"
#include "tls_pbuf.h"
#include <sys/param.h>
#include <ctype.h>
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
index d4b6706c7..fd3b76824 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 = UNKNOWN_UID;
- buf->st_gid = UNKNOWN_GID;
+ buf->st_uid = ILLEGAL_UID;
+ buf->st_gid = ILLEGAL_GID;
buf->st_mode &= ~0777;
}
}
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index 7ff9e59b2..09a8daa37 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 Red Hat, Inc.
+ 2008, 2009, 2011, 2012, 2013, 2014 Red Hat, Inc.
Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com
First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de
@@ -23,134 +23,163 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
-#include "pwdgrp.h"
-static group *group_buf;
-static pwdgrp gr (group_buf);
static char * NO_COPY_RO null_ptr;
bool
pwdgrp::parse_group ()
{
- group &grp = (*group_buf)[curr_lines];
- grp.gr_name = next_str (':');
- if (!*grp.gr_name)
+ pg_grp &grp = group ()[curr_lines];
+ grp.g.gr_name = next_str (':');
+ if (!*grp.g.gr_name)
return false;
-
- grp.gr_passwd = next_str (':');
-
- if (!next_num (grp.gr_gid))
+ grp.g.gr_passwd = next_str (':');
+ if (!next_num (grp.g.gr_gid))
return false;
-
int n;
char *dp = raw_ptr ();
for (n = 0; *next_str (','); n++)
continue;
-
- grp.gr_mem = &null_ptr;
+ grp.g.gr_mem = &null_ptr;
if (n)
{
- char **namearray = (char **) calloc (n + 1, sizeof (char *));
+ char **namearray = (char **) ccalloc (HEAP_BUF, 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;
+ grp.g.gr_mem = namearray;
}
}
-
+ grp.sid.getfromgr (&grp.g);
return true;
}
-/* 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 */
+muto NO_COPY pwdgrp::pglock;
+
void
-pwdgrp::read_group ()
+pwdgrp::init_grp ()
{
- for (int i = 0; i < gr.curr_lines; i++)
- if ((*group_buf)[i].gr_mem != &null_ptr)
- free ((*group_buf)[i].gr_mem);
-
- load (L"\\etc\\group");
+ pwdgrp_buf_elem_size = sizeof (pg_grp);
+ parse = &pwdgrp::parse_group;
+}
- /* Complete /etc/group in memory if needed */
- if (!internal_getgrgid (myself->gid))
+pwdgrp *
+pwdgrp::prep_tls_grbuf ()
+{
+ if (!_my_tls.locals.grbuf)
{
- 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);
+ _my_tls.locals.grbuf = ccalloc_abort (HEAP_BUF, 1,
+ sizeof (pwdgrp) + sizeof (pg_grp));
+ pwdgrp *gr = (pwdgrp *) _my_tls.locals.grbuf;
+ gr->init_grp ();
+ gr->pwdgrp_buf = (void *) (gr + 1);
+ gr->max_lines = 1;
}
- static char NO_COPY pretty_ls[] = "????????::-1:";
- add_line (pretty_ls);
-}
+ pwdgrp *gr = (pwdgrp *) _my_tls.locals.grbuf;
+ if (gr->curr_lines)
+ {
+ cfree (gr->group ()[0].g.gr_name);
+ gr->curr_lines = 0;
+ }
+ return gr;
+}
-muto NO_COPY pwdgrp::pglock;
+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;
+}
-pwdgrp::pwdgrp (passwd *&pbuf) :
- pwdgrp_buf_elem_size (sizeof (*pbuf)), passwd_buf (&pbuf)
+struct group *
+pwdgrp::find_group (const char *name)
{
- read = &pwdgrp::read_passwd;
- parse = &pwdgrp::parse_passwd;
- pglock.init ("pglock");
+ for (ULONG i = 0; i < curr_lines; i++)
+ if (strcasematch (group ()[i].g.gr_name, name))
+ return &group ()[i].g;
+ return NULL;
}
-pwdgrp::pwdgrp (group *&gbuf) :
- pwdgrp_buf_elem_size (sizeof (*gbuf)), group_buf (&gbuf)
+struct group *
+pwdgrp::find_group (gid_t gid)
{
- read = &pwdgrp::read_group;
- parse = &pwdgrp::parse_group;
- pglock.init ("pglock");
+ for (ULONG i = 0; i < curr_lines; i++)
+ if (gid == group ()[i].g.gr_gid)
+ return &group ()[i].g;
+ return NULL;
}
struct group *
internal_getgrsid (cygpsid &sid)
{
- char sid_string[128];
-
- gr.refresh (false);
+ struct group *ret;
- 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;
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_grp_files ())
+ {
+ cygheap->pg.grp_cache.file.check_file (true);
+ if ((ret = cygheap->pg.grp_cache.file.find_group (sid)))
+ return ret;
+ if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (sid)))
+ return ret;
+ }
+ if (cygheap->pg.nss_grp_db ())
+ {
+ if ((ret = cygheap->pg.grp_cache.win.find_group (sid)))
+ return ret;
+ return cygheap->pg.grp_cache.win.add_group_from_windows (sid);
+ }
return NULL;
}
struct group *
-internal_getgrgid (gid_t gid, bool check)
+internal_getgrnam (const char *name)
{
- gr.refresh (check);
+ struct group *ret;
- for (int i = 0; i < gr.curr_lines; i++)
- if (group_buf[i].gr_gid == gid)
- return group_buf + i;
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_grp_files ())
+ {
+ cygheap->pg.grp_cache.file.check_file (true);
+ if ((ret = cygheap->pg.grp_cache.file.find_group (name)))
+ return ret;
+ if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (name)))
+ return ret;
+ }
+ if (cygheap->pg.nss_grp_db ())
+ {
+ if ((ret = cygheap->pg.grp_cache.win.find_group (name)))
+ return ret;
+ return cygheap->pg.grp_cache.win.add_group_from_windows (name);
+ }
return NULL;
}
struct group *
-internal_getgrnam (const char *name, bool check)
+internal_getgrgid (gid_t gid)
{
- gr.refresh (check);
-
- for (int i = 0; i < gr.curr_lines; i++)
- if (strcasematch (group_buf[i].gr_name, name))
- return group_buf + i;
+ struct group *ret;
- /* Didn't find requested group */
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_grp_files ())
+ {
+ cygheap->pg.grp_cache.file.check_file (true);
+ if ((ret = cygheap->pg.grp_cache.file.find_group (gid)))
+ return ret;
+ if ((ret = cygheap->pg.grp_cache.file.add_group_from_file (gid)))
+ return ret;
+ }
+ if (cygheap->pg.nss_grp_db ())
+ {
+ if ((ret = cygheap->pg.grp_cache.win.find_group (gid)))
+ return ret;
+ return cygheap->pg.grp_cache.win.add_group_from_windows (gid);
+ }
+ else if (gid == ILLEGAL_GID)
+ return cygheap->pg.grp_cache.win.add_group_from_windows (gid);
return NULL;
}
@@ -181,7 +210,7 @@ getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize,
if (!grp || !buffer)
return ERANGE;
- struct group *tempgr = internal_getgrgid (gid, true);
+ struct group *tempgr = internal_getgrgid (gid);
pthread_testcancel ();
if (!tempgr)
return 0;
@@ -211,7 +240,7 @@ getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize,
extern "C" struct group *
getgrgid32 (gid_t gid)
{
- return internal_getgrgid (gid, true);
+ return internal_getgrgid (gid);
}
#ifdef __x86_64__
@@ -235,7 +264,7 @@ getgrnam_r (const char *nam, struct group *grp, char *buffer,
if (!grp || !buffer)
return ERANGE;
- struct group *tempgr = internal_getgrnam (nam, true);
+ struct group *tempgr = internal_getgrnam (nam);
pthread_testcancel ();
if (!tempgr)
return 0;
@@ -265,7 +294,7 @@ getgrnam_r (const char *nam, struct group *grp, char *buffer,
extern "C" struct group *
getgrnam32 (const char *name)
{
- return internal_getgrnam (name, true);
+ return internal_getgrnam (name);
}
#ifdef __x86_64__
@@ -289,11 +318,19 @@ endgrent ()
extern "C" struct group *
getgrent32 ()
{
- 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++;
-
+ pwdgrp &grf = cygheap->pg.grp_cache.file;
+ if (cygheap->pg.nss_grp_files ())
+ {
+ cygheap->pg.grp_cache.file.check_file (true);
+ if (_my_tls.locals.grp_pos < grf.cached_groups ())
+ return &grf.group ()[_my_tls.locals.grp_pos++].g;
+ }
+ if ((cygheap->pg.nss_grp_db ()) && cygheap->pg.nss_db_caching ())
+ {
+ pwdgrp &grw = cygheap->pg.grp_cache.win;
+ if (_my_tls.locals.grp_pos - grf.cached_groups () < grw.cached_groups ())
+ return &grw.group ()[_my_tls.locals.grp_pos++ - grf.cached_groups ()].g;
+ }
return NULL;
}
@@ -315,46 +352,29 @@ setgrent ()
_my_tls.locals.grp_pos = 0;
}
-/* Internal function. ONLY USE THIS INTERNALLY, NEVER `getgrent'!!! */
-struct group *
-internal_getgrent (int pos)
-{
- gr.refresh (false);
-
- if (pos < gr.curr_lines)
- return group_buf + pos;
- return NULL;
-}
-
int
-internal_getgroups (int gidsetsize, gid_t *grouplist, cygpsid * srchsid)
+internal_getgroups (int gidsetsize, gid_t *grouplist, cygpsid *srchsid)
{
NTSTATUS status;
HANDLE hToken = NULL;
ULONG size;
int cnt = 0;
- struct group *gr;
+ struct group *grp;
if (!srchsid && cygheap->user.groups.issetgroups ())
{
- 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;
- }
+ for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
+ if ((grp = internal_getgrsid (cygheap->user.groups.sgsids.sids[pg])))
+ {
+ if (cnt < gidsetsize)
+ grouplist[cnt] = grp->gr_gid;
+ ++cnt;
+ if (gidsetsize && cnt > gidsetsize)
+ goto error;
+ }
return cnt;
}
-
/* If impersonated, use impersonation token. */
if (cygheap->user.issetuid ())
hToken = cygheap->user.primary_token ();
@@ -379,21 +399,25 @@ internal_getgroups (int gidsetsize, gid_t *grouplist, cygpsid * srchsid)
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)
+ {
+ for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ {
+ cygpsid sid = groups->Groups[pg].Sid;
+ if ((grp = internal_getgrsid (sid)))
{
- if (cnt < gidsetsize)
- grouplist[cnt] = gr->gr_gid;
- ++cnt;
- if (gidsetsize && cnt > gidsetsize)
- goto error;
- break;
+ if ((groups->Groups[pg].Attributes
+ & (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED))
+ && sid != well_known_world_sid)
+ {
+ if (cnt < gidsetsize)
+ grouplist[cnt] = grp->gr_gid;
+ ++cnt;
+ if (gidsetsize && cnt > gidsetsize)
+ goto error;
+ }
}
+ }
+ }
}
}
else
@@ -443,11 +467,11 @@ get_groups (const char *user, gid_t gid, cygsidlist &gsids)
{
cygheap->user.deimpersonate ();
struct passwd *pw = internal_getpwnam (user);
- struct group *gr = internal_getgrgid (gid);
+ struct group *grp = internal_getgrgid (gid);
cygsid usersid, grpsid;
if (usersid.getfrompw (pw))
get_server_groups (gsids, usersid, pw);
- if (grpsid.getfromgr (gr))
+ if (grpsid.getfromgr (grp))
gsids += grpsid;
cygheap->user.reimpersonate ();
}
@@ -482,7 +506,7 @@ getgrouplist (const char *user, gid_t gid, gid_t *groups, int *ngroups)
{
int ret = 0;
int cnt = 0;
- struct group *gr;
+ struct group *grp;
/* 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.
@@ -495,10 +519,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 ((gr = internal_getgrsid (tmp_gsids.sids[i])) != NULL)
+ if ((grp = internal_getgrsid (tmp_gsids.sids[i])) != NULL)
{
if (groups && cnt < *ngroups)
- groups[cnt] = gr->gr_gid;
+ groups[cnt] = grp->gr_gid;
++cnt;
}
if (cnt > *ngroups)
@@ -522,15 +546,15 @@ setgroups32 (int ngroups, const gid_t *grouplist)
}
cygsidlist gsids (cygsidlist_alloc, ngroups);
- struct group *gr;
+ struct group *grp;
if (ngroups && !gsids.sids)
return -1;
for (int gidx = 0; gidx < ngroups; ++gidx)
{
- if ((gr = internal_getgrgid (grouplist[gidx]))
- && gsids.addfromgr (gr))
+ if ((grp = internal_getgrgid (grouplist[gidx]))
+ && gsids.addfromgr (grp))
continue;
debug_printf ("No sid found for gid %u", grouplist[gidx]);
gsids.free_sids ();
diff --git a/winsup/cygwin/ldap.cc b/winsup/cygwin/ldap.cc
new file mode 100644
index 000000000..de09aa2f6
--- /dev/null
+++ b/winsup/cygwin/ldap.cc
@@ -0,0 +1,443 @@
+/* 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"
+
+static LDAP_TIMEVAL tv = { 3, 0 };
+
+static PWCHAR rootdse_attr[] =
+{
+ (PWCHAR) L"defaultNamingContext",
+ (PWCHAR) L"supportedCapabilities",
+ NULL
+};
+
+static PWCHAR user_attr[] =
+{
+ (PWCHAR) L"uid",
+ (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 nfs_attr[] =
+{
+ (PWCHAR) L"objectSid",
+ NULL
+};
+
+PWCHAR rfc2307_uid_attr[] =
+{
+ (PWCHAR) L"uid",
+ NULL
+};
+
+PWCHAR rfc2307_gid_attr[] =
+{
+ (PWCHAR) L"cn",
+ NULL
+};
+
+DWORD WINAPI
+rediscover_thread (LPVOID dummy)
+{
+ PDOMAIN_CONTROLLER_INFOW pdci;
+ DWORD ret = DsGetDcNameW (NULL, (PWCHAR) dummy, NULL, NULL,
+ DS_FORCE_REDISCOVERY | DS_ONLY_LDAP_NEEDED, &pdci);
+ if (ret == ERROR_SUCCESS)
+ NetApiBufferFree (pdci);
+ else
+ debug_printf ("DsGetDcNameW(%W) failed with error %u", dummy, ret);
+ return 0;
+}
+
+bool
+cyg_ldap::connect_ssl (PCWSTR domain)
+{
+ ULONG ret, timelimit = 3; /* secs */
+
+ if (!(lh = ldap_sslinitW ((PWCHAR) domain, LDAP_SSL_PORT, 1)))
+ {
+ debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ());
+ return false;
+ }
+ if ((ret = ldap_set_option (lh, LDAP_OPT_TIMELIMIT, &timelimit))
+ != LDAP_SUCCESS)
+ debug_printf ("ldap_set_option(LDAP_OPT_TIMELIMIT) 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);
+ ldap_unbind (lh);
+ lh = NULL;
+ return false;
+ }
+ return true;
+}
+
+bool
+cyg_ldap::connect_non_ssl (PCWSTR domain)
+{
+ ULONG ret, timelimit = 3; /* secs */
+
+ if (!(lh = ldap_initW ((PWCHAR) domain, LDAP_PORT)))
+ {
+ debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ());
+ return false;
+ }
+ 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_set_option (lh, LDAP_OPT_TIMELIMIT, &timelimit))
+ != LDAP_SUCCESS)
+ debug_printf ("ldap_set_option(LDAP_OPT_TIMELIMIT) 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);
+ ldap_unbind (lh);
+ lh = NULL;
+ return false;
+ }
+ return true;
+}
+
+bool
+cyg_ldap::open (PCWSTR domain)
+{
+ LARGE_INTEGER start, stop;
+ static LARGE_INTEGER last_rediscover;
+ ULONG ret;
+
+ close ();
+ GetSystemTimeAsFileTime ((LPFILETIME) &start);
+ /* FIXME? connect_ssl can take ages even when failing, so we're trying to
+ do everything the non-SSL (but still encrypted) way. */
+ if (/*!connect_ssl (NULL) && */ !connect_non_ssl (domain))
+ return false;
+ /* For some obscure reason, there's a chance that the ldap_bind_s call takes
+ a long time, if the current primary DC is... well, burping or something.
+ If so, we rediscover in the background which usually switches to the next
+ fastest DC. */
+ GetSystemTimeAsFileTime ((LPFILETIME) &stop);
+ if ((stop.QuadPart - start.QuadPart) >= 3000000LL /* 0.3s */
+ && (stop.QuadPart - last_rediscover.QuadPart) >= 30000000LL) /* 3s */
+ {
+ debug_printf ("ldap_bind_s is laming. Try to rediscover.");
+ HANDLE thr = CreateThread (&sec_none_nih, 4 * PTHREAD_STACK_MIN,
+ rediscover_thread, (LPVOID) domain,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
+ if (!thr)
+ debug_printf ("Couldn't start rediscover thread.");
+ else
+ {
+ last_rediscover = stop;
+ CloseHandle (thr);
+ }
+ }
+
+ if ((ret = ldap_search_stW (lh, NULL, LDAP_SCOPE_BASE,
+ (PWCHAR) L"(objectclass=*)", rootdse_attr,
+ 0, &tv, &msg))
+ != LDAP_SUCCESS)
+ {
+ debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret);
+ goto err;
+ }
+ 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_memfreeW ((PWCHAR) msg);
+ msg = entry = NULL; return true;
+err:
+ close ();
+ return false;
+}
+
+void
+cyg_ldap::close ()
+{
+ if (lh)
+ ldap_unbind (lh);
+ if (msg)
+ ldap_memfreeW ((PWCHAR) msg);
+ if (val)
+ ldap_value_freeW (val);
+ if (rootdse)
+ free (rootdse);
+ lh = NULL;
+ msg = entry = NULL;
+ val = NULL;
+ rootdse = NULL;
+}
+
+bool
+cyg_ldap::fetch_ad_account (PSID sid, bool group)
+{
+ WCHAR filter[512], *f;
+ LONG len = (LONG) RtlLengthSid (sid);
+ PBYTE s = (PBYTE) sid;
+ static WCHAR hex_wchars[] = L"0123456789abcdef";
+ ULONG ret;
+
+ if (msg)
+ {
+ ldap_memfreeW ((PWCHAR) 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")");
+ attr = group ? group_attr : user_attr;
+ if ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter,
+ attr, 0, &tv, &msg)) != LDAP_SUCCESS)
+ {
+ debug_printf ("ldap_search_stW(%W,%W) error 0x%02x",
+ rootdse, filter, ret);
+ return false;
+ }
+ if (!(entry = ldap_first_entry (lh, msg)))
+ {
+ debug_printf ("No entry for %W in rootdse %W", filter, rootdse);
+ return false;
+ }
+ return true;
+}
+
+uint32_t
+cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain)
+{
+ WCHAR filter[512];
+ ULONG ret;
+
+ if (msg)
+ {
+ ldap_memfreeW ((PWCHAR) msg);
+ msg = entry = NULL;
+ }
+ if (val)
+ {
+ ldap_value_freeW (val);
+ val = NULL;
+ }
+ __small_swprintf (filter, L"(&(objectClass=trustedDomain)(name=%W))", domain);
+ if ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter,
+ attr = tdom_attr, 0, &tv, &msg)) != LDAP_SUCCESS)
+ {
+ debug_printf ("ldap_search_stW(%W,%W) error 0x%02x",
+ rootdse, filter, ret);
+ return 0;
+ }
+ if (!(entry = ldap_first_entry (lh, msg)))
+ {
+ debug_printf ("No entry for %W in rootdse %W", filter, rootdse);
+ return 0;
+ }
+ 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[512];
+ ULONG ret;
+ PLDAP_BERVAL *bval;
+
+ if (msg)
+ {
+ ldap_memfreeW ((PWCHAR) 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 ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter,
+ nfs_attr, 0, &tv, &msg)) != LDAP_SUCCESS)
+ {
+ debug_printf ("ldap_search_stW(%W,%W) error 0x%02x",
+ rootdse, filter, ret);
+ return false;
+ }
+ if ((entry = ldap_first_entry (lh, msg))
+ && (bval = ldap_get_values_lenW (lh, entry, nfs_attr[0])))
+ {
+ sid = (PSID) bval[0]->bv_val;
+ ldap_value_free_len (bval);
+ }
+ return true;
+}
+
+PWCHAR
+cyg_ldap::fetch_unix_name_from_rfc2307 (uint32_t id, bool group)
+{
+ WCHAR filter[512];
+ ULONG ret;
+
+ if (msg)
+ {
+ ldap_memfreeW ((PWCHAR) 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 ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter, attr,
+ 0, &tv, &msg)) != LDAP_SUCCESS)
+ {
+ debug_printf ("ldap_search_stW(%W,%W) error 0x%02x",
+ rootdse, filter, ret);
+ 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)))
+ 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)))
+ 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
new file mode 100644
index 000000000..078951768
--- /dev/null
+++ b/winsup/cygwin/ldap.h
@@ -0,0 +1,68 @@
+/* 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 push_macro ("DECLSPEC_IMPORT")
+#undef DECLSPEC_IMPORT
+#define DECLSPEC_IMPORT
+#include <winldap.h>
+#include <ntldap.h>
+#pragma pop_macro ("DECLSPEC_IMPORT")
+
+#define LDAP_USER_NAME_ATTR 0
+#define LDAP_USER_PGRP_ATTR 1
+#define LDAP_USER_GECOS_ATTR 2
+#define LDAP_USER_HOME_ATTR 3
+#define LDAP_USER_SHELL_ATTR 4
+#define LDAP_USER_UID_ATTR 5
+
+#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;
+
+ bool connect_ssl (PCWSTR domain);
+ bool connect_non_ssl (PCWSTR domain);
+ 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)
+ {}
+ ~cyg_ldap () { close (); }
+
+ operator PLDAP () const { return lh; }
+ bool open (PCWSTR in_domain);
+ void close ();
+ bool fetch_ad_account (PSID sid, bool group);
+ uint32_t fetch_posix_offset_for_domain (PCWSTR domain);
+ uid_t remap_uid (uid_t uid);
+ gid_t remap_gid (gid_t gid);
+ PWCHAR get_user_name () { return get_string_attribute (LDAP_USER_NAME_ATTR); }
+ /* 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/passwd.cc b/winsup/cygwin/passwd.cc
index 88690e379..fb51d5aef 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -19,125 +19,158 @@ details. */
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
-#include "pwdgrp.h"
#include "shared_info.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 ()
{
- passwd &res = (*passwd_buf)[curr_lines];
- res.pw_name = next_str (':');
- res.pw_passwd = next_str (':');
- if (!next_num (res.pw_uid))
+ 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))
return false;
- if (!next_num (res.pw_gid))
+ if (!next_num (res.p.pw_gid))
return false;
- res.pw_comment = NULL;
- res.pw_gecos = next_str (':');
- res.pw_dir = next_str (':');
- res.pw_shell = next_str (':');
+ 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);
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::read_passwd ()
+pwdgrp::init_pwd ()
+{
+ pwdgrp_buf_elem_size = sizeof (pg_pwd);
+ parse = &pwdgrp::parse_passwd;
+}
+
+pwdgrp *
+pwdgrp::prep_tls_pwbuf ()
{
- 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))))
+ if (!_my_tls.locals.pwbuf)
{
- 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);
+ _my_tls.locals.pwbuf = ccalloc_abort (HEAP_BUF, 1,
+ sizeof (pwdgrp) + sizeof (pg_pwd));
+ pwdgrp *pw = (pwdgrp *) _my_tls.locals.pwbuf;
+ pw->init_pwd ();
+ pw->pwdgrp_buf = (void *) (pw + 1);
+ pw->max_lines = 1;
}
+ pwdgrp *pw = (pwdgrp *) _my_tls.locals.pwbuf;
+ if (pw->curr_lines)
+ {
+ cfree (pw->passwd ()[0].p.pw_name);
+ pw->curr_lines = 0;
+ }
+ return pw;
}
struct passwd *
-internal_getpwsid (cygpsid &sid)
+pwdgrp::find_user (cygpsid &sid)
+{
+ for (ULONG i = 0; i < curr_lines; i++)
+ if (sid == passwd ()[i].sid)
+ return &passwd ()[i].p;
+ return NULL;
+}
+
+struct passwd *
+pwdgrp::find_user (const char *name)
{
- struct passwd *pw;
- char *ptr1, *ptr2, *endptr;
- char sid_string[128] = {0,','};
+ 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;
+}
- if (sid.string (sid_string + 2))
+struct passwd *
+internal_getpwsid (cygpsid &sid)
+{
+ struct passwd *ret;
+
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_pwd_files ())
{
- 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;
- }
+ cygheap->pg.pwd_cache.file.check_file (false);
+ if ((ret = cygheap->pg.pwd_cache.file.find_user (sid)))
+ return ret;
+ if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (sid)))
+ return ret;
+ }
+ if (cygheap->pg.nss_pwd_db ())
+ {
+ if ((ret = cygheap->pg.pwd_cache.win.find_user (sid)))
+ return ret;
+ return cygheap->pg.pwd_cache.win.add_user_from_windows (sid);
}
return NULL;
}
struct passwd *
-internal_getpwuid (uid_t uid, bool check)
+internal_getpwnam (const char *name)
{
- pr.refresh (check);
+ struct passwd *ret;
- for (int i = 0; i < pr.curr_lines; i++)
- if (uid == passwd_buf[i].pw_uid)
- return passwd_buf + i;
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_pwd_files ())
+ {
+ cygheap->pg.pwd_cache.file.check_file (false);
+ if ((ret = cygheap->pg.pwd_cache.file.find_user (name)))
+ return ret;
+ if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (name)))
+ return ret;
+ }
+ if (cygheap->pg.nss_pwd_db ())
+ {
+ if ((ret = cygheap->pg.pwd_cache.win.find_user (name)))
+ return ret;
+ return cygheap->pg.pwd_cache.win.add_user_from_windows (name);
+ }
return NULL;
}
struct passwd *
-internal_getpwnam (const char *name, bool check)
+internal_getpwuid (uid_t uid)
{
- pr.refresh (check);
+ struct passwd *ret;
- 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;
+ cygheap->pg.nss_init ();
+ if (cygheap->pg.nss_pwd_files ())
+ {
+ cygheap->pg.pwd_cache.file.check_file (false);
+ if ((ret = cygheap->pg.pwd_cache.file.find_user (uid)))
+ return ret;
+ if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (uid)))
+ return ret;
+ }
+ if (cygheap->pg.nss_pwd_db ())
+ {
+ if ((ret = cygheap->pg.pwd_cache.win.find_user (uid)))
+ return ret;
+ return cygheap->pg.pwd_cache.win.add_user_from_windows (uid);
+ }
+ else if (uid == ILLEGAL_UID)
+ return cygheap->pg.pwd_cache.win.add_user_from_windows (uid);
return NULL;
}
-
extern "C" struct passwd *
getpwuid32 (uid_t uid)
{
- struct passwd *temppw = internal_getpwuid (uid, true);
+ struct passwd *temppw = internal_getpwuid (uid);
pthread_testcancel ();
return temppw;
}
@@ -160,7 +193,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, true);
+ struct passwd *temppw = internal_getpwuid (uid);
pthread_testcancel ();
if (!temppw)
return 0;
@@ -198,7 +231,7 @@ 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, true);
+ struct passwd *temppw = internal_getpwnam (name);
pthread_testcancel ();
return temppw;
}
@@ -216,7 +249,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, true);
+ struct passwd *temppw = internal_getpwnam (nam);
pthread_testcancel ();
if (!temppw)
@@ -245,11 +278,19 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
extern "C" struct passwd *
getpwent (void)
{
- 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++;
-
+ pwdgrp &prf = cygheap->pg.pwd_cache.file;
+ if (cygheap->pg.nss_pwd_files ())
+ {
+ cygheap->pg.pwd_cache.file.check_file (false);
+ if (_my_tls.locals.pw_pos < prf.cached_users ())
+ return &prf.passwd ()[_my_tls.locals.pw_pos++].p;
+ }
+ if ((cygheap->pg.nss_pwd_db ()) && cygheap->pg.nss_db_caching ())
+ {
+ pwdgrp &prw = cygheap->pg.pwd_cache.win;
+ if (_my_tls.locals.pw_pos - prf.cached_users () < prw.cached_users ())
+ return &prw.passwd ()[_my_tls.locals.pw_pos++ - prf.cached_users ()].p;
+ }
return NULL;
}
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 1bf47b437..1f4f8286a 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -4612,142 +4612,6 @@ 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 d6c386075..dfd8f0241 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -447,21 +447,4 @@ 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/pinfo.cc b/winsup/cygwin/pinfo.cc
index f56d338c3..b8949bee7 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -41,7 +41,7 @@ pinfo_basic::pinfo_basic ()
GetModuleFileNameW (NULL, progname, sizeof (progname));
/* Default uid/gid are needed very early to initialize shared user info. */
uid = ILLEGAL_UID;
- gid = UNKNOWN_GID;
+ gid = ILLEGAL_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 = UNKNOWN_GID;
+ myself->gid = ILLEGAL_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/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index fe3c3f2a1..a93d2b979 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -1,6 +1,6 @@
/* pwdgrp.h
- Copyright 2001, 2002, 2003 Red Hat inc.
+ Copyright 2001, 2002, 2003, 2014 Red Hat inc.
Stuff common to pwd and grp handling.
@@ -10,42 +10,65 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#pragma once
+
/* These functions are needed to allow searching and walking through
the passwd and group lists */
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 passwd *internal_getpwnam (const char *);
+extern struct passwd *internal_getpwuid (uid_t);
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);
+extern struct group *internal_getgrgid (gid_t);
+extern struct group *internal_getgrnam (const char *);
int internal_getgroups (int, gid_t *, cygpsid * = NULL);
#include "sync.h"
-#include "cygtls.h"
+
+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;
+};
+
+struct pg_grp
+{
+ struct group g;
+ cygsid sid;
+};
+
class pwdgrp
{
unsigned pwdgrp_buf_elem_size;
- union
- {
- passwd **passwd_buf;
- group **group_buf;
- void **pwdgrp_buf;
- };
- void (pwdgrp::*read) ();
+ void *pwdgrp_buf;
bool (pwdgrp::*parse) ();
- int etc_ix;
- UNICODE_STRING upath;
- PWCHAR path;
- char *buf, *lptr;
- int max_lines;
- bool initialized;
+ UNICODE_STRING path;
+ OBJECT_ATTRIBUTES attr;
+ LARGE_INTEGER last_modified;
+ char *lptr;
+ ULONG curr_lines;
+ ULONG max_lines;
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);
@@ -64,21 +87,96 @@ class pwdgrp
i = (int) x;
return res;
}
+ void *add_account_post_fetch (char *line);
+ 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, bool group);
+ void *add_account_from_windows (const char *name, bool group);
+ void *add_account_from_windows (uint32_t id, bool group);
+ 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, bool group);
+ pwdgrp *prep_tls_pwbuf ();
+ pwdgrp *prep_tls_grbuf ();
public:
- int curr_lines;
+ ULONG cached_users () const { return curr_lines; }
+ ULONG cached_groups () const { return curr_lines; }
+ bool check_file (bool group);
- 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 ();
- }
+ void init_pwd ();
+ pg_pwd *passwd () const { return (pg_pwd *) pwdgrp_buf; };
+ inline 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)
+ { return (struct passwd *) add_account_from_windows (sid, false); }
+ struct passwd *add_user_from_windows (const char *name)
+ { return (struct passwd *) add_account_from_windows (name, false); }
+ struct passwd *add_user_from_windows (uint32_t id)
+ { return (struct passwd *) add_account_from_windows (id, false); }
+ struct passwd *find_user (cygpsid &sid);
+ struct passwd *find_user (const char *name);
+ struct passwd *find_user (uid_t uid);
+
+ void init_grp ();
+ pg_grp *group () const { return (pg_grp *) pwdgrp_buf; };
+ 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)
+ { return (struct group *) add_account_from_windows (sid, true); }
+ struct group *add_group_from_windows (const char *name)
+ { return (struct group *) add_account_from_windows (name, true); }
+ struct group *add_group_from_windows (uint32_t id)
+ { return (struct group *) add_account_from_windows (id, true); }
+ struct group *find_group (cygpsid &sid);
+ struct group *find_group (const char *name);
+ struct group *find_group (gid_t gid);
+};
+
+class ugid_cache_t
+{
+ struct idmap {
+ uint32_t nfs_id;
+ uint32_t cyg_id;
+ };
+ class idmaps {
+ uint32_t _cnt;
+ uint32_t _max;
+ idmap *_map;
+ public:
+ idmaps () : _cnt (0), _max (0), _map (NULL) {}
+ 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 *) realloc (_map, (_max += 10) * sizeof (*_map));
+ _map[_cnt].nfs_id = nfs_id;
+ _map[_cnt].cyg_id = cyg_id;
+ ++_cnt;
+ }
+ };
+ idmaps uids;
+ idmaps gids;
- pwdgrp (passwd *&pbuf);
- pwdgrp (group *&gbuf);
+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); }
};
+extern ugid_cache_t ugid_cache;
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 2f7ac278d..099df061c 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 Red Hat, Inc.
+ 2011, 2012, 2014 Red Hat, Inc.
Written by Corinna Vinschen <corinna@vinschen.de>
@@ -22,7 +22,6 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
-#include "pwdgrp.h"
#include "tls_pbuf.h"
static int
diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc
index dfec53ca9..04dc6ca9f 100644
--- a/winsup/cygwin/sec_auth.cc
+++ b/winsup/cygwin/sec_auth.cc
@@ -14,7 +14,6 @@ details. */
#include <wchar.h>
#include <wininet.h>
#include <ntsecapi.h>
-#include <dsgetdc.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
@@ -25,7 +24,6 @@ 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>
@@ -220,28 +218,25 @@ lsa_close_policy (HANDLE lsa)
}
bool
-get_logon_server (PWCHAR domain, WCHAR *server, bool rediscovery)
+get_logon_server (PWCHAR domain, WCHAR *server, ULONG flags)
{
DWORD ret;
PDOMAIN_CONTROLLER_INFOW pci;
- DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
/* Empty domain is interpreted as local system */
- if ((GetComputerNameW (server + 2, &size)) &&
- (!wcscasecmp (domain, server + 2) || !domain[0]))
+ if (!domain[0] || !wcscasecmp (domain, cygheap->dom.account_flat_name ()))
{
- server[0] = server[1] = L'\\';
+ wcpcpy (wcpcpy (server, L"\\\\"), cygheap->dom.account_flat_name ());
return true;
}
/* Try to get any available domain controller for this domain */
- ret = DsGetDcNameW (NULL, domain, NULL, NULL,
- rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
+ ret = DsGetDcNameW (NULL, domain, NULL, NULL, flags, &pci);
if (ret == ERROR_SUCCESS)
{
wcscpy (server, pci->DomainControllerName);
NetApiBufferFree (pci);
- debug_printf ("DC: rediscovery: %d, server: %W", rediscovery, server);
+ debug_printf ("DC: server: %W", server);
return true;
}
__seterrno_from_win_error (ret);
@@ -397,28 +392,6 @@ 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)
{
@@ -479,7 +452,6 @@ 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;
}
@@ -491,12 +463,9 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
__seterrno ();
return false;
}
- if (get_logon_server (domain, server, false)
- && !get_user_groups (server, grp_list, user, domain)
- && get_logon_server (domain, server, true))
+ if (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);
- get_unix_group_sidlist (pw, grp_list);
return true;
}
@@ -757,35 +726,26 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
if (groups.issetgroups ()) /* setgroups was called */
{
- cygsid gsid;
- struct group *gr;
+ cygpsid gsid;
bool saw[groups.sgsids.count ()];
- memset (saw, 0, sizeof(saw));
- /* token groups found in /etc/group match the user.gsids ? */
- for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
- if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
- {
- int pos = groups.sgsids.position (gsid);
- if (pos >= 0)
- saw[pos] = true;
- else if (groups.pgsid == gsid)
- sawpg = true;
-#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
- }
+ /* 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;
+ }
+ }
/* 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 2d81cbd38..8aeac2e5b 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 Red Hat, Inc.
+ 2011, 2012, 2013, 2014 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 =
@@ -126,7 +126,7 @@ cygpsid::get_id (BOOL search_grp, int *type)
}
PWCHAR
-cygpsid::string (PWCHAR nsidstr) const
+cygpsid::pstring (PWCHAR nsidstr) const
{
UNICODE_STRING sid;
@@ -134,11 +134,19 @@ cygpsid::string (PWCHAR nsidstr) const
return NULL;
RtlInitEmptyUnicodeString (&sid, nsidstr, 256);
RtlConvertSidToUnicodeString (&sid, psid, FALSE);
- return nsidstr;
+ return nsidstr + sid.Length / sizeof (WCHAR);
+}
+
+PWCHAR
+cygpsid::string (PWCHAR nsidstr) const
+{
+ if (pstring (nsidstr))
+ return nsidstr;
+ return NULL;
}
char *
-cygpsid::string (char *nsidstr) const
+cygpsid::pstring (char *nsidstr) const
{
char *t;
DWORD i;
@@ -147,10 +155,18 @@ cygpsid::string (char *nsidstr) const
return NULL;
strcpy (nsidstr, "S-1-");
t = nsidstr + sizeof ("S-1-") - 1;
- t += __small_sprintf (t, "%u", RtlIdentifierAuthoritySid (psid)->Value[5]);
+ t += __small_sprintf (t, "%u", sid_id_auth (psid));
for (i = 0; i < *RtlSubAuthorityCountSid (psid); ++i)
- t += __small_sprintf (t, "-%lu", *RtlSubAuthoritySid (psid, i));
- return nsidstr;
+ 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;
}
PSID
@@ -185,6 +201,24 @@ 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[8];
+
+ if (nsidstr && !wcsncmp (nsidstr, L"S-1-", 4))
+ {
+ s = wcstoul (nsidstr + 4, &lasts, 10);
+ while (cnt < 8 && *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;
@@ -264,12 +298,34 @@ get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gid
struct passwd *pw;
struct group *gr = NULL;
bool ret = false;
+ PWCHAR domain;
+ cyg_ldap cldap;
+ bool ldap_open = false;
owner_sid.debug_print ("get_sids_info: owner SID =");
group_sid.debug_print ("get_sids_info: group SID =");
if (group_sid == cygheap->user.groups.pgsid)
*gidret = myself->gid;
+ else if (sid_id_auth (group_sid) == 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 (group_sid);
+ gid_t map_gid = ugid_cache.get_gid (gid);
+ if (map_gid == ILLEGAL_GID)
+ {
+ domain = cygheap->dom.get_rfc2307_domain ();
+ if ((ldap_open = cldap.open (domain)))
+ map_gid = cldap.remap_gid (gid);
+ if (map_gid == ILLEGAL_GID)
+ map_gid = MAP_UNIX_TO_CYGWIN_ID (gid);
+ ugid_cache.add_gid (gid, map_gid);
+ }
+ *gidret = map_gid;
+ }
else if ((gr = internal_getgrsid (group_sid)))
*gidret = gr->gr_gid;
else
@@ -283,6 +339,22 @@ get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gid
else
ret = (internal_getgroups (0, NULL, &group_sid) > 0);
}
+ else if (sid_id_auth (owner_sid) == 22)
+ {
+ /* Samba UNIX user. See comment above. */
+ uid_t uid = sid_sub_auth_rid (owner_sid);
+ uid_t map_uid = ugid_cache.get_uid (uid);
+ if (map_uid == ILLEGAL_UID)
+ {
+ domain = cygheap->dom.get_rfc2307_domain ();
+ if ((ldap_open || cldap.open (domain)))
+ map_uid = cldap.remap_uid (uid);
+ if (map_uid == ILLEGAL_UID)
+ map_uid = MAP_UNIX_TO_CYGWIN_ID (uid);
+ ugid_cache.add_uid (uid, map_uid);
+ }
+ *uidret = map_uid;
+ }
else if ((pw = internal_getpwsid (owner_sid)))
{
*uidret = pw->pw_uid;
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 251e9609e..200bfb782 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 Red Hat, Inc.
+ 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
@@ -23,7 +23,6 @@ details. */
#include "pinfo.h"
#include "cygheap.h"
#include "ntdll.h"
-#include "pwdgrp.h"
#include "tls_pbuf.h"
#include <aclapi.h>
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index 940afc5d7..8edd76833 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -12,14 +12,38 @@ 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
-#define DEFAULT_UID DOMAIN_USER_RID_ADMIN
-#define UNKNOWN_UID 400 /* Non conflicting number */
-#define UNKNOWN_GID 401
+/* UID/GID */
+void uinfo_init ();
+
+#define ILLEGAL_UID ((uid_t)-1)
+#define ILLEGAL_GID ((gid_t)-1)
+
+/* 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 MAX_SID_LEN 40
#define MAX_DACL_LEN(n) (sizeof (ACL) \
@@ -92,6 +116,16 @@ 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"
{
@@ -116,7 +150,9 @@ public:
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
@@ -142,6 +178,7 @@ class cygsid : public cygpsid {
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);
@@ -169,12 +206,16 @@ 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); }
@@ -414,7 +455,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, bool rediscovery);
+bool get_logon_server (PWCHAR domain, PWCHAR wserver, ULONG flags);
HANDLE lsa_open_policy (PWCHAR server, ACCESS_MASK access);
void lsa_close_policy (HANDLE lsa);
diff --git a/winsup/cygwin/setlsapwd.cc b/winsup/cygwin/setlsapwd.cc
index e86696b80..811084832 100644
--- a/winsup/cygwin/setlsapwd.cc
+++ b/winsup/cygwin/setlsapwd.cc
@@ -17,7 +17,6 @@ details. */
#include "cygheap.h"
#include "security.h"
#include "cygserver_setpwd.h"
-#include "pwdgrp.h"
#include "ntdll.h"
#include <ntsecapi.h>
#include <stdlib.h>
@@ -51,7 +50,7 @@ setlsapwd (const char *passwd, const char *username)
if (username)
{
cygsid psid;
- struct passwd *pw = internal_getpwnam (username, false);
+ struct passwd *pw = internal_getpwnam (username);
if (!pw || !psid.getfrompw (pw))
{
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 2f5a45376..9f1f27cd9 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -22,7 +22,6 @@ 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>
@@ -352,6 +351,7 @@ memory_init (bool init_cygheap)
cygheap_init ();
cygheap->user.init ();
cygheap->init_installation_root (); /* Requires user.init! */
+ cygheap->pg.init ();
}
shared_info::create (); /* Initialize global shared memory */
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index a5a18a469..9d7212def 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -58,7 +58,6 @@ details. */
#include "pinfo.h"
#include "shared_info.h"
#include "cygheap.h"
-#include "pwdgrp.h"
#include "cpuid.h"
#include "registry.h"
#include "environ.h"
diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h
index 37f30c070..df8ccfa11 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 = -11260;
-//; $tls::plocal_clib = 1440;
-//; $tls::__dontuse = -11260;
-//; $tls::p__dontuse = 1440;
-//; $tls::func = -10172;
-//; $tls::pfunc = 2528;
-//; $tls::saved_errno = -10168;
-//; $tls::psaved_errno = 2532;
-//; $tls::sa_flags = -10164;
-//; $tls::psa_flags = 2536;
-//; $tls::oldmask = -10160;
-//; $tls::poldmask = 2540;
-//; $tls::deltamask = -10156;
-//; $tls::pdeltamask = 2544;
-//; $tls::errno_addr = -10152;
-//; $tls::perrno_addr = 2548;
-//; $tls::sigmask = -10148;
-//; $tls::psigmask = 2552;
-//; $tls::sigwait_mask = -10144;
-//; $tls::psigwait_mask = 2556;
-//; $tls::sigwait_info = -10140;
-//; $tls::psigwait_info = 2560;
-//; $tls::signal_arrived = -10136;
-//; $tls::psignal_arrived = 2564;
-//; $tls::will_wait_for_signal = -10132;
-//; $tls::pwill_wait_for_signal = 2568;
-//; $tls::thread_context = -10128;
-//; $tls::pthread_context = 2572;
-//; $tls::thread_id = -9916;
-//; $tls::pthread_id = 2784;
-//; $tls::infodata = -9912;
-//; $tls::pinfodata = 2788;
-//; $tls::tid = -9764;
-//; $tls::ptid = 2936;
-//; $tls::_ctinfo = -9760;
-//; $tls::p_ctinfo = 2940;
-//; $tls::andreas = -9756;
-//; $tls::pandreas = 2944;
-//; $tls::wq = -9752;
-//; $tls::pwq = 2948;
-//; $tls::sig = -9724;
-//; $tls::psig = 2976;
-//; $tls::incyg = -9720;
-//; $tls::pincyg = 2980;
-//; $tls::spinning = -9716;
-//; $tls::pspinning = 2984;
-//; $tls::stacklock = -9712;
-//; $tls::pstacklock = 2988;
-//; $tls::stackptr = -9708;
-//; $tls::pstackptr = 2992;
-//; $tls::stack = -9704;
-//; $tls::pstack = 2996;
-//; $tls::initialized = -8680;
-//; $tls::pinitialized = 4020;
+//; $tls::local_clib = -11284;
+//; $tls::plocal_clib = 1416;
+//; $tls::__dontuse = -11284;
+//; $tls::p__dontuse = 1416;
+//; $tls::func = -10196;
+//; $tls::pfunc = 2504;
+//; $tls::saved_errno = -10192;
+//; $tls::psaved_errno = 2508;
+//; $tls::sa_flags = -10188;
+//; $tls::psa_flags = 2512;
+//; $tls::oldmask = -10184;
+//; $tls::poldmask = 2516;
+//; $tls::deltamask = -10180;
+//; $tls::pdeltamask = 2520;
+//; $tls::errno_addr = -10176;
+//; $tls::perrno_addr = 2524;
+//; $tls::sigmask = -10172;
+//; $tls::psigmask = 2528;
+//; $tls::sigwait_mask = -10168;
+//; $tls::psigwait_mask = 2532;
+//; $tls::sigwait_info = -10164;
+//; $tls::psigwait_info = 2536;
+//; $tls::signal_arrived = -10160;
+//; $tls::psignal_arrived = 2540;
+//; $tls::will_wait_for_signal = -10156;
+//; $tls::pwill_wait_for_signal = 2544;
+//; $tls::thread_context = -10152;
+//; $tls::pthread_context = 2548;
+//; $tls::thread_id = -9940;
+//; $tls::pthread_id = 2760;
+//; $tls::infodata = -9936;
+//; $tls::pinfodata = 2764;
+//; $tls::tid = -9788;
+//; $tls::ptid = 2912;
+//; $tls::_ctinfo = -9784;
+//; $tls::p_ctinfo = 2916;
+//; $tls::andreas = -9780;
+//; $tls::pandreas = 2920;
+//; $tls::wq = -9776;
+//; $tls::pwq = 2924;
+//; $tls::sig = -9748;
+//; $tls::psig = 2952;
+//; $tls::incyg = -9744;
+//; $tls::pincyg = 2956;
+//; $tls::spinning = -9740;
+//; $tls::pspinning = 2960;
+//; $tls::stacklock = -9736;
+//; $tls::pstacklock = 2964;
+//; $tls::stackptr = -9732;
+//; $tls::pstackptr = 2968;
+//; $tls::stack = -9728;
+//; $tls::pstack = 2972;
+//; $tls::initialized = -8704;
+//; $tls::pinitialized = 3996;
//; __DATA__
#define tls_locals (-12700)
#define tls_plocals (0)
-#define tls_local_clib (-11260)
-#define tls_plocal_clib (1440)
-#define tls___dontuse (-11260)
-#define tls_p__dontuse (1440)
-#define tls_func (-10172)
-#define tls_pfunc (2528)
-#define tls_saved_errno (-10168)
-#define tls_psaved_errno (2532)
-#define tls_sa_flags (-10164)
-#define tls_psa_flags (2536)
-#define tls_oldmask (-10160)
-#define tls_poldmask (2540)
-#define tls_deltamask (-10156)
-#define tls_pdeltamask (2544)
-#define tls_errno_addr (-10152)
-#define tls_perrno_addr (2548)
-#define tls_sigmask (-10148)
-#define tls_psigmask (2552)
-#define tls_sigwait_mask (-10144)
-#define tls_psigwait_mask (2556)
-#define tls_sigwait_info (-10140)
-#define tls_psigwait_info (2560)
-#define tls_signal_arrived (-10136)
-#define tls_psignal_arrived (2564)
-#define tls_will_wait_for_signal (-10132)
-#define tls_pwill_wait_for_signal (2568)
-#define tls_thread_context (-10128)
-#define tls_pthread_context (2572)
-#define tls_thread_id (-9916)
-#define tls_pthread_id (2784)
-#define tls_infodata (-9912)
-#define tls_pinfodata (2788)
-#define tls_tid (-9764)
-#define tls_ptid (2936)
-#define tls__ctinfo (-9760)
-#define tls_p_ctinfo (2940)
-#define tls_andreas (-9756)
-#define tls_pandreas (2944)
-#define tls_wq (-9752)
-#define tls_pwq (2948)
-#define tls_sig (-9724)
-#define tls_psig (2976)
-#define tls_incyg (-9720)
-#define tls_pincyg (2980)
-#define tls_spinning (-9716)
-#define tls_pspinning (2984)
-#define tls_stacklock (-9712)
-#define tls_pstacklock (2988)
-#define tls_stackptr (-9708)
-#define tls_pstackptr (2992)
-#define tls_stack (-9704)
-#define tls_pstack (2996)
-#define tls_initialized (-8680)
-#define tls_pinitialized (4020)
+#define tls_local_clib (-11284)
+#define tls_plocal_clib (1416)
+#define tls___dontuse (-11284)
+#define tls_p__dontuse (1416)
+#define tls_func (-10196)
+#define tls_pfunc (2504)
+#define tls_saved_errno (-10192)
+#define tls_psaved_errno (2508)
+#define tls_sa_flags (-10188)
+#define tls_psa_flags (2512)
+#define tls_oldmask (-10184)
+#define tls_poldmask (2516)
+#define tls_deltamask (-10180)
+#define tls_pdeltamask (2520)
+#define tls_errno_addr (-10176)
+#define tls_perrno_addr (2524)
+#define tls_sigmask (-10172)
+#define tls_psigmask (2528)
+#define tls_sigwait_mask (-10168)
+#define tls_psigwait_mask (2532)
+#define tls_sigwait_info (-10164)
+#define tls_psigwait_info (2536)
+#define tls_signal_arrived (-10160)
+#define tls_psignal_arrived (2540)
+#define tls_will_wait_for_signal (-10156)
+#define tls_pwill_wait_for_signal (2544)
+#define tls_thread_context (-10152)
+#define tls_pthread_context (2548)
+#define tls_thread_id (-9940)
+#define tls_pthread_id (2760)
+#define tls_infodata (-9936)
+#define tls_pinfodata (2764)
+#define tls_tid (-9788)
+#define tls_ptid (2912)
+#define tls__ctinfo (-9784)
+#define tls_p_ctinfo (2916)
+#define tls_andreas (-9780)
+#define tls_pandreas (2920)
+#define tls_wq (-9776)
+#define tls_pwq (2924)
+#define tls_sig (-9748)
+#define tls_psig (2952)
+#define tls_incyg (-9744)
+#define tls_pincyg (2956)
+#define tls_spinning (-9740)
+#define tls_pspinning (2960)
+#define tls_stacklock (-9736)
+#define tls_pstacklock (2964)
+#define tls_stackptr (-9732)
+#define tls_pstackptr (2968)
+#define tls_stack (-9728)
+#define tls_pstack (2972)
+#define tls_initialized (-8704)
+#define tls_pinitialized (3996)
diff --git a/winsup/cygwin/tlsoffsets64.h b/winsup/cygwin/tlsoffsets64.h
index f85dae242..e966d4567 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 = -11200;
-//; $tls::plocal_clib = 1600;
-//; $tls::__dontuse = -11200;
-//; $tls::p__dontuse = 1600;
-//; $tls::func = -9312;
-//; $tls::pfunc = 3488;
-//; $tls::saved_errno = -9304;
-//; $tls::psaved_errno = 3496;
-//; $tls::sa_flags = -9300;
-//; $tls::psa_flags = 3500;
-//; $tls::oldmask = -9296;
-//; $tls::poldmask = 3504;
-//; $tls::deltamask = -9288;
-//; $tls::pdeltamask = 3512;
-//; $tls::errno_addr = -9280;
-//; $tls::perrno_addr = 3520;
-//; $tls::sigmask = -9272;
-//; $tls::psigmask = 3528;
-//; $tls::sigwait_mask = -9264;
-//; $tls::psigwait_mask = 3536;
-//; $tls::sigwait_info = -9256;
-//; $tls::psigwait_info = 3544;
-//; $tls::signal_arrived = -9248;
-//; $tls::psignal_arrived = 3552;
-//; $tls::will_wait_for_signal = -9240;
-//; $tls::pwill_wait_for_signal = 3560;
-//; $tls::thread_context = -9232;
-//; $tls::pthread_context = 3568;
-//; $tls::thread_id = -8400;
-//; $tls::pthread_id = 4400;
-//; $tls::infodata = -8396;
-//; $tls::pinfodata = 4404;
-//; $tls::tid = -8248;
-//; $tls::ptid = 4552;
-//; $tls::_ctinfo = -8240;
-//; $tls::p_ctinfo = 4560;
-//; $tls::andreas = -8232;
-//; $tls::pandreas = 4568;
-//; $tls::wq = -8224;
-//; $tls::pwq = 4576;
-//; $tls::sig = -8176;
-//; $tls::psig = 4624;
-//; $tls::incyg = -8172;
-//; $tls::pincyg = 4628;
-//; $tls::spinning = -8168;
-//; $tls::pspinning = 4632;
-//; $tls::stacklock = -8164;
-//; $tls::pstacklock = 4636;
-//; $tls::stackptr = -8160;
-//; $tls::pstackptr = 4640;
-//; $tls::stack = -8152;
-//; $tls::pstack = 4648;
-//; $tls::initialized = -6104;
-//; $tls::pinitialized = 6696;
+//; $tls::local_clib = -11240;
+//; $tls::plocal_clib = 1560;
+//; $tls::__dontuse = -11240;
+//; $tls::p__dontuse = 1560;
+//; $tls::func = -9352;
+//; $tls::pfunc = 3448;
+//; $tls::saved_errno = -9344;
+//; $tls::psaved_errno = 3456;
+//; $tls::sa_flags = -9340;
+//; $tls::psa_flags = 3460;
+//; $tls::oldmask = -9336;
+//; $tls::poldmask = 3464;
+//; $tls::deltamask = -9328;
+//; $tls::pdeltamask = 3472;
+//; $tls::errno_addr = -9320;
+//; $tls::perrno_addr = 3480;
+//; $tls::sigmask = -9312;
+//; $tls::psigmask = 3488;
+//; $tls::sigwait_mask = -9304;
+//; $tls::psigwait_mask = 3496;
+//; $tls::sigwait_info = -9296;
+//; $tls::psigwait_info = 3504;
+//; $tls::signal_arrived = -9288;
+//; $tls::psignal_arrived = 3512;
+//; $tls::will_wait_for_signal = -9280;
+//; $tls::pwill_wait_for_signal = 3520;
+//; $tls::thread_context = -9272;
+//; $tls::pthread_context = 3528;
+//; $tls::thread_id = -8440;
+//; $tls::pthread_id = 4360;
+//; $tls::infodata = -8436;
+//; $tls::pinfodata = 4364;
+//; $tls::tid = -8288;
+//; $tls::ptid = 4512;
+//; $tls::_ctinfo = -8280;
+//; $tls::p_ctinfo = 4520;
+//; $tls::andreas = -8272;
+//; $tls::pandreas = 4528;
+//; $tls::wq = -8264;
+//; $tls::pwq = 4536;
+//; $tls::sig = -8216;
+//; $tls::psig = 4584;
+//; $tls::incyg = -8212;
+//; $tls::pincyg = 4588;
+//; $tls::spinning = -8208;
+//; $tls::pspinning = 4592;
+//; $tls::stacklock = -8204;
+//; $tls::pstacklock = 4596;
+//; $tls::stackptr = -8200;
+//; $tls::pstackptr = 4600;
+//; $tls::stack = -8192;
+//; $tls::pstack = 4608;
+//; $tls::initialized = -6144;
+//; $tls::pinitialized = 6656;
//; __DATA__
#define tls_locals (-12800)
#define tls_plocals (0)
-#define tls_local_clib (-11200)
-#define tls_plocal_clib (1600)
-#define tls___dontuse (-11200)
-#define tls_p__dontuse (1600)
-#define tls_func (-9312)
-#define tls_pfunc (3488)
-#define tls_saved_errno (-9304)
-#define tls_psaved_errno (3496)
-#define tls_sa_flags (-9300)
-#define tls_psa_flags (3500)
-#define tls_oldmask (-9296)
-#define tls_poldmask (3504)
-#define tls_deltamask (-9288)
-#define tls_pdeltamask (3512)
-#define tls_errno_addr (-9280)
-#define tls_perrno_addr (3520)
-#define tls_sigmask (-9272)
-#define tls_psigmask (3528)
-#define tls_sigwait_mask (-9264)
-#define tls_psigwait_mask (3536)
-#define tls_sigwait_info (-9256)
-#define tls_psigwait_info (3544)
-#define tls_signal_arrived (-9248)
-#define tls_psignal_arrived (3552)
-#define tls_will_wait_for_signal (-9240)
-#define tls_pwill_wait_for_signal (3560)
-#define tls_thread_context (-9232)
-#define tls_pthread_context (3568)
-#define tls_thread_id (-8400)
-#define tls_pthread_id (4400)
-#define tls_infodata (-8396)
-#define tls_pinfodata (4404)
-#define tls_tid (-8248)
-#define tls_ptid (4552)
-#define tls__ctinfo (-8240)
-#define tls_p_ctinfo (4560)
-#define tls_andreas (-8232)
-#define tls_pandreas (4568)
-#define tls_wq (-8224)
-#define tls_pwq (4576)
-#define tls_sig (-8176)
-#define tls_psig (4624)
-#define tls_incyg (-8172)
-#define tls_pincyg (4628)
-#define tls_spinning (-8168)
-#define tls_pspinning (4632)
-#define tls_stacklock (-8164)
-#define tls_pstacklock (4636)
-#define tls_stackptr (-8160)
-#define tls_pstackptr (4640)
-#define tls_stack (-8152)
-#define tls_pstack (4648)
-#define tls_initialized (-6104)
-#define tls_pinitialized (6696)
+#define tls_local_clib (-11240)
+#define tls_plocal_clib (1560)
+#define tls___dontuse (-11240)
+#define tls_p__dontuse (1560)
+#define tls_func (-9352)
+#define tls_pfunc (3448)
+#define tls_saved_errno (-9344)
+#define tls_psaved_errno (3456)
+#define tls_sa_flags (-9340)
+#define tls_psa_flags (3460)
+#define tls_oldmask (-9336)
+#define tls_poldmask (3464)
+#define tls_deltamask (-9328)
+#define tls_pdeltamask (3472)
+#define tls_errno_addr (-9320)
+#define tls_perrno_addr (3480)
+#define tls_sigmask (-9312)
+#define tls_psigmask (3488)
+#define tls_sigwait_mask (-9304)
+#define tls_psigwait_mask (3496)
+#define tls_sigwait_info (-9296)
+#define tls_psigwait_info (3504)
+#define tls_signal_arrived (-9288)
+#define tls_psignal_arrived (3512)
+#define tls_will_wait_for_signal (-9280)
+#define tls_pwill_wait_for_signal (3520)
+#define tls_thread_context (-9272)
+#define tls_pthread_context (3528)
+#define tls_thread_id (-8440)
+#define tls_pthread_id (4360)
+#define tls_infodata (-8436)
+#define tls_pinfodata (4364)
+#define tls_tid (-8288)
+#define tls_ptid (4512)
+#define tls__ctinfo (-8280)
+#define tls_p_ctinfo (4520)
+#define tls_andreas (-8272)
+#define tls_pandreas (4528)
+#define tls_wq (-8264)
+#define tls_pwq (4536)
+#define tls_sig (-8216)
+#define tls_psig (4584)
+#define tls_incyg (-8212)
+#define tls_pincyg (4588)
+#define tls_spinning (-8208)
+#define tls_pspinning (4592)
+#define tls_stacklock (-8204)
+#define tls_pstacklock (4596)
+#define tls_stackptr (-8200)
+#define tls_pstackptr (4600)
+#define tls_stack (-8192)
+#define tls_pstack (4608)
+#define tls_initialized (-6144)
+#define tls_pinitialized (6656)
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index 4ca901f35..6ef2719e0 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 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -10,12 +10,14 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <unistd.h>
+#include <iptypes.h>
+#include <lm.h>
+#include <ntsecapi.h>
#include <wininet.h>
+#include <unistd.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"
@@ -27,10 +29,12 @@ 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"
+
/* Initialize the part of cygheap_user that does not depend on files.
The information is used in shared.cc for the user shared.
Final initialization occurs in uinfo_init */
@@ -113,13 +117,13 @@ void
internal_getlogin (cygheap_user &user)
{
struct passwd *pw = NULL;
+ struct group *gr, *gr2;
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");
+ if (!pw && !(pw = internal_getpwnam (user.name ())))
+ debug_printf ("user not found in /etc/passwd");
else
{
cygsid gsid;
@@ -127,11 +131,17 @@ internal_getlogin (cygheap_user &user)
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 (gr = internal_getgrgid (pw->pw_gid)))
{
+ /* 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 the
+ gr_gid from the group file. Overwrite it brutally. */
+ if ((gr2 = internal_getgrsid (gsid)) && gr2 != gr)
+ myself->gid = pw->pw_gid = gr2->gr_gid;
+ /* Set primary group to the group in /etc/passwd. */
if (gsid != user.groups.pgsid)
{
- /* Set primary group to the group in /etc/passwd. */
NTSTATUS status = NtSetInformationToken (hProcToken,
TokenPrimaryGroup,
&gsid, sizeof gsid);
@@ -415,7 +425,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, false))
+ if (get_logon_server (wdomain, wlogsrv, DS_IS_FLAT_NAME))
sys_wcstombs_alloc (&plogsrv, HEAP_STR, wlogsrv);
return plogsrv;
}
@@ -525,104 +535,1126 @@ pwdgrp::add_line (char *eptr)
{
if (eptr)
{
- lptr = eptr;
- eptr = strchr (lptr, '\n');
- if (eptr)
- {
- if (eptr > lptr && eptr[-1] == '\r')
- eptr[-1] = '\0';
- else
- *eptr = '\0';
- eptr++;
- }
if (curr_lines >= max_lines)
{
max_lines += 10;
- *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
+ pwdgrp_buf = crealloc_abort (pwdgrp_buf,
+ max_lines * pwdgrp_buf_elem_size);
}
+ lptr = eptr;
if ((this->*parse) ())
curr_lines++;
}
return eptr;
}
+ugid_cache_t ugid_cache;
+
void
-pwdgrp::load (const wchar_t *rel_path)
+cygheap_pwdgrp::init ()
{
- static const char failed[] = "failed";
- static const char succeeded[] = "succeeded";
- const char *res = failed;
- HANDLE fh = NULL;
+ pwd_cache.file.init_pwd ();
+ pwd_cache.win.init_pwd ();
+ grp_cache.file.init_grp ();
+ grp_cache.win.init_grp ();
+ /* Default settings:
+
+ passwd: files db
+ group: files db
+ db_prefix: auto
+ db_cache: yes
+ db_separator: +
+ */
+ pwd_src = (NSS_FILES | NSS_DB);
+ grp_src = (NSS_FILES | NSS_DB);
+ prefix = NSS_AUTO;
+ separator[0] = L'+';
+ caching = true;
+}
- NTSTATUS status;
+/* The /etc/nssswitch.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 (!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 && strchr (" \t", c[1]))
+ separator[0] = (unsigned char) *c;
+ else
+ debug_printf ("Invalid nsswitch.conf content: %s", line);
+ }
+ else if (!strncmp (c, "cache:", 6))
+ {
+ c += 6;
+ c += strspn (c, " \t");
+ if (!strncmp (c, "yes", 3) && strchr (" \t", c[3]))
+ caching = true;
+ else if (!strncmp (c, "no", 2) && strchr (" \t", c[2]))
+ caching = false;
+ else
+ debug_printf ("Invalid nsswitch.conf content: %s", line);
+ }
+ break;
+ case '\0':
+ case '#':
+ break;
+ default:
+ debug_printf ("Invalid nsswitch.conf content: %s", line);
+ break;
+ }
+}
+
+void
+cygheap_pwdgrp::_nss_init ()
+{
+ UNICODE_STRING path;
OBJECT_ATTRIBUTES attr;
- IO_STATUS_BLOCK io;
- FILE_STANDARD_INFORMATION fsi;
+ NT_readline rl;
+ tmp_pathbuf tp;
+ char *buf = tp.c_get ();
+
+ PCWSTR rel_path = L"\\etc\\nsswitch.conf";
+ path.Buffer = (PWCHAR) alloca ((wcslen (cygheap->installation_root)
+ + wcslen (rel_path) + 1) * sizeof (WCHAR));
+ wcpcpy (wcpcpy (path.Buffer, cygheap->installation_root), rel_path);
+ RtlInitUnicodeString (&path, path.Buffer);
+ 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;
+}
- if (buf)
- free (buf);
- buf = NULL;
- curr_lines = 0;
+/* Override the ParentIndex value of the PDS_DOMAIN_TRUSTSW entry with the
+ PosixOffset. */
+#define PosixOffset ParentIndex
- if (!path &&
- !(path = (PWCHAR) malloc ((wcslen (cygheap->installation_root)
- + wcslen (rel_path) + 1) * sizeof (WCHAR))))
+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)
{
- paranoid_printf ("malloc (%W) failed", rel_path);
- goto out;
+ system_printf ("LsaQueryInformationPolicy(Primary) %u", status);
+ return false;
}
- wcpcpy (wcpcpy (path, cygheap->installation_root), rel_path);
- RtlInitUnicodeString (&upath, path);
+ /* 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) %u", status);
+ return false;
+ }
+ /* Copy account domain info to cygheap. */
+ adom_name = cwcsdup (adom->DomainName.Buffer);
+ adom_sid = adom->DomainSid;
+ LsaFreeMemory (adom);
+ lsa_close_policy (lsa);
+ if (cygheap->dom.member_machine ())
+ {
+ /* For a domain member machine fetch all trusted domain info. */
+ lowest_tdo_posix_offset = UNIX_POSIX_OFFSET - 1;
+ 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);
+ tdom[idx].DnsDomainName = cwcsdup (td[idx].DnsDomainName);
+ 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 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;
+}
- InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
- etc_ix = etc::init (etc_ix, &attr);
+/* Per session, so it changes potentially when switching the user context. */
+static cygsid logon_sid ("");
- paranoid_printf ("%S", &upath);
+static void
+get_logon_sid ()
+{
+ if (PSID (logon_sid) == NO_SID)
+ {
+ NTSTATUS status;
+ ULONG size;
+ tmp_pathbuf tp;
+ PTOKEN_GROUPS groups = (PTOKEN_GROUPS) tp.c_get ();
- 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))
+ 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;
+ }
+ }
+ }
+}
+
+void *
+pwdgrp::add_account_post_fetch (char *line)
+{
+ if (line)
+ {
+ void *ret;
+ pglock.init ("pglock")->acquire ();
+ add_line (line);
+ ret = ((char *) pwdgrp_buf) + (curr_lines - 1) * pwdgrp_buf_elem_size;
+ 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);
+}
+
+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);
+}
+
+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);
+}
+
+void *
+pwdgrp::add_account_from_windows (cygpsid &sid, bool group)
+{
+ fetch_user_arg_t arg;
+ arg.type = SID_arg;
+ arg.sid = &sid;
+ char *line = fetch_account_from_windows (arg, group);
+ if (!line)
+ return NULL;
+ if (cygheap->pg.nss_db_caching ())
+ return add_account_post_fetch (line);
+ return (prep_tls_pwbuf ())->add_account_post_fetch (line);
+}
+
+void *
+pwdgrp::add_account_from_windows (const char *name, bool group)
+{
+ fetch_user_arg_t arg;
+ arg.type = NAME_arg;
+ arg.name = name;
+ char *line = fetch_account_from_windows (arg, group);
+ if (!line)
+ return NULL;
+ if (cygheap->pg.nss_db_caching ())
+ return add_account_post_fetch (line);
+ return (prep_tls_pwbuf ())->add_account_post_fetch (line);
+}
+
+void *
+pwdgrp::add_account_from_windows (uint32_t id, bool group)
+{
+ fetch_user_arg_t arg;
+ arg.type = ID_arg;
+ arg.id = id;
+ char *line = fetch_account_from_windows (arg, group);
+ if (!line)
+ return NULL;
+ if (cygheap->pg.nss_db_caching ())
+ return add_account_post_fetch (line);
+ return (prep_tls_pwbuf ())->add_account_post_fetch (line);
+}
+
+/* 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 (bool group)
+{
+ FILE_BASIC_INFORMATION fbi;
+ NTSTATUS status;
+
+ if (!path.Buffer)
{
- paranoid_printf ("NtOpenFile(%S) failed, status %y", &upath, status);
- goto out;
+ PCWSTR rel_path = group ? L"\\etc\\group" : L"\\etc\\passwd";
+ path.Buffer = (PWCHAR) cmalloc_abort (HEAP_BUF,
+ (wcslen (cygheap->installation_root)
+ + wcslen (rel_path) + 1)
+ * sizeof (WCHAR));
+ wcpcpy (wcpcpy (path.Buffer, cygheap->installation_root), rel_path);
+ RtlInitUnicodeString (&path, path.Buffer);
+ InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE,
+ NULL, NULL);
}
- status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi,
- FileStandardInformation);
+ else if (path.MaximumLength == 0) /* Indicates that the file doesn't exist. */
+ return false;
+ status = NtQueryAttributesFile (&attr, &fbi);
if (!NT_SUCCESS (status))
{
- paranoid_printf ("NtQueryInformationFile(%S) failed, status %y",
- &upath, status);
- goto out;
+ if (last_modified.QuadPart)
+ last_modified.QuadPart = 0LL;
+ else
+ path.MaximumLength = 0;
+ return false;
}
- /* 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 (fbi.LastWriteTime.QuadPart > last_modified.QuadPart)
{
- paranoid_printf ("malloc (%u) failed", fsi.EndOfFile.LowPart);
- goto out;
+ 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 (group ? this->group ()[i].g.gr_name
+ : this->passwd ()[i].p.pw_name);
+ pglock.release ();
+ }
}
- status = NtReadFile (fh, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
- NULL, NULL);
- if (!NT_SUCCESS (status))
+ 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 = tp.c_get ();
+ 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;
+}
+
+char *
+pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group)
+{
+ /* 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 = MAX_SID_LEN;
+ cygpsid sid = NO_SID;
+ SID_NAME_USE acc_type;
+ BOOL ret = false;
+ /* Cygwin user name style. */
+ enum {
+ name_only,
+ plus_prepended,
+ fully_qualified
+ } name_style = name_only;
+ /* Computed stuff. */
+ uid_t uid = ILLEGAL_UID;
+ gid_t gid = ILLEGAL_GID;
+ bool is_domain_account = true;
+ PCWSTR domain = NULL;
+ PWCHAR shell = NULL;
+ PWCHAR user = NULL;
+ PWCHAR home = NULL;
+ PWCHAR gecos = NULL;
+ PWCHAR p;
+ WCHAR sidstr[128];
+ /* Temporary stuff. */
+ ULONG posix_offset = 0;
+ cyg_ldap cldap;
+ bool ldap_open = false;
+
+ /* Initialize */
+ if (!cygheap->dom.init ())
+ return NULL;
+
+ switch (arg.type)
{
- paranoid_printf ("NtReadFile(%S) failed, status %y", &upath, status);
- free (buf);
- goto out;
+ case SID_arg:
+ sid = *arg.sid;
+ ret = LookupAccountSidW (NULL, sid, name, &nlen, dom, &dlen, &acc_type);
+ break;
+ case NAME_arg:
+ /* Skip leading domain separator. This denotes an alias or well-known
+ group, which will be found first by LookupAccountNameW anyway.
+ Otherwise, if the name has no leading domain name, it's either a
+ standalone machine, or the username must be from the primary domain.
+ In the latter case, prepend the primary domain name so as not to
+ collide with an account from the account domain with the same name. */
+ p = name;
+ if (*arg.name == cygheap->pg.nss_separator ()[0])
+ ++arg.name;
+ else if (!strchr (arg.name, cygheap->pg.nss_separator ()[0])
+ && cygheap->dom.member_machine ())
+ p = wcpcpy (wcpcpy (p, cygheap->dom.primary_flat_name ()),
+ cygheap->pg.nss_separator ());
+ /* Now fill up with name to search. */
+ sys_mbstowcs (p, UNLEN + 1, arg.name);
+ /* Replace domain separator char with backslash and make sure p is NULL
+ or points to the backslash, so... */
+ if ((p = wcschr (name, cygheap->pg.nss_separator ()[0])))
+ *p = L'\\';
+ 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;
+ 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 <= 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;
+ __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 < 0x100000)
+ {
+ /* 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",
+ group ? 2 : 1, arg.id & UNIX_POSIX_MASK);
+ /* LookupAccountSidW will fail. */
+ sid = csid = sidstr;
+ break;
+ }
+ else
+ {
+ /* Some trusted domain? */
+ PDS_DOMAIN_TRUSTSW td = NULL;
+
+ for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)
+ {
+ /* If we don't have the PosixOffset of the domain, fetch it.
+ Skip primary domain. */
+ if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY))
+ {
+ uint32_t id_val;
+
+ if (!ldap_open && !(ldap_open = cldap.open (NULL)))
+ id_val = cygheap->dom.lowest_tdo_posix_offset
+ - 0x01000000;
+ else
+ id_val =
+ cldap.fetch_posix_offset_for_domain (td->DnsDomainName);
+ if (id_val)
+ {
+ td->PosixOffset = id_val;
+ if (id_val < cygheap->dom.lowest_tdo_posix_offset)
+ cygheap->dom.lowest_tdo_posix_offset = id_val;
+ }
+ }
+ if (td->PosixOffset > posix_offset && td->PosixOffset <= arg.id)
+ posix_offset = td->PosixOffset;
+ }
+ if (posix_offset)
+ {
+ cygpsid tsid (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 - 0x100000);
+ }
+ 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;
}
- 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;
+ if (ret)
+ {
+ /* Builtin account? SYSTEM, for instance, is returned as SidTypeUser,
+ if a process is running as LocalSystem service. */
+ if (acc_type == SidTypeUser && sid_sub_auth_count (sid) <= 3)
+ acc_type = SidTypeWellKnownGroup;
+ /* Alias? There are two types, the builtin aliases like "Administrators"
+ and the local groups in SAM. Handle local groups as groups. */
+ else if (acc_type == SidTypeAlias
+ && sid_sub_auth (sid, 0) == SECURITY_NT_NON_UNIQUE)
+ acc_type = SidTypeGroup;
+
+ switch (acc_type)
+ {
+ case SidTypeUser:
+ case SidTypeGroup:
+ /* Account domain account? */
+ if (!wcscmp (dom, cygheap->dom.account_flat_name ()))
+ {
+ posix_offset = 0x30000;
+ if (cygheap->dom.member_machine ()
+ || !cygheap->pg.nss_prefix_auto ())
+ name_style = fully_qualified;
+ domain = cygheap->dom.account_flat_name ();
+ is_domain_account = false;
+ }
+ /* Domain member machine? */
+ else if (cygheap->dom.member_machine ())
+ {
+ /* Primary domain account? */
+ if (!wcscmp (dom, cygheap->dom.primary_flat_name ()))
+ {
+ posix_offset = 0x100000;
+ /* 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 domain
+ control 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. */
+ domain = NULL;
+ if (!cygheap->pg.nss_prefix_auto ())
+ name_style = fully_qualified;
+ }
+ else
+ {
+ /* No, fetch POSIX offset. */
+ PDS_DOMAIN_TRUSTSW td = NULL;
+
+ name_style = fully_qualified;
+ for (ULONG idx = 0;
+ (td = cygheap->dom.trusted_domain (idx));
+ ++idx)
+ {
+ if (wcscmp (dom, td->NetbiosDomainName))
+ continue;
+ domain = td->DnsDomainName;
+ posix_offset = td->PosixOffset;
+ /* If we don't have the PosixOffset of the domain,
+ fetch it. */
+ if (!posix_offset)
+ {
+ uint32_t id_val;
+
+ if (!ldap_open && !(ldap_open = cldap.open (NULL)))
+ {
+ /* We're probably running under a local account,
+ so we're not allowed to fetch any information
+ from AD beyond the most obvious. Never mind,
+ just fake a reasonable posix offset. */
+ id_val = cygheap->dom.lowest_tdo_posix_offset
+ - 0x01000000;
+ }
+ else
+ id_val =
+ cldap.fetch_posix_offset_for_domain (domain);
+ if (id_val)
+ {
+ td->PosixOffset = posix_offset = id_val;
+ if (id_val < cygheap->dom.lowest_tdo_posix_offset)
+ cygheap->dom.lowest_tdo_posix_offset = id_val;
+ }
+ }
+ 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. */
+ uid = posix_offset + sid_sub_auth_rid (sid);
+ gid = posix_offset + DOMAIN_GROUP_RID_USERS; /* Default. */
+
+ if (is_domain_account)
+ {
+ /* Use LDAP to fetch domain account infos. */
+ if (!ldap_open && !cldap.open (NULL))
+ break;
+ if (cldap.fetch_ad_account (sid, group))
+ {
+ PWCHAR val;
+ uint32_t id_val;
+
+ if (!group)
+ {
+ if ((id_val = cldap.get_primary_gid ()) != ILLEGAL_GID)
+ gid = posix_offset + id_val;
+ if ((val = cldap.get_user_name ())
+ && wcscmp (name, val))
+ user = wcscpy ((PWCHAR) alloca ((wcslen (val) + 1)
+ * sizeof (WCHAR)), val);
+ if ((val = cldap.get_gecos ()))
+ gecos = 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. */
+ id_val = cldap.get_unix_uid ();
+ if (id_val != ILLEGAL_UID
+ && ugid_cache.get_uid (id_val) == ILLEGAL_UID)
+ ugid_cache.add_uid (id_val, uid);
+ }
+ else
+ {
+ if ((val = cldap.get_group_name ())
+ && wcscmp (name, val))
+ user = wcscpy ((PWCHAR) alloca ((wcslen (val) + 1)
+ * sizeof (WCHAR)), val);
+ id_val = cldap.get_unix_gid ();
+ if (id_val != ILLEGAL_GID
+ && ugid_cache.get_gid (id_val) == ILLEGAL_GID)
+ ugid_cache.add_gid (id_val, uid);
+ }
+ }
+ }
+ /* Otherwise check account domain (local SAM).*/
+ else if (acc_type == SidTypeUser)
+ {
+ NET_API_STATUS nas;
+ PUSER_INFO_4 ui;
+
+ nas = NetUserGetInfo (domain, name, 4, (PBYTE *) &ui);
+ if (nas != NERR_Success)
+ debug_printf ("NetUserGetInfo(%W,%W) %u", domain, name, nas);
+ else
+ {
+ struct {
+ PCWSTR str;
+ size_t len;
+ PWCHAR *tgt;
+ } search[] = {
+ { L"name=\"", 6, &user },
+ { L"home=\"", 6, &home },
+ { L"shell=\"", 7, &shell }
+ };
+ PWCHAR s, e;
+
+ /* Fetch primary group. */
+ gid = posix_offset + ui->usri4_primary_group_id;
+ /* Local SAM accounts have only a handful attributes
+ available to home users. Therefore, fetch different
+ Cygwin user name, Cygwin home dir, and Cygwin login
+ shell from the "Description" field in XML short
+ style. */
+ if ((s = wcsstr (ui->usri4_comment, L"<cygwin "))
+ && (e = wcsstr (s + 8, L"/>")))
+ {
+ s += 8;
+ *e = L'\0';
+ while (*s)
+ {
+ while (*s == L' ')
+ ++s;
+ for (size_t i = 0;
+ i < sizeof search / sizeof search[0];
+ ++i)
+ if (!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;
+ }
+ else
+ {
+ *s = L'\0';
+ break;
+ }
+ }
+ }
+ }
+ NetApiBufferFree (ui);
+ }
+ }
+ else /* SidTypeGroup */
+ {
+ NET_API_STATUS nas;
+ PGROUP_INFO_3 gi;
+
+ nas = NetGroupGetInfo (domain, name, 3, (PBYTE *) &gi);
+ if (nas != NERR_Success)
+ debug_printf ("NetGroupGetInfo(%W,%W) %u", domain, name, nas);
+ else
+ {
+ PWCHAR s, e;
+
+ /* Fetch different Cygwin group name from description. */
+ if ((s = wcsstr (gi->grpi3_comment, L"<cygwin "))
+ && (e = wcsstr (s + 8, L"/>")))
+ {
+ s += 8;
+ *e = L'\0';
+ while (*s)
+ {
+ while (*s == L' ')
+ ++s;
+ if (!wcsncmp (s, L"name=\"", 6))
+ {
+ s += 6;
+ if ((e = wcschr (s, L'"')))
+ {
+ *wcpncpy (name = namebuf, s, e - s) = L'\0';
+ s = e + 1;
+ }
+ else
+ break;
+ }
+ }
+ }
+ NetApiBufferFree (gi);
+ }
+ }
+ break;
+ case SidTypeAlias:
+ case SidTypeWellKnownGroup:
+ name_style = (cygheap->pg.nss_prefix_always ()) ? fully_qualified
+ : plus_prepended;
+#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);
+ if (sid_sub_auth (sid, 0) > SECURITY_BUILTIN_DOMAIN_RID)
+ name_style = fully_qualified;
+ }
+ else
+ uid = 0x10000 + 0x100 * sid_id_auth (sid)
+ + (sid_sub_auth_rid (sid) & 0xff);
+#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)
+ uid = sid_sub_auth_rid (sid) & 0x7ff;
+ else
+ {
+ uid = 0x1000 * sid_sub_auth (sid, 0)
+ + (sid_sub_auth_rid (sid) & 0xffff);
+ //name_style = fully_qualified;
+ }
+#endif
+ /* Special case for "Everyone". We don't want to return Everyone
+ as user or group. Ever. */
+ if (uid == 0x10100) /* Computed from S-1-1-0. */
+ return NULL;
+ break;
+ case SidTypeLabel:
+ uid = 0x60000 + sid_sub_auth_rid (sid);
+ name_style = (cygheap->pg.nss_prefix_always ()) ? fully_qualified
+ : plus_prepended;
+ 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");
+ }
+ }
+ 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");
+ name_style = plus_prepended;
+ }
+ else if (sid_id_auth (sid) == 22)
+ {
+ /* Samba UNIX Users/Groups
+
+ This *might* colide 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);
+ name_style = fully_qualified;
+ }
+ else
+ {
+ wcpcpy (dom, L"Unknown");
+ wcpcpy (name = namebuf, group ? L"Group" : L"User");
+ name_style = fully_qualified;
+ }
+
+ 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 (name_style >= fully_qualified)
+ p = wcpcpy (p, user ? group ? L"Posix_Group" : L"Posix_User" : dom);
+ if (name_style >= plus_prepended)
+ p = wcpcpy (p, cygheap->pg.nss_separator ());
+ wcpcpy (p, user ?: name);
+
+ if (group)
+ __small_swprintf (linebuf, L"%W:%W:%u:",
+ posix_name, sid.string (sidstr), uid);
+ 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 ?: user ?: name,
+ shell ?: L"/bin/sh");
+ sys_wcstombs_alloc (&line, HEAP_BUF, linebuf);
+ debug_printf ("line: <%s>", line);
+ return line;
}
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index eb7a423dd..0bfd22de4 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -1,7 +1,7 @@
/* winsup.h: main Cygwin header file.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -172,20 +172,8 @@ 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)