1 /* sec_auth.cc: NT authentication functions
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
28 #include <cygwin/version.h>
31 cygwin_set_impersonation_token (const HANDLE hToken)
33 debug_printf ("set_impersonation_token (%d)", hToken);
34 cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken;
38 extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
43 strlcpy (user, pw->pw_name, UNLEN + 1);
44 debug_printf ("pw_gecos %x (%s)", pw->pw_gecos, pw->pw_gecos);
46 if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
47 (d == pw->pw_gecos || d[-1] == ','))
49 c = strechr (d + 2, ',');
50 if ((u = strechr (d + 2, '\\')) >= c)
52 else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
53 strlcpy (domain, d + 2, u - d - 1);
54 if (c - u <= UNLEN + 1)
55 strlcpy (user, u + 1, c - u);
61 DWORD ulen = UNLEN + 1;
62 DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
64 if (psid.getfrompw (pw))
65 LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
69 cygwin_logon_user (const struct passwd *pw, const char *password)
74 return INVALID_HANDLE_VALUE;
77 char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
78 char nt_user[UNLEN + 1];
81 extract_nt_dom_user (pw, nt_domain, nt_user);
82 debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
83 /* CV 2005-06-08: LogonUser should run under the primary process token,
84 otherwise it returns with ERROR_ACCESS_DENIED on W2K. Don't ask me why. */
86 if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
87 LOGON32_LOGON_INTERACTIVE,
88 LOGON32_PROVIDER_DEFAULT,
92 hToken = INVALID_HANDLE_VALUE;
94 else if (!SetHandleInformation (hToken,
100 hToken = INVALID_HANDLE_VALUE;
102 cygheap->user.reimpersonate ();
103 debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
108 str2lsa (LSA_STRING &tgt, const char *srcstr)
110 tgt.Length = strlen (srcstr);
111 tgt.MaximumLength = tgt.Length + 1;
112 tgt.Buffer = (PCHAR) srcstr;
116 str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
118 tgt.Length = strlen (srcstr);
119 tgt.MaximumLength = tgt.Length + 1;
120 tgt.Buffer = (PCHAR) buf;
121 memcpy (buf, srcstr, tgt.MaximumLength);
124 /* The dimension of buf is assumed to be at least strlen(srcstr) + 1,
125 The result will be shorter if the input has multibyte chars */
127 str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
129 tgt.Buffer = (PWCHAR) buf;
130 tgt.MaximumLength = (strlen (srcstr) + 1) * sizeof (WCHAR);
131 tgt.Length = sys_mbstowcs (buf, srcstr, tgt.MaximumLength / sizeof (WCHAR))
134 tgt.Length -= sizeof (WCHAR);
138 str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
140 int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR), srcstr,
141 (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR));
143 tgt.Length += (len - 1) * sizeof (WCHAR);
145 tgt.Length = tgt.MaximumLength = 0;
151 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
152 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
154 NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
155 if (ret != STATUS_SUCCESS)
156 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
161 close_local_policy (LSA_HANDLE &lsa)
163 if (lsa != INVALID_HANDLE_VALUE)
165 lsa = INVALID_HANDLE_VALUE;
168 /* CV, 2006-07-06: Missing in w32api. */
169 extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG,
170 PDOMAIN_CONTROLLER_INFOA *);
171 #define DS_FORCE_REDISCOVERY 1
174 get_logon_server (const char *domain, char *server, WCHAR *wserver,
178 PDOMAIN_CONTROLLER_INFOA pci;
180 DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
183 /* Empty domain is interpreted as local system */
184 if ((GetComputerName (server + 2, &size)) &&
185 (strcasematch (domain, server + 2) || !domain[0]))
187 server[0] = server[1] = '\\';
189 sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
193 /* Try to get any available domain controller for this domain */
194 dret = DsGetDcNameA (NULL, domain, NULL, NULL,
195 rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
196 if (dret == ERROR_SUCCESS)
198 strcpy (server, pci->DomainControllerName);
199 sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
200 NetApiBufferFree (pci);
201 debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server);
204 else if (dret == ERROR_PROC_NOT_FOUND)
206 /* NT4 w/o DSClient */
207 sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
209 dret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf);
211 dret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf);
212 if (dret == NERR_Success)
214 sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
216 for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
218 NetApiBufferFree (buf);
219 debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server);
223 __seterrno_from_win_error (dret);
228 get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
231 char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
232 WCHAR wuser[UNLEN + 1];
233 sys_mbstowcs (wuser, user, UNLEN + 1);
234 LPGROUP_USERS_INFO_0 buf;
238 /* Look only on logonserver */
239 ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
240 MAX_PREFERRED_LENGTH, &cnt, &tot);
243 __seterrno_from_win_error (ret);
244 /* It's no error when the user name can't be found. */
245 return ret == NERR_UserNotFound;
248 len = strlen (domain);
249 strcpy (dgroup, domain);
250 dgroup[len++] = '\\';
252 for (DWORD i = 0; i < cnt; ++i)
255 DWORD glen = MAX_SID_LEN;
256 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
257 DWORD dlen = sizeof (domain);
258 SID_NAME_USE use = SidTypeInvalid;
260 sys_wcstombs (dgroup + len, GNLEN + 1, buf[i].grui0_name);
261 if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
262 debug_printf ("LookupAccountName(%s), %E", dgroup);
263 else if (legal_sid_type (use))
266 debug_printf ("Global group %s invalid. Domain: %s Use: %d",
267 dgroup, domain, use);
270 NetApiBufferFree (buf);
275 is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
277 LPLOCALGROUP_MEMBERS_INFO_1 buf;
281 /* Members can be users or global groups */
282 ret = NetLocalGroupGetMembers (NULL, wgroup, 1, (LPBYTE *) &buf,
283 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
288 for (DWORD bidx = 0; bidx < cnt; ++bidx)
289 if (EqualSid (pusersid, buf[bidx].lgrmi1_sid))
293 /* The extra test for the group being a global group or a well-known
294 group is necessary, since apparently also aliases (for instance
295 Administrators or Users) can be members of local groups, even
296 though MSDN states otherwise. The GUI refuses to put aliases into
297 local groups, but the CLI interface allows it. However, a normal
298 logon token does not contain groups, in which the user is only
299 indirectly a member by being a member of an alias in this group.
300 So we also should not put them into the token group list.
301 Note: Allowing those groups in our group list renders external
302 tokens invalid, so that it becomes impossible to logon with
303 password and valid logon token. */
304 for (int glidx = 0; glidx < grp_list.count (); ++glidx)
305 if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup
306 || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup)
307 && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid))
313 NetApiBufferFree (buf);
318 get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
320 LPLOCALGROUP_INFO_0 buf;
324 ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
325 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
328 __seterrno_from_win_error (ret);
332 char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
333 char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
337 blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
338 if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
339 || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
344 bgroup[blen++] = lgroup[llen++] = '\\';
346 for (DWORD i = 0; i < cnt; ++i)
347 if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
350 DWORD glen = MAX_SID_LEN;
351 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
352 DWORD dlen = sizeof (domain);
354 use = SidTypeInvalid;
355 sys_wcstombs (bgroup + blen, GNLEN + 1, buf[i].lgrpi0_name);
356 if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
358 if (GetLastError () != ERROR_NONE_MAPPED)
359 debug_printf ("LookupAccountName(%s), %E", bgroup);
360 strcpy (lgroup + llen, bgroup + blen);
361 if (!LookupAccountName (NULL, lgroup, gsid, &glen,
362 domain, &dlen, &use))
363 debug_printf ("LookupAccountName(%s), %E", lgroup);
365 if (!legal_sid_type (use))
366 debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
369 NetApiBufferFree (buf);
374 sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
378 for (DWORD i = 0; i < grps->GroupCount; ++i)
379 if (sid == grps->Groups[i].Sid)
385 get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
387 struct __group32 *gr;
390 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
392 if (gr->gr_gid == (__gid32_t) pw->pw_gid)
395 for (int gi = 0; gr->gr_mem[gi]; ++gi)
396 if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
400 if (gsid.getfromgr (gr))
407 get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
408 LUID auth_luid, int &auth_pos)
413 grp_list += well_known_local_sid;
414 if (sid_in_token_groups (my_grps, well_known_dialup_sid))
415 grp_list *= well_known_dialup_sid;
416 if (sid_in_token_groups (my_grps, well_known_network_sid))
417 grp_list *= well_known_network_sid;
418 if (sid_in_token_groups (my_grps, well_known_batch_sid))
419 grp_list *= well_known_batch_sid;
420 grp_list *= well_known_interactive_sid;
421 if (sid_in_token_groups (my_grps, well_known_service_sid))
422 grp_list *= well_known_service_sid;
423 if (sid_in_token_groups (my_grps, well_known_this_org_sid))
424 grp_list *= well_known_this_org_sid;
428 grp_list += well_known_local_sid;
429 grp_list *= well_known_interactive_sid;
431 if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
433 for (DWORD i = 0; i < my_grps->GroupCount; ++i)
434 if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
436 grp_list += my_grps->Groups[i].Sid;
437 auth_pos = grp_list.count () - 1;
444 get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
446 char user[UNLEN + 1];
447 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
448 WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
449 char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
451 if (well_known_system_sid == usersid)
453 grp_list *= well_known_admins_sid;
454 get_unix_group_sidlist (pw, grp_list);
458 grp_list *= well_known_world_sid;
459 grp_list *= well_known_authenticated_users_sid;
460 extract_nt_dom_user (pw, domain, user);
461 if (get_logon_server (domain, server, wserver, false)
462 && !get_user_groups (wserver, grp_list, user, domain)
463 && get_logon_server (domain, server, wserver, true))
464 get_user_groups (wserver, grp_list, user, domain);
465 if (get_user_local_groups (grp_list, usersid))
467 get_unix_group_sidlist (pw, grp_list);
474 get_initgroups_sidlist (cygsidlist &grp_list,
475 PSID usersid, PSID pgrpsid, struct passwd *pw,
476 PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
478 grp_list *= well_known_world_sid;
479 grp_list *= well_known_authenticated_users_sid;
480 if (well_known_system_sid == usersid)
483 get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
484 if (!get_server_groups (grp_list, usersid, pw))
487 /* special_pgrp true if pgrpsid is not in normal groups */
493 get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
494 PTOKEN_GROUPS my_grps, user_groups &groups,
495 LUID auth_luid, int &auth_pos)
497 tmp_list *= well_known_world_sid;
498 tmp_list *= well_known_authenticated_users_sid;
499 get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
500 get_server_groups (tmp_list, usersid, pw);
501 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
502 tmp_list += groups.sgsids.sids[gidx];
503 tmp_list += groups.pgsid;
506 static ULONG sys_privs[] = {
507 SE_CREATE_TOKEN_PRIVILEGE,
508 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
509 SE_LOCK_MEMORY_PRIVILEGE,
510 SE_INCREASE_QUOTA_PRIVILEGE,
512 SE_SECURITY_PRIVILEGE,
513 SE_TAKE_OWNERSHIP_PRIVILEGE,
514 SE_LOAD_DRIVER_PRIVILEGE,
515 SE_SYSTEM_PROFILE_PRIVILEGE, /* Vista ONLY */
516 SE_SYSTEMTIME_PRIVILEGE,
517 SE_PROF_SINGLE_PROCESS_PRIVILEGE,
518 SE_INC_BASE_PRIORITY_PRIVILEGE,
519 SE_CREATE_PAGEFILE_PRIVILEGE,
520 SE_CREATE_PERMANENT_PRIVILEGE,
522 SE_RESTORE_PRIVILEGE,
523 SE_SHUTDOWN_PRIVILEGE,
526 SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
527 SE_CHANGE_NOTIFY_PRIVILEGE,
529 SE_MANAGE_VOLUME_PRIVILEGE,
530 SE_IMPERSONATE_PRIVILEGE,
531 SE_CREATE_GLOBAL_PRIVILEGE,
532 SE_INCREASE_WORKING_SET_PRIVILEGE,
533 SE_TIME_ZONE_PRIVILEGE,
534 SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
537 #define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
539 static PTOKEN_PRIVILEGES
540 get_system_priv_list (size_t &size)
543 while (max_idx < SYSTEM_PRIVILEGES_COUNT
544 && sys_privs[max_idx] != wincap.max_sys_priv ())
546 if (max_idx >= SYSTEM_PRIVILEGES_COUNT)
547 api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs",
548 wincap.max_sys_priv ());
549 size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES);
550 PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
553 debug_printf ("malloc (system_privs) failed.");
556 privs->PrivilegeCount = 0;
557 for (ULONG i = 0; i <= max_idx; ++i)
559 privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L;
560 privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i];
561 privs->Privileges[privs->PrivilegeCount].Attributes =
562 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
563 ++privs->PrivilegeCount;
568 static PTOKEN_PRIVILEGES
569 get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
572 PLSA_UNICODE_STRING privstrs;
574 PTOKEN_PRIVILEGES privs = NULL;
576 char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
578 if (usersid == well_known_system_sid)
579 return get_system_priv_list (size);
581 for (int grp = -1; grp < grp_list.count (); ++grp)
585 if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
586 &cnt)) != STATUS_SUCCESS)
589 else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
593 for (ULONG i = 0; i < cnt; ++i)
596 PTOKEN_PRIVILEGES tmp;
599 sys_wcstombs (buf, sizeof (buf),
600 privstrs[i].Buffer, privstrs[i].Length / 2);
601 if (!privilege_luid (buf, &priv))
606 DWORD pcnt = privs->PrivilegeCount;
607 LUID_AND_ATTRIBUTES *p = privs->Privileges;
608 for (; pcnt > 0; --pcnt, ++p)
609 if (priv.HighPart == p->Luid.HighPart
610 && priv.LowPart == p->Luid.LowPart)
611 goto next_account_right;
614 tmp_count = privs ? privs->PrivilegeCount : 0;
615 size = sizeof (DWORD)
616 + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
617 tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
622 LsaFreeMemory (privstrs);
623 debug_printf ("realloc (privs) failed.");
626 tmp->PrivilegeCount = tmp_count;
628 privs->Privileges[privs->PrivilegeCount].Luid = priv;
629 privs->Privileges[privs->PrivilegeCount].Attributes =
630 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
631 ++privs->PrivilegeCount;
636 LsaFreeMemory (privstrs);
642 - the requested usersid matches the TokenUser and
643 - if setgroups has been called:
644 the token groups that are listed in /etc/group match the union of
645 the requested primary and supplementary groups in gsids.
646 - else the (unknown) implicitly requested supplementary groups and those
647 in the token are the groups associated with the usersid. We assume
648 they match and verify only the primary groups.
649 The requested primary group must appear in the token.
650 The primary group in the token is a group associated with the usersid,
651 except if the token is internal and the group is in the token SD
652 (see create_token). In that latter case that group must match the
653 requested primary group. */
655 verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
663 if (!GetTokenInformation (token, TokenSource,
664 &ts, sizeof ts, &size))
665 debug_printf ("GetTokenInformation(), %E");
667 *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
670 cygsid tok_usersid = NO_SID;
671 if (!GetTokenInformation (token, TokenUser,
672 &tok_usersid, sizeof tok_usersid, &size))
673 debug_printf ("GetTokenInformation(), %E");
674 if (usersid != tok_usersid)
677 /* For an internal token, if setgroups was not called and if the sd group
678 is not well_known_null_sid, it must match pgrpsid */
679 if (intern && !groups.issetgroups ())
681 const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR);
682 PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
683 cygpsid gsid (NO_SID);
684 if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
685 sd_buf, sd_buf_siz, &size))
686 debug_printf ("GetKernelObjectSecurity(), %E");
687 else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid,
689 debug_printf ("GetSecurityDescriptorGroup(), %E");
690 if (well_known_null_sid != gsid)
691 return gsid == groups.pgsid;
694 PTOKEN_GROUPS my_grps;
695 bool sawpg = false, ret = false;
697 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
698 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
699 debug_printf ("GetTokenInformation(token, TokenGroups), %E");
700 else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
701 debug_printf ("alloca (my_grps) failed.");
702 else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
703 debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
706 if (groups.issetgroups ()) /* setgroups was called */
709 struct __group32 *gr;
710 bool saw[groups.sgsids.count ()];
711 memset (saw, 0, sizeof(saw));
713 /* token groups found in /etc/group match the user.gsids ? */
714 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
715 if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
717 int pos = groups.sgsids.position (gsid);
720 else if (groups.pgsid == gsid)
722 else if (gsid != well_known_world_sid
726 /* user.sgsids groups must be in the token */
727 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
728 if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
731 /* The primary group must be in the token */
733 || sid_in_token_groups (my_grps, groups.pgsid)
734 || groups.pgsid == usersid;
741 create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
744 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
746 cygsidlist tmp_gsids (cygsidlist_auto, 12);
748 SECURITY_QUALITY_OF_SERVICE sqos =
749 { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
750 OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
751 LUID auth_luid = SYSTEM_LUID;
752 LARGE_INTEGER exp = { QuadPart:INT64_MAX };
755 PTOKEN_GROUPS new_tok_gsids = NULL;
756 PTOKEN_PRIVILEGES privs = NULL;
758 TOKEN_PRIMARY_GROUP pgrp;
759 TOKEN_DEFAULT_DACL dacl = {};
761 TOKEN_STATISTICS stats;
762 memcpy (source.SourceName, "Cygwin.1", 8);
763 source.SourceIdentifier.HighPart = 0;
764 source.SourceIdentifier.LowPart = 0x0101;
766 HANDLE token = INVALID_HANDLE_VALUE;
767 HANDLE primary_token = INVALID_HANDLE_VALUE;
769 PTOKEN_GROUPS my_tok_gsids = NULL;
773 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
774 push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
776 /* Open policy object. */
777 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
780 /* User, owner, primary group. */
781 user.User.Sid = usersid;
782 user.User.Attributes = 0;
783 owner.Owner = usersid;
785 /* Retrieve authentication id and group list from own process. */
788 /* Switching user context to SYSTEM doesn't inherit the authentication
789 id of the user account running current process. */
790 if (usersid != well_known_system_sid)
791 if (!GetTokenInformation (hProcToken, TokenStatistics,
792 &stats, sizeof stats, &size))
794 ("GetTokenInformation(hProcToken, TokenStatistics), %E");
796 auth_luid = stats.AuthenticationId;
798 /* Retrieving current processes group list to be able to inherit
799 some important well known group sids. */
800 if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size)
801 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
802 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
803 else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
804 debug_printf ("malloc (my_tok_gsids) failed.");
805 else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
808 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
814 /* Create list of groups, the user is member in. */
816 if (new_groups.issetgroups ())
817 get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
818 auth_luid, auth_pos);
819 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
820 my_tok_gsids, auth_luid, auth_pos))
824 pgrp.PrimaryGroup = new_groups.pgsid;
826 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
827 new_tok_gsids = (PTOKEN_GROUPS)
828 alloca (sizeof (DWORD) + tmp_gsids.count ()
829 * sizeof (SID_AND_ATTRIBUTES));
830 new_tok_gsids->GroupCount = tmp_gsids.count ();
831 for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
833 new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
834 new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
835 | SE_GROUP_ENABLED_BY_DEFAULT
839 new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
840 /* Retrieve list of privileges of that user. */
841 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
844 /* Let's be heroic... */
845 ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
846 &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
847 &pgrp, &dacl, &source);
849 __seterrno_from_nt_status (ret);
850 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
853 debug_printf ("Loading NtCreateToken failed.");
857 /* Convert to primary token. */
858 if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
859 SecurityImpersonation, TokenPrimary,
863 debug_printf ("DuplicateTokenEx %E");
868 pop_self_privilege ();
869 if (token != INVALID_HANDLE_VALUE)
875 close_local_policy (lsa);
877 debug_printf ("0x%x = create_token ()", primary_token);
878 return primary_token;
882 lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
884 cygsidlist tmp_gsids (cygsidlist_auto, 12);
887 HANDLE lsa_hdl = NULL, lsa = INVALID_HANDLE_VALUE;
888 LSA_OPERATIONAL_MODE sec_mode;
890 ULONG package_id, size;
891 LUID auth_luid = SYSTEM_LUID;
896 cyglsa_t *authinf = NULL;
899 PCYG_TOKEN_GROUPS gsids = NULL;
900 PTOKEN_PRIVILEGES privs = NULL;
902 PVOID profile = NULL;
905 size_t psize = 0, gsize = 0, dsize = 0;
906 OFFSET offset, sids_offset;
907 int tmpidx, non_well_known_cnt;
909 HANDLE user_token = NULL;
911 push_self_privilege (SE_TCB_PRIVILEGE, true);
913 /* Register as logon process. */
914 str2lsa (name, "Cygwin");
916 ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
917 if (ret != STATUS_SUCCESS)
919 debug_printf ("LsaRegisterLogonProcess: %p", ret);
920 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
923 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
925 debug_printf ("Couldn't load Secur32.dll");
928 /* Get handle to our own LSA package. */
929 str2lsa (name, CYG_LSA_PKGNAME);
930 ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
931 if (ret != STATUS_SUCCESS)
933 debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
934 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
938 /* Open policy object. */
939 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
943 str2buf2lsa (origin.str, origin.buf, "Cygwin");
944 /* Create token source. */
945 memcpy (ts.SourceName, "Cygwin.1", 8);
946 ts.SourceIdentifier.HighPart = 0;
947 ts.SourceIdentifier.LowPart = 0x0103;
949 /* Create list of groups, the user is member in. */
951 if (new_groups.issetgroups ())
952 get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
954 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
955 NULL, auth_luid, auth_pos))
957 /* The logon SID entry is not generated automatically on Windows 2000
958 and earlier for some reason. So add fake logon sid here, which is
959 filled with logon id values in the authentication package. */
960 if (wincap.needs_logon_sid_in_sid_list ())
961 tmp_gsids += fake_logon_sid;
963 tmp_gsids.debug_print ("tmp_gsids");
965 /* Evaluate size of TOKEN_GROUPS list */
966 non_well_known_cnt = tmp_gsids.non_well_known_count ();
967 gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
969 for (int i = 0; i < non_well_known_cnt; ++i)
970 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
971 gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
973 /* Retrieve list of privileges of that user. */
974 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
977 /* Create DefaultDacl. */
978 dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
979 + GetLengthSid (usersid)
980 + GetLengthSid (well_known_admins_sid)
981 + GetLengthSid (well_known_system_sid);
982 dacl = (PACL) alloca (dsize);
983 if (!InitializeAcl (dacl, dsize, ACL_REVISION))
985 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
987 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
988 well_known_admins_sid))
990 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
991 well_known_system_sid))
994 /* Evaluate authinf size and allocate authinf. */
995 authinf_size = (authinf->data - (PBYTE) authinf);
996 authinf_size += GetLengthSid (usersid); /* User SID */
997 authinf_size += gsize; /* Groups + Group SIDs */
998 /* When trying to define the admins group as primary group on Vista,
999 LsaLogonUser fails with error STATUS_INVALID_OWNER. As workaround
1000 we define "Local" as primary group here. First, this adds the otherwise
1001 missing "Local" group to the group list and second, seteuid32
1002 sets the primary group to the group set in /etc/passwd anyway. */
1003 pgrpsid = well_known_local_sid;
1004 authinf_size += GetLengthSid (pgrpsid); /* Primary Group SID */
1006 authinf_size += psize; /* Privileges */
1007 authinf_size += 0; /* Owner SID */
1008 authinf_size += dsize; /* Default DACL */
1010 authinf = (cyglsa_t *) alloca (authinf_size);
1011 authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
1013 authinf->magic = CYG_LSA_MAGIC;
1015 extract_nt_dom_user (pw, authinf->domain, authinf->username);
1017 /* Store stuff in authinf with offset relative to start of "inf" member,
1018 instead of using pointers. */
1019 offset = authinf->data - (PBYTE) &authinf->inf;
1021 authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
1022 authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
1024 authinf->inf.User.User.Sid = offset;
1025 authinf->inf.User.User.Attributes = 0;
1026 CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
1028 offset += GetLengthSid (usersid);
1030 authinf->inf.Groups = offset;
1031 gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
1032 sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
1033 * sizeof (SID_AND_ATTRIBUTES);
1034 gsids->GroupCount = non_well_known_cnt;
1037 for (int i = 0; i < non_well_known_cnt; ++i)
1039 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
1041 gsids->Groups[i].Sid = sids_offset;
1042 gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
1043 | SE_GROUP_ENABLED_BY_DEFAULT
1045 /* Mark logon SID as logon SID :) */
1046 if (wincap.needs_logon_sid_in_sid_list ()
1047 && tmp_gsids.sids[tmpidx] == fake_logon_sid)
1048 gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
1049 CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
1050 (PSID) ((PBYTE) &authinf->inf + sids_offset),
1051 tmp_gsids.sids[tmpidx]);
1052 sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
1055 /* Primary Group SID */
1056 authinf->inf.PrimaryGroup.PrimaryGroup = offset;
1057 CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
1059 offset += GetLengthSid (pgrpsid);
1061 authinf->inf.Privileges = offset;
1062 memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
1065 authinf->inf.Owner.Owner = 0;
1067 authinf->inf.DefaultDacl.DefaultDacl = offset;
1068 memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
1070 authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
1071 CYGWIN_VERSION_DLL_MINOR);
1072 PDWORD csp = (PDWORD) &authinf->username;
1073 PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
1074 while (csp < csp_end)
1075 authinf->checksum += *csp++;
1077 /* Try to logon... */
1078 ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
1079 authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
1080 &user_token, "a, &ret2);
1081 if (ret != STATUS_SUCCESS)
1083 debug_printf ("LsaLogonUser: %p", ret);
1084 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1088 LsaFreeReturnBuffer (profile);
1090 if (wincap.has_mandatory_integrity_control ())
1092 typedef struct _TOKEN_LINKED_TOKEN
1095 } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
1096 # define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19)
1098 TOKEN_LINKED_TOKEN linked;
1100 if (GetTokenInformation (user_token, TokenLinkedToken,
1101 (PVOID) &linked, sizeof linked, &size))
1103 debug_printf ("Linked Token: %lu", linked.LinkedToken);
1104 if (linked.LinkedToken)
1105 user_token = linked.LinkedToken;
1112 close_local_policy (lsa);
1114 LsaDeregisterLogonProcess (lsa_hdl);
1115 pop_self_privilege ();
1117 debug_printf ("0x%x = lsaauth ()", user_token);