summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/grp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/grp.cc')
-rw-r--r--winsup/cygwin/grp.cc294
1 files changed, 159 insertions, 135 deletions
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 ();