summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog25
-rw-r--r--winsup/cygwin/cygheap.h29
-rw-r--r--winsup/cygwin/grp.cc17
-rw-r--r--winsup/cygwin/pwdgrp.h2
-rw-r--r--winsup/cygwin/uinfo.cc124
5 files changed, 138 insertions, 59 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 5ba1e3e9d..70547fcc2 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,28 @@
+2014-02-28 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygheap.h (cygheap_user::sid): Return reference to cygpsid rather
+ than PSID.
+ (cygheap_user::saved_sid): Ditto.
+ (cygheap_pwdgrp::cache_t): New type.
+ (cygheap_pwdgrp::caching): Convert to cache_t.
+ (cygheap_pwdgrp::nss_db_caching): Change accordingly.
+ (cygheap_pwdgrp::nss_db_full_caching): New inline method.
+ * grp.cc (internal_getgroups): Reinvent. Take cyg_ldap pointer as
+ third parameter and use throughout.
+ (getgroups32): Call internal_getgroups.
+ * pwdgrp.h (internal_getgroups): Declare.
+ * uinfo.cc (internal_getlogin): Partial rewrite to accommodate having
+ no connection to the DC. Give primary group from user token more
+ weight. Generate group entries for all groups in the user token if
+ caching is set to NSS_FULL_CACHING.
+ (cygheap_pwdgrp::init): Initialize caching to NSS_FULL_CACHING.
+ (cygheap_pwdgrp::nss_init_line): Handle "db_cache: full".
+ (pwdgrp::add_account_from_windows): Fix group handling in non-caching
+ mode.
+ (pwdgrp::fetch_account_from_windows): Default primary group for the
+ current user to primary group from user token. Check for primary
+ domain first after LookupAccountSid failed.
+
2014-02-27 Corinna Vinschen <corinna@vinschen.de>
* autoload.cc (CheckTokenMembership): Import.
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 7d4198a49..66603c0c7 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -156,8 +156,8 @@ public:
}
void set_sid (PSID new_sid) { effec_cygsid = new_sid;}
void set_saved_sid () { saved_cygsid = effec_cygsid; }
- PSID sid () { return effec_cygsid; }
- PSID saved_sid () { return saved_cygsid; }
+ cygpsid &sid () { return effec_cygsid; }
+ cygpsid &saved_sid () { return saved_cygsid; }
const char *ontherange (homebodies what, struct passwd * = NULL);
#define NO_IMPERSONATION NULL
bool issetuid () const { return curr_imp_token != NO_IMPERSONATION; }
@@ -400,14 +400,19 @@ class cygheap_pwdgrp
NSS_PRIMARY,
NSS_ALWAYS
};
- bool nss_inited;
- int pwd_src;
- int grp_src;
- pfx_t prefix;
- WCHAR separator[2];
- bool caching;
- int enums;
- PWCHAR enum_tdoms;
+ enum cache_t {
+ NSS_NO_CACHING = 0,
+ NSS_CACHING,
+ NSS_FULL_CACHING
+ };
+ bool nss_inited;
+ int pwd_src;
+ int grp_src;
+ pfx_t prefix;
+ WCHAR separator[2];
+ cache_t caching;
+ int enums;
+ PWCHAR enum_tdoms;
void nss_init_line (const char *line);
void _nss_init ();
@@ -433,7 +438,9 @@ public:
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; }
+ inline bool nss_db_caching () const { return caching != NSS_NO_CACHING; }
+ inline bool nss_db_full_caching () const
+ { return caching == NSS_FULL_CACHING; }
inline int nss_db_enums () const { return enums; }
inline PCWSTR nss_db_enum_tdoms () const { return enum_tdoms; }
};
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index 31bfeda2b..cd4afd4a1 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -459,21 +459,20 @@ endgrent_filtered (void *gr)
((gr_ent *) gr)->endgrent ();
}
-extern "C" int
-getgroups32 (int gidsetsize, gid_t *grouplist)
+int
+internal_getgroups (int gidsetsize, gid_t *grouplist, cyg_ldap *pldap)
{
NTSTATUS status;
HANDLE tok;
ULONG size;
int cnt = 0;
struct group *grp;
- cyg_ldap cldap;
if (cygheap->user.groups.issetgroups ())
{
for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
if ((grp = internal_getgrsid (cygheap->user.groups.sgsids.sids[pg],
- &cldap)))
+ pldap)))
{
if (cnt < gidsetsize)
grouplist[cnt] = grp->gr_gid;
@@ -500,7 +499,7 @@ getgroups32 (int gidsetsize, gid_t *grouplist)
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
{
cygpsid sid = groups->Groups[pg].Sid;
- if ((grp = internal_getgrsid (sid, &cldap)))
+ if ((grp = internal_getgrsid (sid, pldap)))
{
if ((groups->Groups[pg].Attributes
& (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED))
@@ -525,6 +524,14 @@ error:
return -1;
}
+extern "C" int
+getgroups32 (int gidsetsize, gid_t *grouplist)
+{
+ cyg_ldap cldap;
+
+ return internal_getgroups (gidsetsize, grouplist, &cldap);
+}
+
#ifdef __x86_64__
EXPORT_ALIAS (getgroups32, getgroups)
#else
diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index 5a8267cea..41098de6e 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -27,6 +27,8 @@ extern struct group *internal_getgrsid_from_db (cygpsid &sid);
extern struct group *internal_getgrgid (gid_t, cyg_ldap * = NULL);
extern struct group *internal_getgrnam (const char *, cyg_ldap * = NULL);
+extern int internal_getgroups (int, gid_t *, cyg_ldap *);
+
/* These functions are called from mkpasswd/mkgroup via cygwin_internal. */
void *setpwent_filtered (int enums, PCWSTR enum_tdoms);
void *getpwent_filtered (void *gr);
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index e39e08601..dc22082c1 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -116,48 +116,63 @@ cygheap_user::init ()
void
internal_getlogin (cygheap_user &user)
{
- struct passwd *pw = NULL;
- struct group *gr, *gr2;
+ struct passwd *pwd;
+ struct group *pgrp, *grp, *grp2;
cyg_ldap cldap;
- cygpsid psid = user.sid ();
- pw = internal_getpwsid (psid, &cldap);
-
- if (!pw && !(pw = internal_getpwnam (user.name (), &cldap)))
- debug_printf ("user not found in /etc/passwd");
+ /* Fetch (and potentially generate) passwd and group entries for the user
+ and the primary group in the token. */
+ pwd = internal_getpwsid (user.sid (), &cldap);
+ pgrp = internal_getgrsid (user.groups.pgsid, &cldap);
+ if (cygheap->pg.nss_db_full_caching ())
+ internal_getgroups (0, NULL, &cldap);
+ if (!pwd)
+ debug_printf ("user not found in passwd DB");
else
{
cygsid gsid;
- myself->uid = pw->pw_uid;
- myself->gid = pw->pw_gid;
- user.set_name (pw->pw_name);
- if (gsid.getfromgr (gr = internal_getgrgid (pw->pw_gid, &cldap)))
+ user.set_name (pwd->pw_name);
+ myself->uid = pwd->pw_uid;
+ myself->gid = pwd->pw_gid;
+ /* Is the primary group in the passwd DB is different from the primary
+ group in the user token, we have to find the SID of that group and
+ try to override the token primary group. */
+ if (!pgrp || myself->gid != pgrp->gr_gid)
{
- /* 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, &cldap)) && gr2 != gr)
- myself->gid = pw->pw_gid = gr2->gr_gid;
- /* Set primary group to the group in /etc/passwd. */
- if (gsid != user.groups.pgsid)
+ if (gsid.getfromgr (grp = internal_getgrgid (pwd->pw_gid, &cldap)))
{
- NTSTATUS status = NtSetInformationToken (hProcToken,
- TokenPrimaryGroup,
- &gsid, sizeof gsid);
- if (!NT_SUCCESS (status))
- debug_printf ("NtSetInformationToken (TokenPrimaryGroup), %y",
- status);
- else
- user.groups.pgsid = gsid;
- clear_procimptoken ();
+ /* We might have a group file with a group entry for the current
+ user's primary group, but the current user has no entry in
+ passwd. If so, pw_gid is taken from windows and might
+ disagree with gr_gid from the group file. Overwrite it. */
+ if ((grp2 = internal_getgrsid (gsid, &cldap)) && grp2 != grp)
+ myself->gid = pwd->pw_gid = grp2->gr_gid;
+ /* Set primary group to the group in /etc/passwd. */
+ if (gsid != user.groups.pgsid)
+ {
+ NTSTATUS status = NtSetInformationToken (hProcToken,
+ TokenPrimaryGroup,
+ &gsid, sizeof gsid);
+ if (!NT_SUCCESS (status))
+ {
+ debug_printf ("NtSetInformationToken (TokenPrimaryGroup),"
+ " %y", status);
+ /* Revert the primary group setting and override the
+ setting in the passwd entry. */
+ if (pgrp)
+ myself->gid = pwd->pw_gid = pgrp->gr_gid;
+ }
+ else
+ user.groups.pgsid = gsid;
+ clear_procimptoken ();
+ }
}
+ else
+ debug_printf ("group not found in group DB");
}
- else
- debug_printf ("gsid not found in augmented /etc/group");
}
- cygheap->user.ontherange (CH_HOME, pw);
+ cygheap->user.ontherange (CH_HOME, pwd);
}
void
@@ -569,7 +584,7 @@ cygheap_pwdgrp::init ()
grp_src = (NSS_FILES | NSS_DB);
prefix = NSS_AUTO;
separator[0] = L'+';
- caching = true;
+ caching = NSS_FULL_CACHING;
enums = (ENUM_CACHE | ENUM_BUILTIN);
enum_tdoms = NULL;
}
@@ -659,10 +674,12 @@ cygheap_pwdgrp::nss_init_line (const char *line)
{
c += 6;
c += strspn (c, " \t");
- if (!strncmp (c, "yes", 3) && strchr (" \t", c[3]))
- caching = true;
+ if (!strncmp (c, "full", 3) && strchr (" \t", c[3]))
+ caching = NSS_FULL_CACHING;
+ else if (!strncmp (c, "yes", 3) && strchr (" \t", c[3]))
+ caching = NSS_CACHING;
else if (!strncmp (c, "no", 2) && strchr (" \t", c[2]))
- caching = false;
+ caching = NSS_NO_CACHING;
else
debug_printf ("Invalid nsswitch.conf content: %s", line);
}
@@ -986,6 +1003,8 @@ pwdgrp::add_account_from_windows (cygpsid &sid, bool group, cyg_ldap *pldap)
return NULL;
if (cygheap->pg.nss_db_caching ())
return add_account_post_fetch (line, true);
+ if (group)
+ return (prep_tls_grbuf ())->add_account_post_fetch (line, false);
return (prep_tls_pwbuf ())->add_account_post_fetch (line, false);
}
@@ -1000,6 +1019,8 @@ pwdgrp::add_account_from_windows (const char *name, bool group, cyg_ldap *pldap)
return NULL;
if (cygheap->pg.nss_db_caching ())
return add_account_post_fetch (line, true);
+ if (group)
+ return (prep_tls_grbuf ())->add_account_post_fetch (line, false);
return (prep_tls_pwbuf ())->add_account_post_fetch (line, false);
}
@@ -1014,6 +1035,8 @@ pwdgrp::add_account_from_windows (uint32_t id, bool group, cyg_ldap *pldap)
return NULL;
if (cygheap->pg.nss_db_caching ())
return add_account_post_fetch (line, true);
+ if (group)
+ return (prep_tls_grbuf ())->add_account_post_fetch (line, false);
return (prep_tls_pwbuf ())->add_account_post_fetch (line, false);
}
@@ -1481,7 +1504,16 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group,
if (acc_type != SidTypeUser)
break;
- gid = posix_offset + DOMAIN_GROUP_RID_USERS; /* Default. */
+ /* Default primary group. If the sid is the current user, fetch
+ the default group from the current user token, otherwise make
+ the educated guess that the user is in group "Domain Users"
+ or "None". */
+ if (sid == cygheap->user.sid ())
+ gid = posix_offset
+ + sid_sub_auth_rid (cygheap->user.groups.pgsid);
+ else
+ gid = posix_offset + DOMAIN_GROUP_RID_USERS;
+
/* Use LDAP to fetch domain account infos. */
if (!cldap->open (NULL))
break;
@@ -1724,13 +1756,19 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group,
PDS_DOMAIN_TRUSTSW td = NULL;
sid_sub_auth_count (sid) = sid_sub_auth_count (sid) - 1;
- for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)
- if (td->DomainSid && RtlEqualSid (sid, td->DomainSid))
- {
- domain = td->NetbiosDomainName;
- posix_offset = fetch_posix_offset (td, cldap);
- break;
- }
+ if (RtlEqualSid (sid, cygheap->dom.primary_sid ()))
+ {
+ domain = cygheap->dom.primary_flat_name ();
+ posix_offset = 0x100000;
+ }
+ else
+ for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)
+ if (td->DomainSid && RtlEqualSid (sid, td->DomainSid))
+ {
+ domain = td->NetbiosDomainName;
+ posix_offset = fetch_posix_offset (td, cldap);
+ break;
+ }
}
if (domain)
{