* autoload.cc (LsaLookupSids): Import.

* cygserver_pwdgrp.h: Include userinfo.h.  Drop workaround defining
	fetch_user_arg_type_t locally.
	* grp.cc (internal_getgrsid_cachedonly): New function.
	(internal_getgrfull): Ditto.
	(internal_getgroups): Rearrange function.  Center around fetching all
	cached group info first, calling LsaLookupSids on all so far non-cached
	groups second.  Pass all available info to new internal_getgrfull call.
	* pwdgrp.h: Include userinfo.h.  Move definitions of
	fetch_user_arg_type_t and fetch_user_arg_t there.
	(pwdgrp::add_group_from_windows): Declare with getting full group info.
	Called from internal_getgrfull.
	* uinfo.cc (pwdgrp::add_group_from_windows): Define.
	(pwdgrp::fetch_account_from_line): Add default case.
	(pwdgrp::fetch_account_from_file): Ditto.
	(pwdgrp::fetch_account_from_windows): Handle FULL_grp_arg.
	(client_request_pwdgrp::client_request_pwdgrp): Add default case.
	* userinfo.h: New header.
	(enum fetch_user_arg_type_t): Add FULL_grp_arg.
	(struct fetch_full_grp_t): New datatype.
This commit is contained in:
Corinna Vinschen 2015-02-23 20:51:12 +00:00
parent 9b54770bd7
commit bef55bb5c3
7 changed files with 242 additions and 59 deletions

View File

@ -1,3 +1,26 @@
2015-02-23 Corinna Vinschen <corinna@vinschen.de>
* autoload.cc (LsaLookupSids): Import.
* cygserver_pwdgrp.h: Include userinfo.h. Drop workaround defining
fetch_user_arg_type_t locally.
* grp.cc (internal_getgrsid_cachedonly): New function.
(internal_getgrfull): Ditto.
(internal_getgroups): Rearrange function. Center around fetching all
cached group info first, calling LsaLookupSids on all so far non-cached
groups second. Pass all available info to new internal_getgrfull call.
* pwdgrp.h: Include userinfo.h. Move definitions of
fetch_user_arg_type_t and fetch_user_arg_t there.
(pwdgrp::add_group_from_windows): Declare with getting full group info.
Called from internal_getgrfull.
* uinfo.cc (pwdgrp::add_group_from_windows): Define.
(pwdgrp::fetch_account_from_line): Add default case.
(pwdgrp::fetch_account_from_file): Ditto.
(pwdgrp::fetch_account_from_windows): Handle FULL_grp_arg.
(client_request_pwdgrp::client_request_pwdgrp): Add default case.
* userinfo.h: New header.
(enum fetch_user_arg_type_t): Add FULL_grp_arg.
(struct fetch_full_grp_t): New datatype.
2015-02-23 Corinna Vinschen <corinna@vinschen.de>
* grp.cc (internal_getgroups): Check for group attributes and

View File

@ -545,6 +545,7 @@ LoadDLLfunc (LookupAccountSidW, 28, advapi32)
LoadDLLfunc (LsaClose, 4, advapi32)
LoadDLLfunc (LsaEnumerateAccountRights, 16, advapi32)
LoadDLLfunc (LsaFreeMemory, 4, advapi32)
LoadDLLfunc (LsaLookupSids, 20, advapi32)
LoadDLLfunc (LsaOpenPolicy, 16, advapi32)
LoadDLLfunc (LsaQueryInformationPolicy, 12, advapi32)
LoadDLLfunc (LsaRetrievePrivateData, 12, advapi32)

View File

@ -1,6 +1,6 @@
/* cygserver_pwdgrp.h: Request account information
Copyright 2014 Red Hat, Inc.
Copyright 2014, 2015 Red Hat, Inc.
This file is part of Cygwin.
@ -13,21 +13,11 @@ details. */
#include <sys/types.h>
#include "cygserver.h"
#include "userinfo.h"
class transport_layer_base;
class process_cache;
#ifdef __INSIDE_CYGWIN__
#include "pwdgrp.h"
#else
/* Don't include pwdgrp.h, but keep this in sync. */
enum fetch_user_arg_type_t {
SID_arg,
NAME_arg,
ID_arg
};
#endif
class client_request_pwdgrp : public client_request
{
friend class client_request;

View File

@ -14,6 +14,7 @@ details. */
#include "winsup.h"
#include <lm.h>
#include <ntsecapi.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@ -117,6 +118,65 @@ internal_getgrsid (cygpsid &sid, cyg_ldap *pldap)
return NULL;
}
/* Like internal_getgrsid but return only already cached data,
NULL otherwise. */
static struct group *
internal_getgrsid_cachedonly (cygpsid &sid)
{
struct group *ret;
/* Check caches only. */
if (cygheap->pg.nss_cygserver_caching ()
&& (ret = cygheap->pg.grp_cache.cygserver.find_group (sid)))
return ret;
if (cygheap->pg.nss_grp_files ()
&& (ret = cygheap->pg.grp_cache.file.find_group (sid)))
return ret;
if (cygheap->pg.nss_grp_db ()
&& (ret = cygheap->pg.grp_cache.win.find_group (sid)))
return ret;
return NULL;
}
/* Called from internal_getgroups. The full information required to create
a group account entry is already available from the LookupAccountSids
call. internal_getgrfull passes all available info into
pwdgrp::fetch_account_from_line, thus avoiding a LookupAccountSid call
for each group. This is quite a bit faster, especially in slower
environments. */
static struct group * __attribute__((used))
internal_getgrfull (fetch_full_grp_t &full_grp, cyg_ldap *pldap)
{
struct group *ret;
cygheap->pg.nss_init ();
/* Check caches first. */
if (cygheap->pg.nss_cygserver_caching ()
&& (ret = cygheap->pg.grp_cache.cygserver.find_group (full_grp.sid)))
return ret;
if (cygheap->pg.nss_grp_files ()
&& (ret = cygheap->pg.grp_cache.file.find_group (full_grp.sid)))
return ret;
if (cygheap->pg.nss_grp_db ()
&& (ret = cygheap->pg.grp_cache.win.find_group (full_grp.sid)))
return ret;
/* Ask sources afterwards. */
if (cygheap->pg.nss_cygserver_caching ()
&& (ret = cygheap->pg.grp_cache.cygserver.add_group_from_cygserver
(full_grp.sid)))
return ret;
if (cygheap->pg.nss_grp_files ())
{
cygheap->pg.grp_cache.file.check_file ();
if ((ret = cygheap->pg.grp_cache.file.add_group_from_file
(full_grp.sid)))
return ret;
}
if (cygheap->pg.nss_grp_db ())
return cygheap->pg.grp_cache.win.add_group_from_windows (full_grp, pldap);
return NULL;
}
/* This function gets only called from mkgroup via cygwin_internal. */
struct group *
internal_getgrsid_from_db (cygpsid &sid)
@ -502,8 +562,15 @@ internal_getgroups (int gidsetsize, gid_t *grouplist, cyg_ldap *pldap,
NTSTATUS status;
HANDLE tok;
ULONG size;
int cnt = 0;
PTOKEN_GROUPS groups;
PSID *sidp_buf;
ULONG scnt;
PLSA_REFERENCED_DOMAIN_LIST dlst = NULL;
PLSA_TRANSLATED_NAME nlst = NULL;
tmp_pathbuf tp;
struct group *grp;
int cnt = 0;
if (cygheap->user.groups.issetgroups ())
{
@ -515,53 +582,101 @@ internal_getgroups (int gidsetsize, gid_t *grouplist, cyg_ldap *pldap,
grouplist[cnt] = grp->gr_gid;
++cnt;
if (gidsetsize && cnt > gidsetsize)
goto error;
{
cnt = -1;
break;
}
}
return cnt;
goto out;
}
/* If impersonated, use impersonation token. */
tok = cygheap->user.issetuid () ? cygheap->user.primary_token () : hProcToken;
tok = cygheap->user.issetuid () ? cygheap->user.primary_token ()
: hProcToken;
status = NtQueryInformationToken (tok, TokenGroups, NULL, 0, &size);
if (NT_SUCCESS (status) || status == STATUS_BUFFER_TOO_SMALL)
/* Fetch groups from user token. */
groups = (PTOKEN_GROUPS) tp.w_get ();
status = NtQueryInformationToken (tok, TokenGroups, groups, 2 * NT_MAX_PATH,
&size);
if (!NT_SUCCESS (status))
{
PTOKEN_GROUPS groups = (PTOKEN_GROUPS) alloca (size);
status = NtQueryInformationToken (tok, TokenGroups, groups, size, &size);
system_printf ("token group list > 64K? status = %u", status);
goto out;
}
/* Iterate over the group list and check which of them are already cached.
Those are simply copied to grouplist. The non-cached ones are collected
in sidp_buf for a later call to LsaLookupSids. */
sidp_buf = (PSID *) tp.w_get ();
scnt = 0;
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
{
cygpsid sid = groups->Groups[pg].Sid;
if ((groups->Groups[pg].Attributes
& (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED)) == 0
|| sid == well_known_world_sid)
continue;
if ((grp = internal_getgrsid_cachedonly (sid)))
{
if (cnt < gidsetsize)
grouplist[cnt] = grp->gr_gid;
++cnt;
if (gidsetsize && cnt > gidsetsize)
{
cnt = -1;
goto out;
}
}
else
sidp_buf[scnt++] = sid;
}
/* If there are non-cached groups left, call LsaLookupSids and call
internal_getgrfull on the returned groups. This performs a lot
better than calling internal_getgrsid on each group. */
if (scnt > 0)
{
status = STATUS_ACCESS_DENIED;
HANDLE lsa = lsa_open_policy (NULL, POLICY_LOOKUP_NAMES);
if (!lsa)
{
system_printf ("POLICY_LOOKUP_NAMES not given?");
goto out;
}
status = LsaLookupSids (lsa, scnt, sidp_buf, &dlst, &nlst);
lsa_close_policy (lsa);
if (NT_SUCCESS (status))
{
ULONGLONG t0;
if (timeout_ns)
t0 = GetTickCount_ns ();
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
for (ULONG ncnt = 0; ncnt < scnt; ++ncnt)
{
cygpsid sid = groups->Groups[pg].Sid;
if ((groups->Groups[pg].Attributes
& (SE_GROUP_ENABLED | SE_GROUP_INTEGRITY_ENABLED)) == 0
|| sid == well_known_world_sid)
continue;
if ((grp = internal_getgrsid (sid, pldap)))
fetch_full_grp_t full_grp =
{
.sid = sidp_buf[ncnt],
.name = &nlst[ncnt].Name,
.dom = &dlst->Domains[nlst[ncnt].DomainIndex].Name,
.acc_type = nlst[ncnt].Use
};
if ((grp = internal_getgrfull (full_grp, pldap)))
{
if (cnt < gidsetsize)
grouplist[cnt] = grp->gr_gid;
++cnt;
if (gidsetsize && cnt > gidsetsize)
goto error;
{
cnt = -1;
goto out;
}
}
if (timeout_ns && GetTickCount_ns () - t0 >= timeout_ns)
break;
}
}
}
else
debug_printf ("%u = NtQueryInformationToken(NULL) %y", size, status);
return cnt;
error:
set_errno (EINVAL);
return -1;
out:
if (dlst)
LsaFreeMemory (dlst);
if (nlst)
LsaFreeMemory (nlst);
if (cnt == -1)
set_errno (EINVAL);
return cnt;
}
extern "C" int

View File

@ -15,6 +15,7 @@ details. */
#include "sync.h"
#include "ldap.h"
#include "miscfuncs.h"
#include "userinfo.h"
/* These functions are needed to allow searching and walking through
the passwd and group lists */
@ -37,24 +38,6 @@ void *setgrent_filtered (int enums, PCWSTR enum_tdoms);
void *getgrent_filtered (void *gr);
void endgrent_filtered (void *gr);
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;
@ -176,6 +159,8 @@ public:
{ return (struct group *) add_account_from_windows (name, pldap); }
struct group *add_group_from_windows (uint32_t id, cyg_ldap *pldap = NULL)
{ return (struct group *) add_account_from_windows (id, pldap); }
struct group *add_group_from_windows (fetch_full_grp_t &full_grp,
cyg_ldap *pldap = NULL);
struct group *find_group (cygpsid &sid);
struct group *find_group (const char *name);
struct group *find_group (gid_t gid);

View File

@ -1545,6 +1545,19 @@ pwdgrp::add_account_from_windows (uint32_t id, cyg_ldap *pldap)
return add_account_post_fetch (line, true);
}
/* Called from internal_getgrfull, in turn called from internal_getgroups. */
struct group *
pwdgrp::add_group_from_windows (fetch_full_grp_t &full_grp, cyg_ldap *pldap)
{
fetch_user_arg_t arg;
arg.type = FULL_grp_arg;
arg.full_grp = &full_grp;
char *line = fetch_account_from_windows (arg, pldap);
if (!line)
return NULL;
return (struct group *) add_account_post_fetch (line, true);
}
/* Check if file exists and if it has been written to since last checked.
If file has been changed, invalidate the current cache.
@ -1627,6 +1640,8 @@ pwdgrp::fetch_account_from_line (fetch_user_arg_t &arg, const char *line)
if (strtoul (p + 1, &e, 10) != arg.id || !e || *e != ':')
return NULL;
break;
default:
return NULL;
}
return cstrdup (line);
}
@ -1653,6 +1668,8 @@ pwdgrp::fetch_account_from_file (fetch_user_arg_t &arg)
break;
case ID_arg:
break;
default:
return NULL;
}
if (rl.init (&attr, buf, NT_MAX_PATH))
while ((buf = rl.gets ()))
@ -1742,6 +1759,17 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
switch (arg.type)
{
case FULL_grp_arg:
{
sid = arg.full_grp->sid;
*wcpncpy (name, arg.full_grp->name->Buffer,
arg.full_grp->name->Length / sizeof (WCHAR)) = L'\0';
*wcpncpy (dom, arg.full_grp->dom->Buffer,
arg.full_grp->dom->Length / sizeof (WCHAR)) = L'\0';
acc_type = arg.full_grp->acc_type;
ret = acc_type != SidTypeUnknown;
}
break;
case SID_arg:
sid = *arg.sid;
ret = LookupAccountSidW (NULL, sid, name, &nlen, dom, &dlen, &acc_type);
@ -2489,6 +2517,9 @@ client_request_pwdgrp::client_request_pwdgrp (fetch_user_arg_t &arg, bool group)
case ID_arg:
_parameters.in.arg.id = arg.id;
len = sizeof (uint32_t);
default:
api_fatal ("Fetching account info from cygserver with wrong arg.type "
"%d", arg.type);
}
msglen (__builtin_offsetof (struct _pwdgrp_param_t::_pwdgrp_in_t, arg) + len);
}

38
winsup/cygwin/userinfo.h Normal file
View File

@ -0,0 +1,38 @@
/* userinfo.h
Copyright 2015 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 once
enum fetch_user_arg_type_t {
SID_arg,
NAME_arg,
ID_arg,
FULL_grp_arg,
};
struct fetch_full_grp_t {
cygpsid sid;
PUNICODE_STRING name;
PUNICODE_STRING dom;
SID_NAME_USE acc_type;
};
struct fetch_user_arg_t
{
fetch_user_arg_type_t type;
union {
cygpsid *sid;
const char *name;
uint32_t id;
fetch_full_grp_t *full_grp;
};
/* Only used in fetch_account_from_file/line. */
size_t len;
};