Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2015-02-23 23:51:12 +0300
committerCorinna Vinschen <corinna@vinschen.de>2015-02-23 23:51:12 +0300
commitbef55bb5c3322c57a0136b63c490e61f230da9be (patch)
treee940cee1f35cb965ba624deaf5840c34e1933d89
parent9b54770bd71537be20ded7eeb51e672f98839f7b (diff)
* 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.
-rw-r--r--winsup/cygwin/ChangeLog23
-rw-r--r--winsup/cygwin/autoload.cc1
-rw-r--r--winsup/cygwin/cygserver_pwdgrp.h14
-rw-r--r--winsup/cygwin/grp.cc175
-rw-r--r--winsup/cygwin/pwdgrp.h21
-rw-r--r--winsup/cygwin/uinfo.cc31
-rw-r--r--winsup/cygwin/userinfo.h38
7 files changed, 243 insertions, 60 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 7c89307d5..de0ba04dd 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,28 @@
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
Everyone sid before calling internal_getgrsid.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index ce5d32834..a4812a678 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -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)
diff --git a/winsup/cygwin/cygserver_pwdgrp.h b/winsup/cygwin/cygserver_pwdgrp.h
index 52b9b42ba..03a6a65d0 100644
--- a/winsup/cygwin/cygserver_pwdgrp.h
+++ b/winsup/cygwin/cygserver_pwdgrp.h
@@ -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;
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index ba6584c8e..676dd7672 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -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;
-
- status = NtQueryInformationToken (tok, TokenGroups, NULL, 0, &size);
- if (NT_SUCCESS (status) || status == STATUS_BUFFER_TOO_SMALL)
+ tok = cygheap->user.issetuid () ? cygheap->user.primary_token ()
+ : hProcToken;
+
+ /* 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
diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index 24a397185..ad2108063 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -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);
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index 1e8e7b671..c24d528f3 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -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);
}
diff --git a/winsup/cygwin/userinfo.h b/winsup/cygwin/userinfo.h
new file mode 100644
index 000000000..db557a77e
--- /dev/null
+++ b/winsup/cygwin/userinfo.h
@@ -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;
+};