diff options
Diffstat (limited to 'winsup/cygwin/grp.cc')
-rw-r--r-- | winsup/cygwin/grp.cc | 294 |
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 (); |