1 /* sec_auth.cc: NT authentication functions
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008 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, tgt.MaximumLength / sizeof (WCHAR), srcstr)
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),
141 (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR),
144 tgt.Length += (len - 1) * sizeof (WCHAR);
146 tgt.Length = tgt.MaximumLength = 0;
152 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
153 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
155 NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
156 if (ret != STATUS_SUCCESS)
157 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
162 close_local_policy (LSA_HANDLE &lsa)
164 if (lsa != INVALID_HANDLE_VALUE)
166 lsa = INVALID_HANDLE_VALUE;
169 /* CV, 2006-07-06: Missing in w32api. */
170 extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG,
171 PDOMAIN_CONTROLLER_INFOA *);
172 #define DS_FORCE_REDISCOVERY 1
175 get_logon_server (const char *domain, char *server, WCHAR *wserver,
179 PDOMAIN_CONTROLLER_INFOA pci;
181 DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
184 /* Empty domain is interpreted as local system */
185 if ((GetComputerName (server + 2, &size)) &&
186 (strcasematch (domain, server + 2) || !domain[0]))
188 server[0] = server[1] = '\\';
190 sys_mbstowcs (wserver, INTERNET_MAX_HOST_NAME_LENGTH + 1, server);
194 /* Try to get any available domain controller for this domain */
195 dret = DsGetDcNameA (NULL, domain, NULL, NULL,
196 rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
197 if (dret == ERROR_SUCCESS)
199 strcpy (server, pci->DomainControllerName);
200 sys_mbstowcs (wserver, INTERNET_MAX_HOST_NAME_LENGTH + 1, server);
201 NetApiBufferFree (pci);
202 debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server);
205 else if (dret == ERROR_PROC_NOT_FOUND)
207 /* NT4 w/o DSClient */
208 sys_mbstowcs (wdomain, INTERNET_MAX_HOST_NAME_LENGTH + 1, domain);
210 dret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf);
212 dret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf);
213 if (dret == NERR_Success)
215 sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
217 for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
219 NetApiBufferFree (buf);
220 debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server);
224 __seterrno_from_win_error (dret);
229 get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
232 char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
233 WCHAR wuser[UNLEN + 1];
234 sys_mbstowcs (wuser, UNLEN + 1, user);
235 LPGROUP_USERS_INFO_0 buf;
239 /* Look only on logonserver */
240 ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
241 MAX_PREFERRED_LENGTH, &cnt, &tot);
244 __seterrno_from_win_error (ret);
245 /* It's no error when the user name can't be found. */
246 return ret == NERR_UserNotFound;
249 len = strlen (domain);
250 strcpy (dgroup, domain);
251 dgroup[len++] = '\\';
253 for (DWORD i = 0; i < cnt; ++i)
256 DWORD glen = MAX_SID_LEN;
257 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
258 DWORD dlen = sizeof (domain);
259 SID_NAME_USE use = SidTypeInvalid;
261 sys_wcstombs (dgroup + len, GNLEN + 1, buf[i].grui0_name);
262 if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
263 debug_printf ("LookupAccountName(%s), %E", dgroup);
264 else if (legal_sid_type (use))
267 debug_printf ("Global group %s invalid. Domain: %s Use: %d",
268 dgroup, domain, use);
271 NetApiBufferFree (buf);
276 is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
278 LPLOCALGROUP_MEMBERS_INFO_1 buf;
282 /* Members can be users or global groups */
283 ret = NetLocalGroupGetMembers (NULL, wgroup, 1, (LPBYTE *) &buf,
284 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
289 for (DWORD bidx = 0; bidx < cnt; ++bidx)
290 if (EqualSid (pusersid, buf[bidx].lgrmi1_sid))
294 /* The extra test for the group being a global group or a well-known
295 group is necessary, since apparently also aliases (for instance
296 Administrators or Users) can be members of local groups, even
297 though MSDN states otherwise. The GUI refuses to put aliases into
298 local groups, but the CLI interface allows it. However, a normal
299 logon token does not contain groups, in which the user is only
300 indirectly a member by being a member of an alias in this group.
301 So we also should not put them into the token group list.
302 Note: Allowing those groups in our group list renders external
303 tokens invalid, so that it becomes impossible to logon with
304 password and valid logon token. */
305 for (int glidx = 0; glidx < grp_list.count (); ++glidx)
306 if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup
307 || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup)
308 && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid))
314 NetApiBufferFree (buf);
319 get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
321 LPLOCALGROUP_INFO_0 buf;
325 ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
326 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
329 __seterrno_from_win_error (ret);
333 char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
334 char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
338 blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
339 if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
340 || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
345 bgroup[blen++] = lgroup[llen++] = '\\';
347 for (DWORD i = 0; i < cnt; ++i)
348 if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
351 DWORD glen = MAX_SID_LEN;
352 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
353 DWORD dlen = sizeof (domain);
355 use = SidTypeInvalid;
356 sys_wcstombs (bgroup + blen, GNLEN + 1, buf[i].lgrpi0_name);
357 if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
359 if (GetLastError () != ERROR_NONE_MAPPED)
360 debug_printf ("LookupAccountName(%s), %E", bgroup);
361 strcpy (lgroup + llen, bgroup + blen);
362 if (!LookupAccountName (NULL, lgroup, gsid, &glen,
363 domain, &dlen, &use))
364 debug_printf ("LookupAccountName(%s), %E", lgroup);
366 if (!legal_sid_type (use))
367 debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
370 NetApiBufferFree (buf);
375 sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
379 for (DWORD i = 0; i < grps->GroupCount; ++i)
380 if (sid == grps->Groups[i].Sid)
386 get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
388 struct __group32 *gr;
391 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
393 if (gr->gr_gid == (__gid32_t) pw->pw_gid)
396 for (int gi = 0; gr->gr_mem[gi]; ++gi)
397 if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
401 if (gsid.getfromgr (gr))
408 get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
409 LUID auth_luid, int &auth_pos)
414 grp_list += well_known_local_sid;
415 if (sid_in_token_groups (my_grps, well_known_dialup_sid))
416 grp_list *= well_known_dialup_sid;
417 if (sid_in_token_groups (my_grps, well_known_network_sid))
418 grp_list *= well_known_network_sid;
419 if (sid_in_token_groups (my_grps, well_known_batch_sid))
420 grp_list *= well_known_batch_sid;
421 grp_list *= well_known_interactive_sid;
422 if (sid_in_token_groups (my_grps, well_known_service_sid))
423 grp_list *= well_known_service_sid;
424 if (sid_in_token_groups (my_grps, well_known_this_org_sid))
425 grp_list *= well_known_this_org_sid;
429 grp_list += well_known_local_sid;
430 grp_list *= well_known_interactive_sid;
432 if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
434 for (DWORD i = 0; i < my_grps->GroupCount; ++i)
435 if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
437 grp_list += my_grps->Groups[i].Sid;
438 auth_pos = grp_list.count () - 1;
445 get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
447 char user[UNLEN + 1];
448 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
449 WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
450 char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
452 if (well_known_system_sid == usersid)
454 grp_list *= well_known_admins_sid;
455 get_unix_group_sidlist (pw, grp_list);
459 grp_list *= well_known_world_sid;
460 grp_list *= well_known_authenticated_users_sid;
461 extract_nt_dom_user (pw, domain, user);
462 if (get_logon_server (domain, server, wserver, false)
463 && !get_user_groups (wserver, grp_list, user, domain)
464 && get_logon_server (domain, server, wserver, true))
465 get_user_groups (wserver, grp_list, user, domain);
466 if (get_user_local_groups (grp_list, usersid))
468 get_unix_group_sidlist (pw, grp_list);
475 get_initgroups_sidlist (cygsidlist &grp_list,
476 PSID usersid, PSID pgrpsid, struct passwd *pw,
477 PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
479 grp_list *= well_known_world_sid;
480 grp_list *= well_known_authenticated_users_sid;
481 if (well_known_system_sid == usersid)
484 get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
485 if (!get_server_groups (grp_list, usersid, pw))
488 /* special_pgrp true if pgrpsid is not in normal groups */
494 get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
495 PTOKEN_GROUPS my_grps, user_groups &groups,
496 LUID auth_luid, int &auth_pos)
498 tmp_list *= well_known_world_sid;
499 tmp_list *= well_known_authenticated_users_sid;
500 get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
501 get_server_groups (tmp_list, usersid, pw);
502 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
503 tmp_list += groups.sgsids.sids[gidx];
504 tmp_list += groups.pgsid;
507 static ULONG sys_privs[] = {
508 SE_CREATE_TOKEN_PRIVILEGE,
509 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
510 SE_LOCK_MEMORY_PRIVILEGE,
511 SE_INCREASE_QUOTA_PRIVILEGE,
513 SE_SECURITY_PRIVILEGE,
514 SE_TAKE_OWNERSHIP_PRIVILEGE,
515 SE_LOAD_DRIVER_PRIVILEGE,
516 SE_SYSTEM_PROFILE_PRIVILEGE, /* Vista ONLY */
517 SE_SYSTEMTIME_PRIVILEGE,
518 SE_PROF_SINGLE_PROCESS_PRIVILEGE,
519 SE_INC_BASE_PRIORITY_PRIVILEGE,
520 SE_CREATE_PAGEFILE_PRIVILEGE,
521 SE_CREATE_PERMANENT_PRIVILEGE,
523 SE_RESTORE_PRIVILEGE,
524 SE_SHUTDOWN_PRIVILEGE,
527 SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
528 SE_CHANGE_NOTIFY_PRIVILEGE,
530 SE_MANAGE_VOLUME_PRIVILEGE,
531 SE_IMPERSONATE_PRIVILEGE,
532 SE_CREATE_GLOBAL_PRIVILEGE,
533 SE_INCREASE_WORKING_SET_PRIVILEGE,
534 SE_TIME_ZONE_PRIVILEGE,
535 SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
538 #define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
540 static PTOKEN_PRIVILEGES
541 get_system_priv_list (size_t &size)
544 while (max_idx < SYSTEM_PRIVILEGES_COUNT
545 && sys_privs[max_idx] != wincap.max_sys_priv ())
547 if (max_idx >= SYSTEM_PRIVILEGES_COUNT)
548 api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs",
549 wincap.max_sys_priv ());
550 size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES);
551 PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
554 debug_printf ("malloc (system_privs) failed.");
557 privs->PrivilegeCount = 0;
558 for (ULONG i = 0; i <= max_idx; ++i)
560 privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L;
561 privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i];
562 privs->Privileges[privs->PrivilegeCount].Attributes =
563 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
564 ++privs->PrivilegeCount;
569 static PTOKEN_PRIVILEGES
570 get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
573 PLSA_UNICODE_STRING privstrs;
575 PTOKEN_PRIVILEGES privs = NULL;
577 char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
579 if (usersid == well_known_system_sid)
580 return get_system_priv_list (size);
582 for (int grp = -1; grp < grp_list.count (); ++grp)
586 if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
587 &cnt)) != STATUS_SUCCESS)
590 else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
594 for (ULONG i = 0; i < cnt; ++i)
597 PTOKEN_PRIVILEGES tmp;
600 sys_wcstombs (buf, sizeof (buf),
601 privstrs[i].Buffer, privstrs[i].Length / 2);
602 if (!privilege_luid (buf, &priv))
607 DWORD pcnt = privs->PrivilegeCount;
608 LUID_AND_ATTRIBUTES *p = privs->Privileges;
609 for (; pcnt > 0; --pcnt, ++p)
610 if (priv.HighPart == p->Luid.HighPart
611 && priv.LowPart == p->Luid.LowPart)
612 goto next_account_right;
615 tmp_count = privs ? privs->PrivilegeCount : 0;
616 size = sizeof (DWORD)
617 + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
618 tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
623 LsaFreeMemory (privstrs);
624 debug_printf ("realloc (privs) failed.");
627 tmp->PrivilegeCount = tmp_count;
629 privs->Privileges[privs->PrivilegeCount].Luid = priv;
630 privs->Privileges[privs->PrivilegeCount].Attributes =
631 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
632 ++privs->PrivilegeCount;
637 LsaFreeMemory (privstrs);
643 - the requested usersid matches the TokenUser and
644 - if setgroups has been called:
645 the token groups that are listed in /etc/group match the union of
646 the requested primary and supplementary groups in gsids.
647 - else the (unknown) implicitly requested supplementary groups and those
648 in the token are the groups associated with the usersid. We assume
649 they match and verify only the primary groups.
650 The requested primary group must appear in the token.
651 The primary group in the token is a group associated with the usersid,
652 except if the token is internal and the group is in the token SD
653 (see create_token). In that latter case that group must match the
654 requested primary group. */
656 verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
664 if (!GetTokenInformation (token, TokenSource,
665 &ts, sizeof ts, &size))
666 debug_printf ("GetTokenInformation(), %E");
668 *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
671 cygsid tok_usersid = NO_SID;
672 if (!GetTokenInformation (token, TokenUser,
673 &tok_usersid, sizeof tok_usersid, &size))
674 debug_printf ("GetTokenInformation(), %E");
675 if (usersid != tok_usersid)
678 /* For an internal token, if setgroups was not called and if the sd group
679 is not well_known_null_sid, it must match pgrpsid */
680 if (intern && !groups.issetgroups ())
682 const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR);
683 PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
684 cygpsid gsid (NO_SID);
685 if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
686 sd_buf, sd_buf_siz, &size))
687 debug_printf ("GetKernelObjectSecurity(), %E");
688 else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid,
690 debug_printf ("GetSecurityDescriptorGroup(), %E");
691 if (well_known_null_sid != gsid)
692 return gsid == groups.pgsid;
695 PTOKEN_GROUPS my_grps;
696 bool sawpg = false, ret = false;
698 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
699 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
700 debug_printf ("GetTokenInformation(token, TokenGroups), %E");
701 else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
702 debug_printf ("alloca (my_grps) failed.");
703 else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
704 debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
707 if (groups.issetgroups ()) /* setgroups was called */
710 struct __group32 *gr;
711 bool saw[groups.sgsids.count ()];
712 memset (saw, 0, sizeof(saw));
714 /* token groups found in /etc/group match the user.gsids ? */
715 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
716 if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
718 int pos = groups.sgsids.position (gsid);
721 else if (groups.pgsid == gsid)
723 else if (gsid != well_known_world_sid
727 /* user.sgsids groups must be in the token */
728 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
729 if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
732 /* The primary group must be in the token */
734 || sid_in_token_groups (my_grps, groups.pgsid)
735 || groups.pgsid == usersid;
742 create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
745 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
747 cygsidlist tmp_gsids (cygsidlist_auto, 12);
749 SECURITY_QUALITY_OF_SERVICE sqos =
750 { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
751 OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
752 LUID auth_luid = SYSTEM_LUID;
753 LARGE_INTEGER exp = { QuadPart:INT64_MAX };
756 PTOKEN_GROUPS new_tok_gsids = NULL;
757 PTOKEN_PRIVILEGES privs = NULL;
759 TOKEN_PRIMARY_GROUP pgrp;
760 TOKEN_DEFAULT_DACL dacl = {};
762 TOKEN_STATISTICS stats;
763 memcpy (source.SourceName, "Cygwin.1", 8);
764 source.SourceIdentifier.HighPart = 0;
765 source.SourceIdentifier.LowPart = 0x0101;
767 HANDLE token = INVALID_HANDLE_VALUE;
768 HANDLE primary_token = INVALID_HANDLE_VALUE;
770 PTOKEN_GROUPS my_tok_gsids = NULL;
774 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
775 push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
777 /* Open policy object. */
778 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
781 /* User, owner, primary group. */
782 user.User.Sid = usersid;
783 user.User.Attributes = 0;
784 owner.Owner = usersid;
786 /* Retrieve authentication id and group list from own process. */
789 /* Switching user context to SYSTEM doesn't inherit the authentication
790 id of the user account running current process. */
791 if (usersid != well_known_system_sid)
792 if (!GetTokenInformation (hProcToken, TokenStatistics,
793 &stats, sizeof stats, &size))
795 ("GetTokenInformation(hProcToken, TokenStatistics), %E");
797 auth_luid = stats.AuthenticationId;
799 /* Retrieving current processes group list to be able to inherit
800 some important well known group sids. */
801 if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size)
802 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
803 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
804 else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
805 debug_printf ("malloc (my_tok_gsids) failed.");
806 else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
809 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
815 /* Create list of groups, the user is member in. */
817 if (new_groups.issetgroups ())
818 get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
819 auth_luid, auth_pos);
820 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
821 my_tok_gsids, auth_luid, auth_pos))
825 pgrp.PrimaryGroup = new_groups.pgsid;
827 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
828 new_tok_gsids = (PTOKEN_GROUPS)
829 alloca (sizeof (DWORD) + tmp_gsids.count ()
830 * sizeof (SID_AND_ATTRIBUTES));
831 new_tok_gsids->GroupCount = tmp_gsids.count ();
832 for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
834 new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
835 new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
836 | SE_GROUP_ENABLED_BY_DEFAULT
840 new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
841 /* Retrieve list of privileges of that user. */
842 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
845 /* Let's be heroic... */
846 ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
847 &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
848 &pgrp, &dacl, &source);
850 __seterrno_from_nt_status (ret);
851 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
854 debug_printf ("Loading NtCreateToken failed.");
858 /* Convert to primary token. */
859 if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
860 SecurityImpersonation, TokenPrimary,
864 debug_printf ("DuplicateTokenEx %E");
869 pop_self_privilege ();
870 if (token != INVALID_HANDLE_VALUE)
876 close_local_policy (lsa);
878 debug_printf ("0x%x = create_token ()", primary_token);
879 return primary_token;
883 lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
885 cygsidlist tmp_gsids (cygsidlist_auto, 12);
888 HANDLE lsa_hdl = NULL, lsa = INVALID_HANDLE_VALUE;
889 LSA_OPERATIONAL_MODE sec_mode;
891 ULONG package_id, size;
892 LUID auth_luid = SYSTEM_LUID;
897 cyglsa_t *authinf = NULL;
900 PCYG_TOKEN_GROUPS gsids = NULL;
901 PTOKEN_PRIVILEGES privs = NULL;
903 PVOID profile = NULL;
906 size_t psize = 0, gsize = 0, dsize = 0;
907 OFFSET offset, sids_offset;
908 int tmpidx, non_well_known_cnt;
910 HANDLE user_token = NULL;
912 push_self_privilege (SE_TCB_PRIVILEGE, true);
914 /* Register as logon process. */
915 str2lsa (name, "Cygwin");
917 ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
918 if (ret != STATUS_SUCCESS)
920 debug_printf ("LsaRegisterLogonProcess: %p", ret);
921 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
924 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
926 debug_printf ("Couldn't load Secur32.dll");
929 /* Get handle to our own LSA package. */
930 str2lsa (name, CYG_LSA_PKGNAME);
931 ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
932 if (ret != STATUS_SUCCESS)
934 debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
935 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
939 /* Open policy object. */
940 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
944 str2buf2lsa (origin.str, origin.buf, "Cygwin");
945 /* Create token source. */
946 memcpy (ts.SourceName, "Cygwin.1", 8);
947 ts.SourceIdentifier.HighPart = 0;
948 ts.SourceIdentifier.LowPart = 0x0103;
950 /* Create list of groups, the user is member in. */
952 if (new_groups.issetgroups ())
953 get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
955 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
956 NULL, auth_luid, auth_pos))
958 /* The logon SID entry is not generated automatically on Windows 2000
959 and earlier for some reason. So add fake logon sid here, which is
960 filled with logon id values in the authentication package. */
961 if (wincap.needs_logon_sid_in_sid_list ())
962 tmp_gsids += fake_logon_sid;
964 tmp_gsids.debug_print ("tmp_gsids");
966 /* Evaluate size of TOKEN_GROUPS list */
967 non_well_known_cnt = tmp_gsids.non_well_known_count ();
968 gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
970 for (int i = 0; i < non_well_known_cnt; ++i)
971 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
972 gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
974 /* Retrieve list of privileges of that user. */
975 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
978 /* Create DefaultDacl. */
979 dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
980 + GetLengthSid (usersid)
981 + GetLengthSid (well_known_admins_sid)
982 + GetLengthSid (well_known_system_sid);
983 dacl = (PACL) alloca (dsize);
984 if (!InitializeAcl (dacl, dsize, ACL_REVISION))
986 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
988 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
989 well_known_admins_sid))
991 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
992 well_known_system_sid))
995 /* Evaluate authinf size and allocate authinf. */
996 authinf_size = (authinf->data - (PBYTE) authinf);
997 authinf_size += GetLengthSid (usersid); /* User SID */
998 authinf_size += gsize; /* Groups + Group SIDs */
999 /* When trying to define the admins group as primary group on Vista,
1000 LsaLogonUser fails with error STATUS_INVALID_OWNER. As workaround
1001 we define "Local" as primary group here. First, this adds the otherwise
1002 missing "Local" group to the group list and second, seteuid32
1003 sets the primary group to the group set in /etc/passwd anyway. */
1004 pgrpsid = well_known_local_sid;
1005 authinf_size += GetLengthSid (pgrpsid); /* Primary Group SID */
1007 authinf_size += psize; /* Privileges */
1008 authinf_size += 0; /* Owner SID */
1009 authinf_size += dsize; /* Default DACL */
1011 authinf = (cyglsa_t *) alloca (authinf_size);
1012 authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
1014 authinf->magic = CYG_LSA_MAGIC;
1016 extract_nt_dom_user (pw, authinf->domain, authinf->username);
1018 /* Store stuff in authinf with offset relative to start of "inf" member,
1019 instead of using pointers. */
1020 offset = authinf->data - (PBYTE) &authinf->inf;
1022 authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
1023 authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
1025 authinf->inf.User.User.Sid = offset;
1026 authinf->inf.User.User.Attributes = 0;
1027 CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
1029 offset += GetLengthSid (usersid);
1031 authinf->inf.Groups = offset;
1032 gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
1033 sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
1034 * sizeof (SID_AND_ATTRIBUTES);
1035 gsids->GroupCount = non_well_known_cnt;
1038 for (int i = 0; i < non_well_known_cnt; ++i)
1040 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
1042 gsids->Groups[i].Sid = sids_offset;
1043 gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
1044 | SE_GROUP_ENABLED_BY_DEFAULT
1046 /* Mark logon SID as logon SID :) */
1047 if (wincap.needs_logon_sid_in_sid_list ()
1048 && tmp_gsids.sids[tmpidx] == fake_logon_sid)
1049 gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
1050 CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
1051 (PSID) ((PBYTE) &authinf->inf + sids_offset),
1052 tmp_gsids.sids[tmpidx]);
1053 sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
1056 /* Primary Group SID */
1057 authinf->inf.PrimaryGroup.PrimaryGroup = offset;
1058 CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
1060 offset += GetLengthSid (pgrpsid);
1062 authinf->inf.Privileges = offset;
1063 memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
1066 authinf->inf.Owner.Owner = 0;
1068 authinf->inf.DefaultDacl.DefaultDacl = offset;
1069 memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
1071 authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
1072 CYGWIN_VERSION_DLL_MINOR);
1073 PDWORD csp = (PDWORD) &authinf->username;
1074 PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
1075 while (csp < csp_end)
1076 authinf->checksum += *csp++;
1078 /* Try to logon... */
1079 ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
1080 authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
1081 &user_token, "a, &ret2);
1082 if (ret != STATUS_SUCCESS)
1084 debug_printf ("LsaLogonUser: %p", ret);
1085 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1089 LsaFreeReturnBuffer (profile);
1091 if (wincap.has_mandatory_integrity_control ())
1093 typedef struct _TOKEN_LINKED_TOKEN
1096 } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
1097 # define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19)
1099 TOKEN_LINKED_TOKEN linked;
1101 if (GetTokenInformation (user_token, TokenLinkedToken,
1102 (PVOID) &linked, sizeof linked, &size))
1104 debug_printf ("Linked Token: %lu", linked.LinkedToken);
1105 if (linked.LinkedToken)
1106 user_token = linked.LinkedToken;
1113 close_local_policy (lsa);
1115 LsaDeregisterLogonProcess (lsa_hdl);
1116 pop_self_privilege ();
1118 debug_printf ("0x%x = lsaauth ()", user_token);