OSDN Git Service

* cyglsa.h: New header file.
authorcorinna <corinna>
Mon, 27 Nov 2006 12:59:58 +0000 (12:59 +0000)
committercorinna <corinna>
Mon, 27 Nov 2006 12:59:58 +0000 (12:59 +0000)
* environ.cc: Disable subauth settings.
* grp.cc: Accomodate cygsidlist's count now being a method.
* sec_helper.cc (SECURITY_MANDATORY_INTEGRITY_AUTHORITY): Remove.
(mandatory_medium_integrity_sid): Remove.
(mandatory_high_integrity_sid): Remove.
(mandatory_system_integrity_sid): Remove.
(fake_logon_sid): Add.
(cygsid::get_sid): Add well_known parameter.  Set well_known_sid
accordingly.
(cygsid::getfromstr): Ditto.
(cygsidlist::alloc_sids): Move here from security.cc.
(cygsidlist::free_sids): Ditto.
(cygsidlist::add): Move here from security.h.  Add well_known parameter.
Set well_known_sid accordingly.  Don't allow duplicate SIDs.
* security.cc: Include cyglsa.h and cygwin/version.h.  Throughout
accomodate cygsidlist's count now being a method.  Throughout drop
redundant "contains" tests.
(get_user_local_groups): Add local groups as well known SIDs.
(get_token_group_sidlist): Add well known groups as well known SIDs.
(get_server_groups): Ditto.  Only call get_unix_group_sidlist after
get_user_local_groups to maintain "well_known_sid" attribute.
(get_initgroups_sidlist): Add well known groups as well known SIDs.
(get_setgroups_sidlist): Add usersid and struct passwd parameter to
allow calling get_server_groups from here.
(get_system_priv_list): Make static.  Return size of TOKEN_PRIVILEGES
structure.
(get_priv_list): Ditto.
(create_token): Accomodate above changes.  Drop misguided attempt to
add MIC SIDs to created user token.  Print returned token as hex value.
(subauth): Disable.
(lsaauth): New function implementing client side of LSA authentication.
* security.h (class cygsid): Add well_known_sid attribute.  Accomodate
throughout.  Add *= operator to create a well known SID.
(class cygsidlist): Rename count to cnt.  Make count a method.
(cygsidlist::add): Move to sec_helper.cc.
(cygsidlist::operator *=): New method to add well known SID.
(cygsidlist::non_well_known_count): New method returning number of
non well known SIDs in list.
(cygsidlist::next_non_well_known_sid): New method returning next non
well known SID by index.
(mandatory_medium_integrity_sid): Drop declaration.
(mandatory_high_integrity_sid): Drop declaration.
(mandatory_system_integrity_sid): Drop declaration.
(fake_logon_sid): Add declaration.
(subauth): Disable declaration.
(lsaauth): Add declaration.
* syscalls.cc (seteuid32): Disable subauthentication.  Add LSA
authentication.
* wincap.h: Define needs_logon_sid_in_sid_list throughout.
* wincap.cc: Ditto.

winsup/cygwin/ChangeLog
winsup/cygwin/cyglsa.h [new file with mode: 0644]
winsup/cygwin/environ.cc
winsup/cygwin/grp.cc
winsup/cygwin/sec_helper.cc
winsup/cygwin/security.cc
winsup/cygwin/security.h
winsup/cygwin/syscalls.cc
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h

index e35ed57..177e77c 100644 (file)
@@ -1,3 +1,57 @@
+2006-11-27  Corinna Vinschen  <corinna@vinschen.de>
+
+       * cyglsa.h: New header file.
+       * environ.cc: Disable subauth settings.
+       * grp.cc: Accomodate cygsidlist's count now being a method.
+       * sec_helper.cc (SECURITY_MANDATORY_INTEGRITY_AUTHORITY): Remove.
+       (mandatory_medium_integrity_sid): Remove.
+       (mandatory_high_integrity_sid): Remove.
+       (mandatory_system_integrity_sid): Remove.
+       (fake_logon_sid): Add.
+       (cygsid::get_sid): Add well_known parameter.  Set well_known_sid
+       accordingly.
+       (cygsid::getfromstr): Ditto.
+       (cygsidlist::alloc_sids): Move here from security.cc.
+       (cygsidlist::free_sids): Ditto.
+       (cygsidlist::add): Move here from security.h.  Add well_known parameter.
+       Set well_known_sid accordingly.  Don't allow duplicate SIDs.
+       * security.cc: Include cyglsa.h and cygwin/version.h.  Throughout
+       accomodate cygsidlist's count now being a method.  Throughout drop
+       redundant "contains" tests.
+       (get_user_local_groups): Add local groups as well known SIDs.
+       (get_token_group_sidlist): Add well known groups as well known SIDs.
+       (get_server_groups): Ditto.  Only call get_unix_group_sidlist after
+       get_user_local_groups to maintain "well_known_sid" attribute.
+       (get_initgroups_sidlist): Add well known groups as well known SIDs.
+       (get_setgroups_sidlist): Add usersid and struct passwd parameter to
+       allow calling get_server_groups from here.
+       (get_system_priv_list): Make static.  Return size of TOKEN_PRIVILEGES
+       structure.
+       (get_priv_list): Ditto.
+       (create_token): Accomodate above changes.  Drop misguided attempt to
+       add MIC SIDs to created user token.  Print returned token as hex value.
+       (subauth): Disable.
+       (lsaauth): New function implementing client side of LSA authentication.
+       * security.h (class cygsid): Add well_known_sid attribute.  Accomodate
+       throughout.  Add *= operator to create a well known SID.
+       (class cygsidlist): Rename count to cnt.  Make count a method.
+       (cygsidlist::add): Move to sec_helper.cc.
+       (cygsidlist::operator *=): New method to add well known SID.
+       (cygsidlist::non_well_known_count): New method returning number of
+       non well known SIDs in list.
+       (cygsidlist::next_non_well_known_sid): New method returning next non
+       well known SID by index.
+       (mandatory_medium_integrity_sid): Drop declaration.
+       (mandatory_high_integrity_sid): Drop declaration.
+       (mandatory_system_integrity_sid): Drop declaration.
+       (fake_logon_sid): Add declaration.
+       (subauth): Disable declaration.
+       (lsaauth): Add declaration.
+       * syscalls.cc (seteuid32): Disable subauthentication.  Add LSA
+       authentication.
+       * wincap.h: Define needs_logon_sid_in_sid_list throughout.
+       * wincap.cc: Ditto.
+
 2006-11-23  Corinna Vinschen  <corinna@vinschen.de>
 
        * security.h (DBGSID): Define for debugging purposes.
diff --git a/winsup/cygwin/cyglsa.h b/winsup/cygwin/cyglsa.h
new file mode 100644 (file)
index 0000000..4af9e8c
--- /dev/null
@@ -0,0 +1,149 @@
+/* cyglsa.h: Header file for Cygwin LSA authentication
+
+   Copyright 2006 Red Hat, Inc.
+
+   Written by Corinna Vinschen <corinna@vinschen.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. */
+
+#ifndef _CYGLSA_H
+#define _CYGLSA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CYG_LSA_PKGNAME "CygwinLsa"
+
+#define CYG_LSA_MAGIC 0x0379f014LU
+
+/* Datastructures not defined in w32api. */
+typedef PVOID *PLSA_CLIENT_REQUEST;
+
+typedef struct _SECPKG_CLIENT_INFO
+{
+  LUID LogonId;
+  ULONG ProcessID;
+  ULONG ThreadID;
+  BOOLEAN HasTcbPrivilege;
+  BOOLEAN Impersonating;
+  BOOLEAN Restricted;
+} SECPKG_CLIENT_INFO, *PSECPKG_CLIENT_INFO;
+
+/* The table returned by LsaApInitializePackage is actually a
+   LSA_SECPKG_FUNCTION_TABLE even though that's not documented.
+   We need only a subset of this table, basically the LSA_DISPATCH_TABLE
+   plus the pointer to the GetClientInfo function. */
+typedef struct _LSA_SECPKG_FUNCS
+{
+  NTSTATUS (NTAPI *CreateLogonSession)(PLUID);
+  NTSTATUS (NTAPI *DeleteLogonSession)(PLUID);
+  NTSTATUS (NTAPI *AddCredentials)(PVOID); /* wrong prototype, unused */
+  NTSTATUS (NTAPI *GetCredentials)(PVOID); /* wrong prototype, unused */
+  NTSTATUS (NTAPI *DeleteCredentials)(PVOID); /* wrong prototype, unused */
+  PVOID (NTAPI *AllocateLsaHeap)(ULONG);
+  VOID (NTAPI *FreeLsaHeap)(PVOID);
+  NTSTATUS (NTAPI *AllocateClientBuffer)(PLSA_CLIENT_REQUEST, ULONG, PVOID *);
+  NTSTATUS (NTAPI *FreeClientBuffer)(PLSA_CLIENT_REQUEST, PVOID);
+  NTSTATUS (NTAPI *CopyToClientBuffer)(PLSA_CLIENT_REQUEST, ULONG,
+                                       PVOID, PVOID);
+  NTSTATUS (NTAPI *CopyFromClientBuffer)(PLSA_CLIENT_REQUEST, ULONG,
+                                         PVOID, PVOID);
+  NTSTATUS (NTAPI *ImpersonateClient)(VOID);
+  NTSTATUS (NTAPI *UnloadPackage)(VOID);
+  NTSTATUS (NTAPI *DuplicateHandle)(HANDLE,PHANDLE);
+  NTSTATUS (NTAPI *SaveSupplementalCredentials)(VOID);
+  NTSTATUS (NTAPI *CreateThread)(PVOID); /* wrong prototype, unused */
+  NTSTATUS (NTAPI *GetClientInfo)(PSECPKG_CLIENT_INFO);
+} LSA_SECPKG_FUNCS, *PLSA_SECPKG_FUNCS;
+
+typedef enum _LSA_TOKEN_INFORMATION_TYPE
+{
+  LsaTokenInformationNull,
+  LsaTokenInformationV1,
+  LsaTokenInformationV2
+} LSA_TOKEN_INFORMATION_TYPE, *PLSA_TOKEN_INFORMATION_TYPE;
+
+typedef struct _LSA_TOKEN_INFORMATION_V2
+{
+  LARGE_INTEGER ExpirationTime;
+  TOKEN_USER User;
+  PTOKEN_GROUPS Groups;
+  TOKEN_PRIMARY_GROUP PrimaryGroup;
+  PTOKEN_PRIVILEGES Privileges;
+  TOKEN_OWNER Owner;
+  TOKEN_DEFAULT_DACL DefaultDacl;
+} LSA_TOKEN_INFORMATION_V2, *PLSA_TOKEN_INFORMATION_V2;
+
+/* These structures are eqivalent to the appropriate Windows structures,
+   using 32 bit offsets instead of pointers.  These datastructures are
+   used to transfer the logon information to the LSA authentication package.
+   We can't use the LSA_TOKEN_INFORMATION_V2 structure directly, because
+   its size differs between 32 bit and 64 bit Windows. */
+
+typedef DWORD OFFSET;
+
+typedef struct _CYG_SID_AND_ATTRIBUTES
+{
+  OFFSET Sid;
+  DWORD Attributes;
+} CYG_SID_AND_ATTRIBUTES, *PCYG_SID_AND_ATTRIBUTES;
+
+typedef struct _CYG_TOKEN_USER
+{
+  CYG_SID_AND_ATTRIBUTES User;
+} CYG_TOKEN_USER, *PCYG_TOKEN_USER;
+
+typedef struct _CYG_TOKEN_GROUPS
+{
+  DWORD GroupCount;
+  CYG_SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];
+} CYG_TOKEN_GROUPS, *PCYG_TOKEN_GROUPS;
+
+typedef struct _CYG_TOKEN_PRIMARY_GROUP
+{
+  OFFSET PrimaryGroup;
+} CYG_TOKEN_PRIMARY_GROUP, *PCYG_TOKEN_PRIMARY_GROUP;
+
+typedef struct _CYG_TOKEN_OWNER
+{
+  OFFSET Owner;
+} CYG_TOKEN_OWNER, *PCYG_TOKEN_OWNER;
+
+typedef struct _CYG_TOKEN_DEFAULT_DACL
+{
+  OFFSET DefaultDacl;
+} CYG_TOKEN_DEFAULT_DACL, *PCYG_TOKEN_DEFAULT_DACL;
+
+typedef struct _CYG_LSA_TOKEN_INFORMATION
+{
+  LARGE_INTEGER ExpirationTime;
+  CYG_TOKEN_USER User;
+  OFFSET Groups;
+  CYG_TOKEN_PRIMARY_GROUP PrimaryGroup;
+  OFFSET Privileges;
+  CYG_TOKEN_OWNER Owner;
+  CYG_TOKEN_DEFAULT_DACL DefaultDacl;
+} CYG_LSA_TOKEN_INFORMATION, *PCYG_LSA_TOKEN_INFORMATION;
+
+/* This is the structure created by security.cc:lsaauth(), which is given to
+   LsaApLogonUser to create the token information returned to the LSA. */
+typedef struct
+{
+  DWORD magic;
+  DWORD checksum;
+  CHAR username[UNLEN + 1];
+  CHAR domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+  ULONG inf_size;
+  CYG_LSA_TOKEN_INFORMATION inf;
+  BYTE data[1];
+} cyglsa_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CYGLSA_H */
index 58b1e50..ec4edf5 100644 (file)
@@ -34,7 +34,9 @@ extern bool ignore_case_with_glob;
 extern bool allow_winsymlinks;
 extern bool strip_title_path;
 extern int pcheck_case;
+#if 0
 extern int subauth_id;
+#endif
 bool reset_com = false;
 static bool envcache = true;
 #ifdef USE_SERVER
@@ -530,6 +532,7 @@ codepage_init (const char *buf)
     debug_printf ("Wrong codepage name: %s", buf);
 }
 
+#if 0
 static void
 subauth_id_init (const char *buf)
 {
@@ -542,6 +545,7 @@ subauth_id_init (const char *buf)
   if (i > 127 && i != 132 && i <= 255)
     subauth_id = i;
 }
+#endif
 
 static void
 set_chunksize (const char *buf)
@@ -620,7 +624,9 @@ static struct parse_thing
 #endif
   {"smbntsec", {func: set_smbntsec}, isfunc, NULL, {{0}, {s: "yes"}}},
   {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
+#if 0
   {"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}},
+#endif
   {"title", {&display_title}, justset, NULL, {{false}, {true}}},
   {"traverse", {func: set_traverse}, isfunc, NULL, {{0}, {s: "yes"}}},
   {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
index 20698ad..13d334a 100644 (file)
@@ -348,7 +348,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid)
       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)
+         for (int pg = 0; pg < cygheap->user.groups.sgsids.count (); ++pg)
            if (sid == cygheap->user.groups.sgsids.sids[pg] &&
                sid != well_known_world_sid)
              {
@@ -484,10 +484,10 @@ initgroups32 (const char *name, __gid32_t gid)
       if (!get_server_groups (tmp_gsids, usersid, pw))
        goto out;
       tmp_gsids += grpsid;
-      cygsidlist new_gsids (cygsidlist_alloc, tmp_gsids.count);
-      for (int i = 0; i < tmp_gsids.count; i++)
+      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;
+      new_gsids.count (tmp_gsids.count ());
       cygheap->user.groups.update_supp (new_gsids);
     }
   ret = 0;
index ecb19fc..f1caf48 100644 (file)
@@ -67,15 +67,8 @@ MKSID (well_known_system_sid, "S-1-5-18",
 MKSID (well_known_admins_sid, "S-1-5-32-544",
        SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                 DOMAIN_ALIAS_RID_ADMINS);
-
-#define SECURITY_MANDATORY_INTEGRITY_AUTHORITY       {0,0,0,0,0,16}
-
-MKSID (mandatory_medium_integrity_sid, "S-1-64-8192",
-       SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 8192);
-MKSID (mandatory_high_integrity_sid, "S-1-64-12288",
-       SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 12288);
-MKSID (mandatory_system_integrity_sid, "S-1-64-16384",
-       SECURITY_MANDATORY_INTEGRITY_AUTHORITY, 1, 16384);
+MKSID (fake_logon_sid, "S-1-5-5-0-0",
+       SECURITY_NT_AUTHORITY, 3, SECURITY_LOGON_IDS_RID, 0, 0);
 
 bool
 cygpsid::operator== (const char *nsidstr) const
@@ -135,7 +128,7 @@ cygpsid::string (char *nsidstr) const
 }
 
 PSID
-cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r)
+cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known)
 {
   DWORD i;
   SID_IDENTIFIER_AUTHORITY sid_auth = {0,0,0,0,0,0};
@@ -150,11 +143,12 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r)
   InitializeSid (psid, &sid_auth, cnt);
   for (i = 0; i < cnt; ++i)
     memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD));
+  well_known_sid = well_known;
   return psid;
 }
 
 const PSID
-cygsid::getfromstr (const char *nsidstr)
+cygsid::getfromstr (const char *nsidstr, bool well_known)
 {
   char *lasts;
   DWORD s, cnt = 0;
@@ -166,7 +160,7 @@ cygsid::getfromstr (const char *nsidstr)
       while (cnt < 8 && *lasts == '-')
        r[cnt++] = strtoul (lasts + 1, &lasts, 10);
       if (!*lasts)
-       return get_sid (s, cnt, r);
+       return get_sid (s, cnt, r, well_known);
     }
   return psid = NO_SID;
 }
@@ -185,6 +179,48 @@ cygsid::getfromgr (const struct __group32 *gr)
   return (*this = sp) != NULL;
 }
 
+cygsid *
+cygsidlist::alloc_sids (int n)
+{
+  if (n > 0)
+    return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
+  else
+    return NULL;
+}
+
+void
+cygsidlist::free_sids ()
+{
+  if (sids)
+    cfree (sids);
+  sids = NULL;
+  cnt = maxcnt = 0;
+  type = cygsidlist_empty;
+}
+
+BOOL
+cygsidlist::add (const PSID nsi, bool well_known)
+{ 
+  if (contains (nsi)) 
+    return TRUE;
+  if (cnt >= maxcnt)
+    {
+      cygsid *tmp = new cygsid [2 * maxcnt];
+      if (!tmp) 
+       return FALSE;
+      maxcnt *= 2;
+      for (int i = 0; i < cnt; ++i)
+       tmp[i] = sids[i];
+      delete [] sids;
+      sids = tmp;
+    }
+  if (well_known) 
+    sids[cnt++] *= nsi;
+  else
+    sids[cnt++] = nsi;
+  return TRUE;
+} 
+
 bool
 get_sids_info (cygpsid owner_sid, cygpsid group_sid, __uid32_t * uidret, __gid32_t * gidret)
 {
index 96d903f..79c3c2f 100644 (file)
@@ -41,6 +41,8 @@ details. */
 #include "ntdll.h"
 #include "lm.h"
 #include "pwdgrp.h"
+#include "cyglsa.h"
+#include <cygwin/version.h>
 
 bool allow_ntsec;
 /* allow_smbntsec is handled exclusively in path.cc (path_conv::check).
@@ -48,25 +50,6 @@ bool allow_ntsec;
 bool allow_smbntsec;
 bool allow_traverse;
 
-cygsid *
-cygsidlist::alloc_sids (int n)
-{
-  if (n > 0)
-    return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
-  else
-    return NULL;
-}
-
-void
-cygsidlist::free_sids ()
-{
-  if (sids)
-    cfree (sids);
-  sids = NULL;
-  count = maxcount = 0;
-  type = cygsidlist_empty;
-}
-
 extern "C" void
 cygwin_set_impersonation_token (const HANDLE hToken)
 {
@@ -346,7 +329,7 @@ is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
           Note: Allowing those groups in our group list renders external
           tokens invalid, so that it becomes impossible to logon with
           password and valid logon token. */
-       for (int glidx = 0; glidx < grp_list.count; ++glidx)
+       for (int glidx = 0; glidx < grp_list.count (); ++glidx)
          if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup
               || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup)
              && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid))
@@ -409,8 +392,7 @@ get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
          }
        if (!legal_sid_type (use))
          debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
-       else if (!grp_list.contains (gsid))
-         grp_list += gsid;
+       grp_list *= gsid;
       }
   NetApiBufferFree (buf);
   return true;
@@ -480,7 +462,7 @@ get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
            goto found;
       continue;
     found:
-      if (gsid.getfromgr (gr) && !grp_list.contains (gsid))
+      if (gsid.getfromgr (gr))
        grp_list += gsid;
 
     }
@@ -498,26 +480,26 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
       /*if (sid_in_token_groups (my_grps, well_known_local_sid))*/
        grp_list += well_known_local_sid;
       if (sid_in_token_groups (my_grps, well_known_dialup_sid))
-       grp_list += well_known_dialup_sid;
+       grp_list *= well_known_dialup_sid;
       if (sid_in_token_groups (my_grps, well_known_network_sid))
-       grp_list += well_known_network_sid;
+       grp_list *= well_known_network_sid;
       if (sid_in_token_groups (my_grps, well_known_batch_sid))
-       grp_list += well_known_batch_sid;
+       grp_list *= well_known_batch_sid;
       /* This is a problem on 2K3 (only domain controllers?!?) which only
          enables tools for selected special groups.  A subauth token is
         only NETWORK, but NETWORK has no access to these tools.  Therefore
         we always add INTERACTIVE here. */
       /*if (sid_in_token_groups (my_grps, well_known_interactive_sid))*/
-       grp_list += well_known_interactive_sid;
+       grp_list *= well_known_interactive_sid;
       if (sid_in_token_groups (my_grps, well_known_service_sid))
-       grp_list += well_known_service_sid;
+       grp_list *= well_known_service_sid;
       if (sid_in_token_groups (my_grps, well_known_this_org_sid))
-       grp_list += well_known_this_org_sid;
+       grp_list *= well_known_this_org_sid;
     }
   else
     {
       grp_list += well_known_local_sid;
-      grp_list += well_known_interactive_sid;
+      grp_list *= well_known_interactive_sid;
     }
   if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
     {
@@ -525,7 +507,7 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
        if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
          {
            grp_list += my_grps->Groups[i].Sid;
-           auth_pos = grp_list.count - 1;
+           auth_pos = grp_list.count () - 1;
            break;
          }
     }
@@ -541,22 +523,24 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
 
   if (well_known_system_sid == usersid)
     {
-      grp_list += well_known_admins_sid;
+      grp_list *= well_known_admins_sid;
       get_unix_group_sidlist (pw, grp_list);
       return true;
     }
 
-  if (!grp_list.contains (well_known_world_sid))
-    grp_list += well_known_world_sid;
-  if (!grp_list.contains (well_known_authenticated_users_sid))
-    grp_list += well_known_authenticated_users_sid;
+  grp_list *= well_known_world_sid;
+  grp_list *= well_known_authenticated_users_sid;
   extract_nt_dom_user (pw, domain, user);
   if (get_logon_server (domain, server, wserver, false)
       && !get_user_groups (wserver, grp_list, user, domain)
       && get_logon_server (domain, server, wserver, true))
     get_user_groups (wserver, grp_list, user, domain);
-  get_unix_group_sidlist (pw, grp_list);
-  return get_user_local_groups (grp_list, usersid);
+  if (get_user_local_groups (grp_list, usersid))
+    {
+      get_unix_group_sidlist (pw, grp_list);
+      return true;
+    }
+  return false;
 }
 
 static bool
@@ -564,8 +548,8 @@ get_initgroups_sidlist (cygsidlist &grp_list,
                        PSID usersid, PSID pgrpsid, struct passwd *pw,
                        PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
 {
-  grp_list += well_known_world_sid;
-  grp_list += well_known_authenticated_users_sid;
+  grp_list *= well_known_world_sid;
+  grp_list *= well_known_authenticated_users_sid;
   if (well_known_system_sid == usersid)
     auth_pos = -1;
   else
@@ -574,24 +558,22 @@ get_initgroups_sidlist (cygsidlist &grp_list,
     return false;
 
   /* special_pgrp true if pgrpsid is not in normal groups */
-  if (!grp_list.contains (pgrpsid))
-    grp_list += pgrpsid;
+  grp_list += pgrpsid;
   return true;
 }
 
 static void
-get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps,
-                      user_groups &groups, LUID auth_luid, int &auth_pos)
+get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
+                      PTOKEN_GROUPS my_grps, user_groups &groups,
+                      LUID auth_luid, int &auth_pos)
 {
-  PSID pgpsid = groups.pgsid;
-  tmp_list += well_known_world_sid;
-  tmp_list += well_known_authenticated_users_sid;
+  tmp_list *= well_known_world_sid;
+  tmp_list *= well_known_authenticated_users_sid;
   get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
-  for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
-    if (!tmp_list.contains (groups.sgsids.sids[gidx]))
-      tmp_list += groups.sgsids.sids[gidx];
-  if (!groups.sgsids.contains (pgpsid))
-    tmp_list += pgpsid;
+  get_server_groups (tmp_list, usersid, pw);
+  for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
+    tmp_list += groups.sgsids.sids[gidx];
+  tmp_list += groups.pgsid;
 }
 
 static const cygpriv_idx sys_privs[] = {
@@ -628,13 +610,13 @@ static const cygpriv_idx sys_privs[] = {
 
 #define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
 
-PTOKEN_PRIVILEGES
-get_system_priv_list (cygsidlist &grp_list)
+static PTOKEN_PRIVILEGES
+get_system_priv_list (cygsidlist &grp_list, size_t &size)
 {
   const LUID *priv;
-  PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES)
-    malloc (sizeof (ULONG)
-           + SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES));
+  size = sizeof (ULONG)
+        + SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES);
+  PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
   if (!privs)
     {
       debug_printf ("malloc (system_privs) failed.");
@@ -653,8 +635,9 @@ get_system_priv_list (cygsidlist &grp_list)
   return privs;
 }
 
-PTOKEN_PRIVILEGES
-get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
+static PTOKEN_PRIVILEGES
+get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
+              size_t &size)
 {
   PLSA_UNICODE_STRING privstrs;
   ULONG cnt;
@@ -663,9 +646,9 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
   char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
 
   if (usersid == well_known_system_sid)
-    return get_system_priv_list (grp_list);
+    return get_system_priv_list (grp_list, size);
 
-  for (int grp = -1; grp < grp_list.count; ++grp)
+  for (int grp = -1; grp < grp_list.count (); ++grp)
     {
       if (grp == -1)
        {
@@ -699,9 +682,9 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
            }
 
          tmp_count = privs ? privs->PrivilegeCount : 0;
-         tmp = (PTOKEN_PRIVILEGES)
-           realloc (privs, sizeof (ULONG) +
-                    (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
+         size = sizeof (DWORD)
+                + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
+         tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
          if (!tmp)
            {
              if (privs)
@@ -794,7 +777,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
        {
          cygsid gsid;
          struct __group32 *gr;
-         bool saw[groups.sgsids.count];
+         bool saw[groups.sgsids.count ()];
          memset (saw, 0, sizeof(saw));
 
          /* token groups found in /etc/group match the user.gsids ? */
@@ -811,7 +794,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
                  goto done;
              }
          /* user.sgsids groups must be in the token */
-         for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
+         for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
            if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
              goto done;
        }
@@ -857,6 +840,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw,
 
   PTOKEN_GROUPS my_tok_gsids = NULL;
   DWORD size;
+  size_t psize = 0;
 
   /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
   push_self_privilege (SE_CREATE_TOKEN_PRIV, true);
@@ -929,8 +913,8 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw,
   /* Create list of groups, the user is member in. */
   int auth_pos;
   if (new_groups.issetgroups ())
-    get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid,
-                          auth_pos);
+    get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
+                          auth_luid, auth_pos);
   else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
                                    my_tok_gsids, auth_luid, auth_pos))
     goto out;
@@ -940,9 +924,9 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw,
 
   /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
   new_tok_gsids = (PTOKEN_GROUPS)
-                 alloca (sizeof (ULONG) + (tmp_gsids.count  + 1 )
+                 alloca (sizeof (DWORD) + tmp_gsids.count ()
                                           * sizeof (SID_AND_ATTRIBUTES));
-  new_tok_gsids->GroupCount = tmp_gsids.count;
+  new_tok_gsids->GroupCount = tmp_gsids.count ();
   for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
     {
       new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
@@ -952,42 +936,8 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw,
     }
   if (auth_pos >= 0)
     new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
-
-  /* On systems supporting Mandatory Integrity Control, add a MIC SID. */
-  if (wincap.has_mandatory_integrity_control ())
-    {
-      bool add_mic_sid = true;
-      new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes = 0;
-
-      /* The subauth token usually contains a MIC SID.  Copy it into our
-        group SID list. */
-      if (my_tok_gsids)
-       for (DWORD i = 0; i < my_tok_gsids->GroupCount; ++i)
-         if (EqualPrefixSid (mandatory_medium_integrity_sid,
-                             my_tok_gsids->Groups[i].Sid))
-           {
-             new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
-               = my_tok_gsids->Groups[i].Sid;
-             add_mic_sid = false;
-             break;
-           }
-      /* If no MIC SID was available add a matching one for the account type. */
-      if (add_mic_sid)
-        {
-         if (usersid == well_known_system_sid)
-           new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
-             = mandatory_system_integrity_sid;
-         else if (tmp_gsids.contains (well_known_admins_sid))
-           new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
-             = mandatory_high_integrity_sid;
-         else
-           new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
-             = mandatory_medium_integrity_sid;
-       }
-    }
-
   /* Retrieve list of privileges of that user. */
-  if (!privs && !(privs = get_priv_list (lsa, usersid, tmp_gsids)))
+  if (!privs && !(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
     goto out;
 
   /* Let's be heroic... */
@@ -1023,10 +973,16 @@ out:
     free (my_tok_gsids);
   close_local_policy (lsa);
 
-  debug_printf ("%d = create_token ()", primary_token);
+  debug_printf ("0x%x = create_token ()", primary_token);
   return primary_token;
 }
 
+/* Subauthentication gets useless now that real LSA authentication is
+   available.  The accompanying code in seteuid32 and environ.cc is
+   also disabled.
+   TODO: Deprecate and delete code entirely.
+   TODO: Delete from documentation. */
+#if 0
 extern "C"
 {
   BOOL WINAPI Wow64DisableWow64FsRedirection (PVOID *);
@@ -1047,7 +1003,7 @@ HANDLE
 subauth (struct passwd *pw)
 {
   LSA_STRING name;
-  HANDLE lsa_hdl;
+  HANDLE lsa_hdl = NULL;
   LSA_OPERATIONAL_MODE sec_mode;
   NTSTATUS ret, ret2;
   ULONG package_id, size;
@@ -1141,7 +1097,6 @@ subauth (struct passwd *pw)
     {
       debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
       __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-      LsaDeregisterLogonProcess (lsa_hdl);
       goto out;
     }
   /* Create origin. */
@@ -1170,7 +1125,6 @@ subauth (struct passwd *pw)
     {
       debug_printf ("LsaLogonUser: %d", ret);
       __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-      LsaDeregisterLogonProcess (lsa_hdl);
       goto out;
     }
   LsaFreeReturnBuffer (profile);
@@ -1180,11 +1134,254 @@ subauth (struct passwd *pw)
     __seterrno ();
 
 out:
+  if (lsa_hdl)
+    LsaDeregisterLogonProcess (lsa_hdl);
   pop_self_privilege ();
   if (user_token)
     CloseHandle (user_token);
   return primary_token;
 }
+#endif
+
+HANDLE
+lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
+{
+  cygsidlist tmp_gsids (cygsidlist_auto, 12);
+  cygpsid pgrpsid;
+  LSA_STRING name;
+  HANDLE lsa_hdl = NULL, lsa;
+  LSA_OPERATIONAL_MODE sec_mode;
+  NTSTATUS ret, ret2;
+  ULONG package_id, size;
+  LUID auth_luid = SYSTEM_LUID;
+  struct {
+    LSA_STRING str;
+    CHAR buf[16];
+  } origin;
+  cyglsa_t *authinf = NULL;
+  ULONG authinf_size;
+  TOKEN_SOURCE ts;
+  PCYG_TOKEN_GROUPS gsids = NULL;
+  PTOKEN_PRIVILEGES privs = NULL;
+  PACL dacl = NULL;
+  PVOID profile = NULL;
+  LUID luid;
+  QUOTA_LIMITS quota;
+  size_t psize = 0, gsize = 0, dsize = 0;
+  OFFSET offset, sids_offset;
+  int tmpidx, non_well_known_cnt;
+
+  HANDLE user_token = NULL;
+
+  push_self_privilege (SE_TCB_PRIV, true);
+
+  /* Register as logon process. */
+  str2lsa (name, "Cygwin");
+  SetLastError (0);
+  ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaRegisterLogonProcess: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+  else if (GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      debug_printf ("Couldn't load Secur32.dll");
+      goto out;
+    }
+  /* Get handle to our own LSA package. */
+  str2lsa (name, CYG_LSA_PKGNAME);
+  ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+
+  /* Open policy object. */
+  if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
+    goto out;
+
+  /* Create origin. */
+  str2buf2lsa (origin.str, origin.buf, "Cygwin");
+  /* Create token source. */
+  memcpy (ts.SourceName, "Cygwin.1", 8);
+  ts.SourceIdentifier.HighPart = 0;
+  ts.SourceIdentifier.LowPart = 0x0103;
+
+  /* Create list of groups, the user is member in. */
+  int auth_pos;
+  if (new_groups.issetgroups ())
+    get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
+                          auth_pos);
+  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
+                                   NULL, auth_luid, auth_pos))
+    goto out;
+  /* The logon SID entry is not generated automatically on Windows 2000
+     and earlier for some reason.  So add fake logon sid here, which is
+     filled with logon id values in the authentication package. */
+  if (wincap.needs_logon_sid_in_sid_list ())
+    tmp_gsids += fake_logon_sid;
+
+  tmp_gsids.debug_print ("tmp_gsids");
+
+  /* Evaluate size of TOKEN_GROUPS list */
+  non_well_known_cnt =  tmp_gsids.non_well_known_count ();
+  gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
+  tmpidx = -1;
+  for (int i = 0; i < non_well_known_cnt; ++i)
+    if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
+      gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
+
+  /* Retrieve list of privileges of that user. */
+  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
+    goto out;
+
+  /* Create DefaultDacl. */
+  dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
+         + GetLengthSid (usersid)
+         + GetLengthSid (well_known_admins_sid)
+         + GetLengthSid (well_known_system_sid);
+  dacl = (PACL) alloca (dsize);
+  if (!InitializeAcl (dacl, dsize, ACL_REVISION))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
+                           well_known_admins_sid))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
+                           well_known_system_sid))
+    goto out;
+
+  /* Evaluate authinf size and allocate authinf. */
+  authinf_size = (authinf->data - (PBYTE) authinf);
+  authinf_size += GetLengthSid (usersid);          /* User SID */
+  authinf_size += gsize;                           /* Groups + Group SIDs */
+  /* When trying to define the admins group as primary group on Vista,
+     LsaLogonUser fails with error STATUS_INVALID_OWNER.  As workaround
+     we define "Local" as primary group here.  First, this adds the otherwise
+     missing "Local" group to the group list and second, seteuid32
+     sets the primary group to the group set in /etc/passwd anyway. */
+  pgrpsid = well_known_local_sid;
+  authinf_size += GetLengthSid (pgrpsid);          /* Primary Group SID */
+
+  authinf_size += psize;                           /* Privileges */
+  authinf_size += 0;                               /* Owner SID */
+  authinf_size += dsize;                           /* Default DACL */
+
+  authinf = (cyglsa_t *) alloca (authinf_size);
+  authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
+
+  authinf->magic = CYG_LSA_MAGIC;
+
+  extract_nt_dom_user (pw, authinf->domain, authinf->username);
+
+  /* Store stuff in authinf with offset relative to start of "inf" member,
+     instead of using pointers. */
+  offset = authinf->data - (PBYTE) &authinf->inf;
+
+  authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
+  authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
+  /* User SID */
+  authinf->inf.User.User.Sid = offset;
+  authinf->inf.User.User.Attributes = 0;
+  CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
+          usersid);
+  offset += GetLengthSid (usersid);
+  /* Groups */
+  authinf->inf.Groups = offset;
+  gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
+  sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
+                                         * sizeof (SID_AND_ATTRIBUTES);
+  gsids->GroupCount = non_well_known_cnt;
+  /* Group SIDs */
+  tmpidx = -1;
+  for (int i = 0; i < non_well_known_cnt; ++i)
+    {
+      if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
+        break;
+      gsids->Groups[i].Sid = sids_offset;
+      gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
+                                   | SE_GROUP_ENABLED_BY_DEFAULT
+                                   | SE_GROUP_ENABLED;
+      /* Mark logon SID as logon SID :) */
+      if (wincap.needs_logon_sid_in_sid_list ()
+         && tmp_gsids.sids[tmpidx] == fake_logon_sid)
+        gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
+      CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
+              (PSID) ((PBYTE) &authinf->inf + sids_offset),
+              tmp_gsids.sids[tmpidx]);
+      sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
+    }
+  offset += gsize;
+  /* Primary Group SID */
+  authinf->inf.PrimaryGroup.PrimaryGroup = offset;
+  CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
+          pgrpsid);
+  offset += GetLengthSid (pgrpsid);
+  /* Privileges */
+  authinf->inf.Privileges = offset;
+  memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
+  offset += psize;
+  /* Owner */
+  authinf->inf.Owner.Owner = 0;
+  /* Default DACL */
+  authinf->inf.DefaultDacl.DefaultDacl = offset;
+  memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
+
+  authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
+                                           CYGWIN_VERSION_DLL_MINOR);
+  PDWORD csp = (PDWORD) &authinf->username;
+  PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
+  while (csp < csp_end)
+    authinf->checksum += *csp++;
+
+  /* Try to logon... */
+  ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
+                     authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
+                     &user_token, &quota, &ret2);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaLogonUser: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+  if (profile)
+    LsaFreeReturnBuffer (profile);
+
+  if (wincap.has_mandatory_integrity_control ())
+    {
+      typedef struct _TOKEN_LINKED_TOKEN
+      {
+       HANDLE LinkedToken;
+      } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
+#     define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19)
+
+      TOKEN_LINKED_TOKEN linked;
+
+      if (GetTokenInformation (user_token, TokenLinkedToken,
+                              (PVOID) &linked, sizeof linked, &size))
+       {
+         debug_printf ("Linked Token: %lu", linked.LinkedToken);
+         if (linked.LinkedToken)
+           user_token = linked.LinkedToken;
+       }
+    }
+
+out:
+  if (privs)
+    free (privs);
+  close_local_policy (lsa);
+  if (lsa_hdl)
+    LsaDeregisterLogonProcess (lsa_hdl);
+  pop_self_privilege ();
+
+  debug_printf ("0x%x = lsaauth ()", user_token);
+  return user_token;
+}
 
 /* read_sd reads a security descriptor from a file.
    In case of error, -1 is returned and errno is set.
index 0f0fdb0..9823ca2 100644 (file)
@@ -80,11 +80,12 @@ public:
 
 class cygsid : public cygpsid {
   char sbuf[MAX_SID_LEN];
+  bool well_known_sid;
 
-  const PSID getfromstr (const char *nsidstr);
-  PSID get_sid (DWORD s, DWORD cnt, DWORD *r);
+  const PSID getfromstr (const char *nsidstr, bool well_known);
+  PSID get_sid (DWORD s, DWORD cnt, DWORD *r, bool well_known);
 
-  inline const PSID assign (const PSID nsid)
+  inline const PSID assign (const PSID nsid, bool well_known)
     {
       if (!nsid)
        psid = NO_SID;
@@ -92,21 +93,32 @@ class cygsid : public cygpsid {
        {
          psid = (PSID) sbuf;
          CopySid (MAX_SID_LEN, psid, nsid);
+         well_known_sid = well_known;
        }
       return psid;
     }
 
 public:
   inline operator const PSID () { return psid; }
+  inline bool is_well_known_sid () { return well_known_sid; }
 
+  /* Both, = and *= are assignment operators.  = creates a "normal" SID,
+     *= marks the SID as being a well-known SID.  This difference is
+     important when creating a SID list for LSA authentication. */
   inline const PSID operator= (cygsid &nsid)
-    { return assign (nsid); }
+    { return assign (nsid, nsid.well_known_sid); }
   inline const PSID operator= (const PSID nsid)
-    { return assign (nsid); }
+    { return assign (nsid, false); }
   inline const PSID operator= (const char *nsidstr)
-    { return getfromstr (nsidstr); }
-
-  inline cygsid () : cygpsid ((PSID) sbuf) {}
+    { return getfromstr (nsidstr, false); }
+  inline const PSID operator*= (cygsid &nsid)
+    { return assign (nsid, true); }
+  inline const PSID operator*= (const PSID nsid)
+    { return assign (nsid, true); }
+  inline const PSID operator*= (const char *nsidstr)
+    { return getfromstr (nsidstr, true); }
+
+  inline cygsid () : cygpsid ((PSID) sbuf), well_known_sid (false) {}
   inline cygsid (const PSID nsid) { *this = nsid; }
   inline cygsid (const char *nstrsid) { *this = nstrsid; }
 
@@ -114,21 +126,28 @@ public:
 
   BOOL getfrompw (const struct passwd *pw);
   BOOL getfromgr (const struct __group32 *gr);
+
+  void debug_print (const char *prefix = NULL) const
+    {
+      char buf[256] __attribute__ ((unused));
+      debug_printf ("%s %s%s", prefix ?: "", string (buf) ?: "NULL", well_known_sid ? " (*)" : " (+)");
+    }
 };
 
 typedef enum { cygsidlist_empty, cygsidlist_alloc, cygsidlist_auto } cygsidlist_type;
 class cygsidlist {
-  int maxcount;
+  int maxcnt;
+  int cnt;
+
+  BOOL add (const PSID nsi, bool well_known); /* Only with auto for now */
+
 public:
-  int count;
   cygsid *sids;
   cygsidlist_type type;
 
   cygsidlist (cygsidlist_type t, int m)
+  : maxcnt (m), cnt (0), type (t)
     {
-      type = t;
-      count = 0;
-      maxcount = m;
       if (t == cygsidlist_alloc)
        sids = alloc_sids (m);
       else
@@ -136,49 +155,56 @@ public:
     }
   ~cygsidlist () { if (type == cygsidlist_auto) delete [] sids; }
 
-  BOOL add (const PSID nsi) /* Only with auto for now */
+  BOOL addfromgr (struct __group32 *gr) /* Only with alloc */
+    { return sids[cnt].getfromgr (gr) && ++cnt; }
+
+  /* += adds a "normal" SID, *= adds a well-known SID.  See comment in class
+     cygsid above. */
+  BOOL operator+= (cygsid &si) { return add ((PSID) si, false); }
+  BOOL operator+= (const char *sidstr) { cygsid nsi (sidstr);
+                                        return add ((PSID) nsi, false); }
+  BOOL operator+= (const PSID psid) { return add (psid, false); }
+  BOOL operator*= (cygsid &si) { return add ((PSID) si, true); }
+  BOOL operator*= (const char *sidstr) { cygsid nsi (sidstr);
+                                        return add ((PSID) nsi, true); }
+  BOOL operator*= (const PSID psid) { return add (psid, true); }
+
+  void count (int ncnt)
+    { cnt = ncnt; }
+  int count () const { return cnt; }
+  int non_well_known_count () const
     {
-      if (count >= maxcount)
-       {
-         cygsid *tmp = new cygsid [ 2 * maxcount];
-         if (!tmp)
-           return FALSE;
-         maxcount *= 2;
-         for (int i = 0; i < count; ++i)
-           tmp[i] = sids[i];
-         delete [] sids;
-         sids = tmp;
-       }
-      sids[count++] = nsi;
-      return TRUE;
+      int wcnt = 0;
+      for (int i = 0; i < cnt; ++i)
+        if (!sids[i].is_well_known_sid ())
+         ++wcnt;
+      return wcnt;
     }
-  BOOL add (cygsid &nsi) { return add ((PSID) nsi); }
-  BOOL add (const char *sidstr)
-    { cygsid nsi (sidstr); return add (nsi); }
-  BOOL addfromgr (struct __group32 *gr) /* Only with alloc */
-    { return sids[count].getfromgr (gr) && ++count; }
-
-  BOOL operator+= (cygsid &si) { return add (si); }
-  BOOL operator+= (const char *sidstr) { return add (sidstr); }
-  BOOL operator+= (const PSID psid) { return add (psid); }
 
   int position (const PSID sid) const
     {
-      for (int i = 0; i < count; ++i)
+      for (int i = 0; i < cnt; ++i)
        if (sids[i] == sid)
          return i;
       return -1;
     }
 
+  int next_non_well_known_sid (int idx)
+    {
+      while (++idx < cnt)
+        if (!sids[idx].is_well_known_sid ())
+         return idx;
+      return -1;
+    }
   BOOL contains (const PSID sid) const { return position (sid) >= 0; }
   cygsid *alloc_sids (int n);
   void free_sids ();
   void debug_print (const char *prefix = NULL) const
     {
       debug_printf ("-- begin sidlist ---");
-      if (!count)
+      if (!cnt)
        debug_printf ("No elements");
-      for (int i = 0; i < count; ++i)
+      for (int i = 0; i < cnt; ++i)
        sids[i].debug_print (prefix);
       debug_printf ("-- ende sidlist ---");
     }
@@ -256,9 +282,7 @@ extern cygpsid well_known_authenticated_users_sid;
 extern cygpsid well_known_this_org_sid;
 extern cygpsid well_known_system_sid;
 extern cygpsid well_known_admins_sid;
-extern cygpsid mandatory_medium_integrity_sid;
-extern cygpsid mandatory_high_integrity_sid;
-extern cygpsid mandatory_system_integrity_sid;
+extern cygpsid fake_logon_sid;
 
 /* Order must be same as cygpriv in sec_helper.cc. */
 enum cygpriv_idx {
@@ -348,11 +372,15 @@ struct _UNICODE_STRING;
 void __stdcall str2buf2uni (_UNICODE_STRING &, WCHAR *, const char *) __attribute__ ((regparm (3)));
 void __stdcall str2uni_cat (_UNICODE_STRING &, const char *) __attribute__ ((regparm (2)));
 
-/* Try a subauthentication. */
-HANDLE subauth (struct passwd *pw);
-/* Try creating a token directly. */
+/* Function creating a token by calling NtCreateToken. */
 HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw,
                     HANDLE subauth_token);
+#if 0
+/* Subauthentication function. */
+HANDLE subauth (struct passwd *pw);
+#endif
+/* LSA authentication function. */
+HANDLE lsaauth (cygsid &, user_groups &, struct passwd *);
 /* Verify an existing token */
 bool verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern = NULL);
 /* Get groups of a user */
index 241efd4..91c6960 100644 (file)
@@ -2111,30 +2111,46 @@ seteuid32 (__uid32_t uid)
   debug_printf ("Found token %d", new_token);
 
   /* If no impersonation token is available, try to
-     authenticate using NtCreateToken () or subauthentication. */
+     authenticate using NtCreateToken () or LSA authentication. */
   if (new_token == INVALID_HANDLE_VALUE)
     {
-      new_token = subauth (pw_new);
-      debug_printf ("subauth %s, try create_token.",
-                   new_token == INVALID_HANDLE_VALUE ? "failed" : "succeeded");
-      HANDLE new_token2 = create_token (usersid, groups, pw_new, new_token);
-      if (new_token2 == INVALID_HANDLE_VALUE)
-       {
+      if (!(new_token = lsaauth (usersid, groups, pw_new)))
+        {
+#if 0
+         new_token = subauth (pw_new);
+         debug_printf ("subauth %s, try create_token.",
+                       new_token == INVALID_HANDLE_VALUE ? "failed" : "succeeded");
+         HANDLE new_token2 = create_token (usersid, groups, pw_new, new_token);
+         if (new_token2 == INVALID_HANDLE_VALUE)
+           {
+             if (new_token == INVALID_HANDLE_VALUE)
+               {
+                 debug_printf ("create_token failed, bail out of here");
+                 cygheap->user.reimpersonate ();
+                 return -1;
+               }
+             debug_printf ("create_token failed, use original subauth token");
+           }
+         else
+           {
+             debug_printf ("create_token succeeded");
+             if (new_token != INVALID_HANDLE_VALUE)
+               CloseHandle (new_token);
+             new_token = new_token2;
+           }
+#else
+         debug_printf ("lsaauth failed, try create_token.");
+         new_token = create_token (usersid, groups, pw_new,
+                                   INVALID_HANDLE_VALUE);
          if (new_token == INVALID_HANDLE_VALUE)
            {
              debug_printf ("create_token failed, bail out of here");
              cygheap->user.reimpersonate ();
              return -1;
            }
-         debug_printf ("create_token failed, use original subauth token");
-       }
-      else
-        {
-         debug_printf ("create_token succeeded");
-         if (new_token != INVALID_HANDLE_VALUE)
-           CloseHandle (new_token);
-         new_token = new_token2;
+#endif
        }
+
       /* Keep at most one internal token */
       if (cygheap->user.internal_token != NO_IMPERSONATION)
        CloseHandle (cygheap->user.internal_token);
index 8879f9e..85405ba 100644 (file)
@@ -69,6 +69,7 @@ static NO_COPY wincaps wincap_unknown = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_95 = {
@@ -129,6 +130,7 @@ static NO_COPY wincaps wincap_95 = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_95osr2 = {
@@ -189,6 +191,7 @@ static NO_COPY wincaps wincap_95osr2 = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_98 = {
@@ -249,6 +252,7 @@ static NO_COPY wincaps wincap_98 = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_98se = {
@@ -309,6 +313,7 @@ static NO_COPY wincaps wincap_98se = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_me = {
@@ -369,6 +374,7 @@ static NO_COPY wincaps wincap_me = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_nt3 = {
@@ -429,6 +435,7 @@ static NO_COPY wincaps wincap_nt3 = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:true,
 };
 
 static NO_COPY wincaps wincap_nt4 = {
@@ -489,6 +496,7 @@ static NO_COPY wincaps wincap_nt4 = {
   has_exclusiveaddruse:false,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:true,
 };
 
 static NO_COPY wincaps wincap_nt4sp4 = {
@@ -549,6 +557,7 @@ static NO_COPY wincaps wincap_nt4sp4 = {
   has_exclusiveaddruse:true,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:true,
 };
 
 static NO_COPY wincaps wincap_2000 = {
@@ -609,6 +618,7 @@ static NO_COPY wincaps wincap_2000 = {
   has_exclusiveaddruse:true,
   has_buggy_restart_scan:true,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:true,
 };
 
 static NO_COPY wincaps wincap_xp = {
@@ -669,6 +679,7 @@ static NO_COPY wincaps wincap_xp = {
   has_exclusiveaddruse:true,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_2003 = {
@@ -729,6 +740,7 @@ static NO_COPY wincaps wincap_2003 = {
   has_exclusiveaddruse:true,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
+  needs_logon_sid_in_sid_list:false,
 };
 
 static NO_COPY wincaps wincap_vista = {
@@ -789,6 +801,7 @@ static NO_COPY wincaps wincap_vista = {
   has_exclusiveaddruse:true,
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:true,
+  needs_logon_sid_in_sid_list:false,
 };
 
 wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
index 63f8742..d40d12c 100644 (file)
@@ -70,6 +70,7 @@ struct wincaps
   unsigned has_exclusiveaddruse                                : 1;
   unsigned has_buggy_restart_scan                      : 1;
   unsigned has_mandatory_integrity_control             : 1;
+  unsigned needs_logon_sid_in_sid_list                 : 1;
 };
 
 class wincapc
@@ -146,6 +147,7 @@ public:
   bool IMPLEMENT (has_exclusiveaddruse)
   bool IMPLEMENT (has_buggy_restart_scan)
   bool IMPLEMENT (has_mandatory_integrity_control)
+  bool IMPLEMENT (needs_logon_sid_in_sid_list)
 
 #undef IMPLEMENT
 };