mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-28 10:00:23 +08:00
1ca20a1cd2
/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.
587 lines
14 KiB
C++
587 lines
14 KiB
C++
/* grp.cc
|
|
|
|
Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
|
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
|
|
|
|
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 <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "cygerrno.h"
|
|
#include "pinfo.h"
|
|
#include "path.h"
|
|
#include "fhandler.h"
|
|
#include "dtable.h"
|
|
#include "cygheap.h"
|
|
#include "ntdll.h"
|
|
|
|
static char * NO_COPY_RO null_ptr;
|
|
|
|
bool
|
|
pwdgrp::parse_group ()
|
|
{
|
|
pg_grp &grp = group ()[curr_lines];
|
|
grp.g.gr_name = next_str (':');
|
|
if (!*grp.g.gr_name)
|
|
return false;
|
|
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.g.gr_mem = &null_ptr;
|
|
if (n)
|
|
{
|
|
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.g.gr_mem = namearray;
|
|
}
|
|
}
|
|
grp.sid.getfromgr (&grp.g);
|
|
return true;
|
|
}
|
|
|
|
muto NO_COPY pwdgrp::pglock;
|
|
|
|
void
|
|
pwdgrp::init_grp ()
|
|
{
|
|
pwdgrp_buf_elem_size = sizeof (pg_grp);
|
|
parse = &pwdgrp::parse_group;
|
|
}
|
|
|
|
pwdgrp *
|
|
pwdgrp::prep_tls_grbuf ()
|
|
{
|
|
if (!_my_tls.locals.grbuf)
|
|
{
|
|
_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;
|
|
}
|
|
pwdgrp *gr = (pwdgrp *) _my_tls.locals.grbuf;
|
|
if (gr->curr_lines)
|
|
{
|
|
cfree (gr->group ()[0].g.gr_name);
|
|
gr->curr_lines = 0;
|
|
}
|
|
return gr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
struct group *
|
|
pwdgrp::find_group (const char *name)
|
|
{
|
|
for (ULONG i = 0; i < curr_lines; i++)
|
|
if (strcasematch (group ()[i].g.gr_name, name))
|
|
return &group ()[i].g;
|
|
return NULL;
|
|
}
|
|
|
|
struct group *
|
|
pwdgrp::find_group (gid_t gid)
|
|
{
|
|
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)
|
|
{
|
|
struct group *ret;
|
|
|
|
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_getgrnam (const char *name)
|
|
{
|
|
struct group *ret;
|
|
|
|
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_getgrgid (gid_t gid)
|
|
{
|
|
struct group *ret;
|
|
|
|
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;
|
|
}
|
|
|
|
#ifndef __x86_64__
|
|
static struct __group16 *
|
|
grp32togrp16 (struct __group16 *gp16, struct group *gp32)
|
|
{
|
|
if (!gp16 || !gp32)
|
|
return NULL;
|
|
|
|
/* Copying the pointers is actually unnecessary. Just having the correct
|
|
return type is important. */
|
|
gp16->gr_name = gp32->gr_name;
|
|
gp16->gr_passwd = gp32->gr_passwd;
|
|
gp16->gr_gid = (__gid16_t) gp32->gr_gid; /* Not loss-free */
|
|
gp16->gr_mem = gp32->gr_mem;
|
|
|
|
return gp16;
|
|
}
|
|
#endif
|
|
|
|
extern "C" int
|
|
getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t bufsize,
|
|
struct group **result)
|
|
{
|
|
*result = NULL;
|
|
|
|
if (!grp || !buffer)
|
|
return ERANGE;
|
|
|
|
struct group *tempgr = internal_getgrgid (gid);
|
|
pthread_testcancel ();
|
|
if (!tempgr)
|
|
return 0;
|
|
|
|
/* check needed buffer size. */
|
|
int i;
|
|
size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
|
|
+ 2 + sizeof (char *);
|
|
for (i = 0; tempgr->gr_mem[i]; ++i)
|
|
needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *);
|
|
if (needsize > bufsize)
|
|
return ERANGE;
|
|
|
|
/* make a copy of tempgr */
|
|
*result = grp;
|
|
grp->gr_gid = tempgr->gr_gid;
|
|
buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
|
|
buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
|
|
grp->gr_mem = (char **) (buffer + 1);
|
|
buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *);
|
|
for (i = 0; tempgr->gr_mem[i]; ++i)
|
|
buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1;
|
|
grp->gr_mem[i] = NULL;
|
|
return 0;
|
|
}
|
|
|
|
extern "C" struct group *
|
|
getgrgid32 (gid_t gid)
|
|
{
|
|
return internal_getgrgid (gid);
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (getgrgid32, getgrgid)
|
|
#else
|
|
extern "C" struct __group16 *
|
|
getgrgid (__gid16_t gid)
|
|
{
|
|
static struct __group16 g16; /* FIXME: thread-safe? */
|
|
|
|
return grp32togrp16 (&g16, getgrgid32 (gid16togid32 (gid)));
|
|
}
|
|
#endif
|
|
|
|
extern "C" int
|
|
getgrnam_r (const char *nam, struct group *grp, char *buffer,
|
|
size_t bufsize, struct group **result)
|
|
{
|
|
*result = NULL;
|
|
|
|
if (!grp || !buffer)
|
|
return ERANGE;
|
|
|
|
struct group *tempgr = internal_getgrnam (nam);
|
|
pthread_testcancel ();
|
|
if (!tempgr)
|
|
return 0;
|
|
|
|
/* check needed buffer size. */
|
|
int i;
|
|
size_t needsize = strlen (tempgr->gr_name) + strlen (tempgr->gr_passwd)
|
|
+ 2 + sizeof (char *);
|
|
for (i = 0; tempgr->gr_mem[i]; ++i)
|
|
needsize += strlen (tempgr->gr_mem[i]) + 1 + sizeof (char *);
|
|
if (needsize > bufsize)
|
|
return ERANGE;
|
|
|
|
/* make a copy of tempgr */
|
|
*result = grp;
|
|
grp->gr_gid = tempgr->gr_gid;
|
|
buffer = stpcpy (grp->gr_name = buffer, tempgr->gr_name);
|
|
buffer = stpcpy (grp->gr_passwd = buffer + 1, tempgr->gr_passwd);
|
|
grp->gr_mem = (char **) (buffer + 1);
|
|
buffer = (char *) grp->gr_mem + (i + 1) * sizeof (char *);
|
|
for (i = 0; tempgr->gr_mem[i]; ++i)
|
|
buffer = stpcpy (grp->gr_mem[i] = buffer, tempgr->gr_mem[i]) + 1;
|
|
grp->gr_mem[i] = NULL;
|
|
return 0;
|
|
}
|
|
|
|
extern "C" struct group *
|
|
getgrnam32 (const char *name)
|
|
{
|
|
return internal_getgrnam (name);
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (getgrnam32, getgrnam)
|
|
#else
|
|
extern "C" struct __group16 *
|
|
getgrnam (const char *name)
|
|
{
|
|
static struct __group16 g16; /* FIXME: thread-safe? */
|
|
|
|
return grp32togrp16 (&g16, getgrnam32 (name));
|
|
}
|
|
#endif
|
|
|
|
extern "C" void
|
|
endgrent ()
|
|
{
|
|
_my_tls.locals.grp_pos = 0;
|
|
}
|
|
|
|
extern "C" struct group *
|
|
getgrent32 ()
|
|
{
|
|
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;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (getgrent32, getgrent)
|
|
#else
|
|
extern "C" struct __group16 *
|
|
getgrent ()
|
|
{
|
|
static struct __group16 g16; /* FIXME: thread-safe? */
|
|
|
|
return grp32togrp16 (&g16, getgrent32 ());
|
|
}
|
|
#endif
|
|
|
|
extern "C" void
|
|
setgrent ()
|
|
{
|
|
_my_tls.locals.grp_pos = 0;
|
|
}
|
|
|
|
int
|
|
internal_getgroups (int gidsetsize, gid_t *grouplist, cygpsid *srchsid)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE hToken = NULL;
|
|
ULONG size;
|
|
int cnt = 0;
|
|
struct group *grp;
|
|
|
|
if (!srchsid && cygheap->user.groups.issetgroups ())
|
|
{
|
|
for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
|
|
if ((grp = internal_getgrsid (cygheap->user.groups.sgsids.sids[pg])))
|
|
{
|
|
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 ();
|
|
else
|
|
hToken = hProcToken;
|
|
|
|
status = NtQueryInformationToken (hToken, TokenGroups, NULL, 0, &size);
|
|
if (NT_SUCCESS (status) || status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
PTOKEN_GROUPS groups = (PTOKEN_GROUPS) alloca (size);
|
|
|
|
status = NtQueryInformationToken (hToken, TokenGroups, groups,
|
|
size, &size);
|
|
if (NT_SUCCESS (status))
|
|
{
|
|
cygsid sid;
|
|
|
|
if (srchsid)
|
|
{
|
|
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
|
|
if ((cnt = (*srchsid == groups->Groups[pg].Sid)))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
|
|
{
|
|
cygpsid sid = groups->Groups[pg].Sid;
|
|
if ((grp = internal_getgrsid (sid)))
|
|
{
|
|
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
|
|
debug_printf ("%u = NtQueryInformationToken(NULL) %y", size, status);
|
|
return cnt;
|
|
|
|
error:
|
|
set_errno (EINVAL);
|
|
return -1;
|
|
}
|
|
|
|
extern "C" int
|
|
getgroups32 (int gidsetsize, gid_t *grouplist)
|
|
{
|
|
return internal_getgroups (gidsetsize, grouplist);
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (getgroups32, getgroups)
|
|
#else
|
|
extern "C" int
|
|
getgroups (int gidsetsize, __gid16_t *grouplist)
|
|
{
|
|
gid_t *grouplist32 = NULL;
|
|
|
|
if (gidsetsize < 0)
|
|
{
|
|
set_errno (EINVAL);
|
|
return -1;
|
|
}
|
|
if (gidsetsize > 0 && grouplist)
|
|
grouplist32 = (gid_t *) alloca (gidsetsize * sizeof (gid_t));
|
|
|
|
int ret = internal_getgroups (gidsetsize, grouplist32);
|
|
|
|
if (gidsetsize > 0 && grouplist)
|
|
for (int i = 0; i < ret; ++ i)
|
|
grouplist[i] = grouplist32[i];
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* Core functionality of initgroups and getgrouplist. */
|
|
static void
|
|
get_groups (const char *user, gid_t gid, cygsidlist &gsids)
|
|
{
|
|
cygheap->user.deimpersonate ();
|
|
struct passwd *pw = internal_getpwnam (user);
|
|
struct group *grp = internal_getgrgid (gid);
|
|
cygsid usersid, grpsid;
|
|
if (usersid.getfrompw (pw))
|
|
get_server_groups (gsids, usersid, pw);
|
|
if (grpsid.getfromgr (grp))
|
|
gsids += grpsid;
|
|
cygheap->user.reimpersonate ();
|
|
}
|
|
|
|
extern "C" int
|
|
initgroups32 (const char *user, gid_t gid)
|
|
{
|
|
assert (user != NULL);
|
|
cygsidlist tmp_gsids (cygsidlist_auto, 12);
|
|
get_groups (user, gid, tmp_gsids);
|
|
cygsidlist new_gsids (cygsidlist_alloc, tmp_gsids.count ());
|
|
for (int i = 0; i < tmp_gsids.count (); i++)
|
|
new_gsids.sids[i] = tmp_gsids.sids[i];
|
|
new_gsids.count (tmp_gsids.count ());
|
|
cygheap->user.groups.update_supp (new_gsids);
|
|
syscall_printf ( "0 = initgroups(%s, %u)", user, gid);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (initgroups32, initgroups)
|
|
#else
|
|
extern "C" int
|
|
initgroups (const char *user, __gid16_t gid)
|
|
{
|
|
return initgroups32 (user, gid16togid32(gid));
|
|
}
|
|
#endif
|
|
|
|
extern "C" int
|
|
getgrouplist (const char *user, gid_t gid, gid_t *groups, int *ngroups)
|
|
{
|
|
int ret = 0;
|
|
int cnt = 0;
|
|
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.
|
|
FreeBSD calls assert for ngroups and allows a NULL groups if
|
|
*ngroups is 0. We follow FreeBSD's lead here, but always allow
|
|
a NULL groups pointer. */
|
|
assert (user != NULL);
|
|
assert (ngroups != NULL);
|
|
|
|
cygsidlist tmp_gsids (cygsidlist_auto, 12);
|
|
get_groups (user, gid, tmp_gsids);
|
|
for (int i = 0; i < tmp_gsids.count (); i++)
|
|
if ((grp = internal_getgrsid (tmp_gsids.sids[i])) != NULL)
|
|
{
|
|
if (groups && cnt < *ngroups)
|
|
groups[cnt] = grp->gr_gid;
|
|
++cnt;
|
|
}
|
|
if (cnt > *ngroups)
|
|
ret = -1;
|
|
*ngroups = cnt;
|
|
|
|
syscall_printf ( "%d = getgrouplist(%s, %u, %p, %d)",
|
|
ret, user, gid, groups, *ngroups);
|
|
return ret;
|
|
}
|
|
|
|
/* setgroups32: standards? */
|
|
extern "C" int
|
|
setgroups32 (int ngroups, const gid_t *grouplist)
|
|
{
|
|
syscall_printf ("setgroups32 (%d)", ngroups);
|
|
if (ngroups < 0 || (ngroups > 0 && !grouplist))
|
|
{
|
|
set_errno (EINVAL);
|
|
return -1;
|
|
}
|
|
|
|
cygsidlist gsids (cygsidlist_alloc, ngroups);
|
|
struct group *grp;
|
|
|
|
if (ngroups && !gsids.sids)
|
|
return -1;
|
|
|
|
for (int gidx = 0; gidx < ngroups; ++gidx)
|
|
{
|
|
if ((grp = internal_getgrgid (grouplist[gidx]))
|
|
&& gsids.addfromgr (grp))
|
|
continue;
|
|
debug_printf ("No sid found for gid %u", grouplist[gidx]);
|
|
gsids.free_sids ();
|
|
set_errno (EINVAL);
|
|
return -1;
|
|
}
|
|
cygheap->user.groups.update_supp (gsids);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
EXPORT_ALIAS (setgroups32, setgroups)
|
|
#else
|
|
extern "C" int
|
|
setgroups (int ngroups, const __gid16_t *grouplist)
|
|
{
|
|
gid_t *grouplist32 = NULL;
|
|
|
|
if (ngroups > 0 && grouplist)
|
|
{
|
|
grouplist32 = (gid_t *) alloca (ngroups * sizeof (gid_t));
|
|
if (grouplist32 == NULL)
|
|
return -1;
|
|
for (int i = 0; i < ngroups; i++)
|
|
grouplist32[i] = grouplist[i];
|
|
}
|
|
return setgroups32 (ngroups, grouplist32);
|
|
}
|
|
#endif
|