1 /* sec_auth.cc: NT authentication functions
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009 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
30 #include "cygserver_setpwd.h"
31 #include <cygwin/version.h>
34 set_imp_token (HANDLE token, int type)
36 debug_printf ("set_imp_token (%d, %d)", token, type);
37 cygheap->user.external_token = (token == INVALID_HANDLE_VALUE
38 ? NO_IMPERSONATION : token);
39 cygheap->user.ext_token_is_restricted = (type == CW_TOKEN_RESTRICTED);
43 cygwin_set_impersonation_token (const HANDLE hToken)
45 set_imp_token (hToken, CW_TOKEN_IMPERSONATION);
49 extract_nt_dom_user (const struct passwd *pw, PWCHAR domain, PWCHAR user)
53 DWORD ulen = UNLEN + 1;
54 DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
57 debug_printf ("pw_gecos %x (%s)", pw->pw_gecos, pw->pw_gecos);
59 if (psid.getfrompw (pw)
60 && LookupAccountSidW (NULL, psid, user, &ulen, domain, &dlen, &use))
65 sys_mbstowcs (user, UNLEN + 1, pw->pw_name);
66 if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
67 (d == pw->pw_gecos || d[-1] == ','))
69 c = strechr (d + 2, ',');
70 if ((u = strechr (d + 2, '\\')) >= c)
72 else if (u - d <= MAX_DOMAIN_NAME_LEN + 2)
73 sys_mbstowcs (domain, MAX_DOMAIN_NAME_LEN + 1, d + 2, u - d - 1);
74 if (c - u <= UNLEN + 1)
75 sys_mbstowcs (user, UNLEN + 1, u + 1, c - u);
80 cygwin_logon_user (const struct passwd *pw, const char *password)
85 return INVALID_HANDLE_VALUE;
88 WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1];
89 WCHAR nt_user[UNLEN + 1];
94 extract_nt_dom_user (pw, nt_domain, nt_user);
95 debug_printf ("LogonUserW (%W, %W, ...)", nt_user, nt_domain);
96 sys_mbstowcs (passwd = tp.w_get (), NT_MAX_PATH, password);
97 /* CV 2005-06-08: LogonUser should run under the primary process token,
98 otherwise it returns with ERROR_ACCESS_DENIED. */
99 cygheap->user.deimpersonate ();
100 if (!LogonUserW (nt_user, *nt_domain ? nt_domain : NULL, passwd,
101 LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
105 hToken = INVALID_HANDLE_VALUE;
107 else if (!SetHandleInformation (hToken,
109 HANDLE_FLAG_INHERIT))
112 CloseHandle (hToken);
113 hToken = INVALID_HANDLE_VALUE;
115 cygheap->user.reimpersonate ();
116 debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
121 str2lsa (LSA_STRING &tgt, const char *srcstr)
123 tgt.Length = strlen (srcstr);
124 tgt.MaximumLength = tgt.Length + 1;
125 tgt.Buffer = (PCHAR) srcstr;
129 str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
131 tgt.Length = strlen (srcstr);
132 tgt.MaximumLength = tgt.Length + 1;
133 tgt.Buffer = (PCHAR) buf;
134 memcpy (buf, srcstr, tgt.MaximumLength);
138 open_local_policy (ACCESS_MASK access)
140 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
141 HANDLE lsa = INVALID_HANDLE_VALUE;
143 NTSTATUS ret = LsaOpenPolicy (NULL, &oa, access, &lsa);
144 if (ret != STATUS_SUCCESS)
146 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
147 /* Some versions of Windows set the lsa handle to NULL when
148 LsaOpenPolicy fails. */
149 lsa = INVALID_HANDLE_VALUE;
155 close_local_policy (LSA_HANDLE &lsa)
157 if (lsa != INVALID_HANDLE_VALUE)
159 lsa = INVALID_HANDLE_VALUE;
163 get_logon_server (PWCHAR domain, WCHAR *server, bool rediscovery)
166 PDOMAIN_CONTROLLER_INFOW pci;
168 DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
170 /* Empty domain is interpreted as local system */
171 if ((GetComputerNameW (server + 2, &size)) &&
172 (!wcscasecmp (domain, server + 2) || !domain[0]))
174 server[0] = server[1] = L'\\';
178 /* Try to get any available domain controller for this domain */
179 dret = DsGetDcNameW (NULL, domain, NULL, NULL,
180 rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
181 if (dret == ERROR_SUCCESS)
183 wcscpy (server, pci->DomainControllerName);
184 NetApiBufferFree (pci);
185 debug_printf ("DC: rediscovery: %d, server: %W", rediscovery, server);
188 else if (dret == ERROR_PROC_NOT_FOUND)
190 /* NT4 w/o DSClient */
192 dret = NetGetAnyDCName (NULL, domain, (LPBYTE *) &buf);
194 dret = NetGetDCName (NULL, domain, (LPBYTE *) &buf);
195 if (dret == NERR_Success)
197 wcscpy (server, buf);
198 NetApiBufferFree (buf);
199 debug_printf ("NT: rediscovery: %d, server: %W", rediscovery, server);
203 __seterrno_from_win_error (dret);
208 get_user_groups (WCHAR *logonserver, cygsidlist &grp_list,
209 PWCHAR user, PWCHAR domain)
211 WCHAR dgroup[MAX_DOMAIN_NAME_LEN + GNLEN + 2];
212 LPGROUP_USERS_INFO_0 buf;
216 /* Look only on logonserver */
217 ret = NetUserGetGroups (logonserver, user, 0, (LPBYTE *) &buf,
218 MAX_PREFERRED_LENGTH, &cnt, &tot);
221 __seterrno_from_win_error (ret);
222 /* It's no error when the user name can't be found. */
223 return ret == NERR_UserNotFound;
226 len = wcslen (domain);
227 wcscpy (dgroup, domain);
228 dgroup[len++] = L'\\';
230 for (DWORD i = 0; i < cnt; ++i)
233 DWORD glen = MAX_SID_LEN;
234 WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
235 DWORD dlen = sizeof (dom);
236 SID_NAME_USE use = SidTypeInvalid;
238 wcscpy (dgroup + len, buf[i].grui0_name);
239 if (!LookupAccountNameW (NULL, dgroup, gsid, &glen, dom, &dlen, &use))
240 debug_printf ("LookupAccountName(%W), %E", dgroup);
241 else if (legal_sid_type (use))
244 debug_printf ("Global group %W invalid. Use: %d", dgroup, use);
247 NetApiBufferFree (buf);
252 get_user_local_groups (PWCHAR logonserver, PWCHAR domain,
253 cygsidlist &grp_list, PWCHAR user)
255 LPLOCALGROUP_INFO_0 buf;
259 ret = NetUserGetLocalGroups (logonserver, user, 0, LG_INCLUDE_INDIRECT,
260 (LPBYTE *) &buf, MAX_PREFERRED_LENGTH,
264 __seterrno_from_win_error (ret);
268 WCHAR domlocal_grp[MAX_DOMAIN_NAME_LEN + GNLEN + 2];
269 WCHAR builtin_grp[sizeof ("BUILTIN\\") + GNLEN + 2];
270 PWCHAR dg_ptr, bg_ptr;
273 dg_ptr = wcpcpy (domlocal_grp, domain);
275 bg_ptr = wcpcpy (builtin_grp, L"BUILTIN\\");
277 for (DWORD i = 0; i < cnt; ++i)
280 DWORD glen = MAX_SID_LEN;
281 WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
282 DWORD domlen = sizeof (dom);
284 use = SidTypeInvalid;
285 wcscpy (dg_ptr, buf[i].lgrpi0_name);
286 if (LookupAccountNameW (NULL, domlocal_grp, gsid, &glen,
289 if (!legal_sid_type (use))
290 debug_printf ("Rejecting local %W. use: %d", dg_ptr, use);
294 else if (GetLastError () == ERROR_NONE_MAPPED)
296 /* Check if it's a builtin group. */
297 wcscpy (bg_ptr, dg_ptr);
298 if (LookupAccountNameW (NULL, builtin_grp, gsid, &glen,
301 if (!legal_sid_type (use))
302 debug_printf ("Rejecting local %W. use: %d", dg_ptr, use);
307 debug_printf ("LookupAccountName(%W), %E", builtin_grp);
310 debug_printf ("LookupAccountName(%W), %E", domlocal_grp);
312 NetApiBufferFree (buf);
317 sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
321 for (DWORD i = 0; i < grps->GroupCount; ++i)
322 if (sid == grps->Groups[i].Sid)
328 get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
330 struct __group32 *gr;
333 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
335 if (gr->gr_gid == (__gid32_t) pw->pw_gid)
338 for (int gi = 0; gr->gr_mem[gi]; ++gi)
339 if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
343 if (gsid.getfromgr (gr))
350 get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
351 LUID auth_luid, int &auth_pos)
356 grp_list += well_known_local_sid;
357 if (sid_in_token_groups (my_grps, well_known_dialup_sid))
358 grp_list *= well_known_dialup_sid;
359 if (sid_in_token_groups (my_grps, well_known_network_sid))
360 grp_list *= well_known_network_sid;
361 if (sid_in_token_groups (my_grps, well_known_batch_sid))
362 grp_list *= well_known_batch_sid;
363 grp_list *= well_known_interactive_sid;
364 if (sid_in_token_groups (my_grps, well_known_service_sid))
365 grp_list *= well_known_service_sid;
366 if (sid_in_token_groups (my_grps, well_known_this_org_sid))
367 grp_list *= well_known_this_org_sid;
371 grp_list += well_known_local_sid;
372 grp_list *= well_known_interactive_sid;
374 if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
376 for (DWORD i = 0; i < my_grps->GroupCount; ++i)
377 if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
379 grp_list += my_grps->Groups[i].Sid;
380 auth_pos = grp_list.count () - 1;
387 get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
389 WCHAR user[UNLEN + 1];
390 WCHAR domain[MAX_DOMAIN_NAME_LEN + 1];
391 WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
392 DWORD ulen = UNLEN + 1;
393 DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
396 if (well_known_system_sid == usersid)
398 grp_list *= well_known_admins_sid;
399 get_unix_group_sidlist (pw, grp_list);
403 grp_list *= well_known_world_sid;
404 grp_list *= well_known_authenticated_users_sid;
406 if (!LookupAccountSidW (NULL, usersid, user, &ulen, domain, &dlen, &use))
411 if (get_logon_server (domain, server, false)
412 && !get_user_groups (server, grp_list, user, domain)
413 && get_logon_server (domain, server, true))
414 get_user_groups (server, grp_list, user, domain);
415 get_user_local_groups (server, domain, grp_list, user);
416 get_unix_group_sidlist (pw, grp_list);
421 get_initgroups_sidlist (cygsidlist &grp_list,
422 PSID usersid, PSID pgrpsid, struct passwd *pw,
423 PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
425 grp_list *= well_known_world_sid;
426 grp_list *= well_known_authenticated_users_sid;
427 if (well_known_system_sid == usersid)
430 get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
431 if (!get_server_groups (grp_list, usersid, pw))
434 /* special_pgrp true if pgrpsid is not in normal groups */
440 get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
441 PTOKEN_GROUPS my_grps, user_groups &groups,
442 LUID auth_luid, int &auth_pos)
444 tmp_list *= well_known_world_sid;
445 tmp_list *= well_known_authenticated_users_sid;
446 get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
447 get_server_groups (tmp_list, usersid, pw);
448 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
449 tmp_list += groups.sgsids.sids[gidx];
450 tmp_list += groups.pgsid;
453 static ULONG sys_privs[] = {
454 SE_CREATE_TOKEN_PRIVILEGE,
455 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
456 SE_LOCK_MEMORY_PRIVILEGE,
457 SE_INCREASE_QUOTA_PRIVILEGE,
459 SE_SECURITY_PRIVILEGE,
460 SE_TAKE_OWNERSHIP_PRIVILEGE,
461 SE_LOAD_DRIVER_PRIVILEGE,
462 SE_SYSTEM_PROFILE_PRIVILEGE, /* Vista ONLY */
463 SE_SYSTEMTIME_PRIVILEGE,
464 SE_PROF_SINGLE_PROCESS_PRIVILEGE,
465 SE_INC_BASE_PRIORITY_PRIVILEGE,
466 SE_CREATE_PAGEFILE_PRIVILEGE,
467 SE_CREATE_PERMANENT_PRIVILEGE,
469 SE_RESTORE_PRIVILEGE,
470 SE_SHUTDOWN_PRIVILEGE,
473 SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
474 SE_CHANGE_NOTIFY_PRIVILEGE,
476 SE_MANAGE_VOLUME_PRIVILEGE,
477 SE_IMPERSONATE_PRIVILEGE,
478 SE_CREATE_GLOBAL_PRIVILEGE,
479 SE_INCREASE_WORKING_SET_PRIVILEGE,
480 SE_TIME_ZONE_PRIVILEGE,
481 SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
484 #define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
486 static PTOKEN_PRIVILEGES
487 get_system_priv_list (size_t &size)
490 while (max_idx < SYSTEM_PRIVILEGES_COUNT
491 && sys_privs[max_idx] != wincap.max_sys_priv ())
493 if (max_idx >= SYSTEM_PRIVILEGES_COUNT)
494 api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs",
495 wincap.max_sys_priv ());
496 size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES);
497 PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
500 debug_printf ("malloc (system_privs) failed.");
503 privs->PrivilegeCount = 0;
504 for (ULONG i = 0; i <= max_idx; ++i)
506 privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L;
507 privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i];
508 privs->Privileges[privs->PrivilegeCount].Attributes =
509 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
510 ++privs->PrivilegeCount;
515 static PTOKEN_PRIVILEGES
516 get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
519 PLSA_UNICODE_STRING privstrs;
521 PTOKEN_PRIVILEGES privs = NULL;
524 if (usersid == well_known_system_sid)
525 return get_system_priv_list (size);
527 for (int grp = -1; grp < grp_list.count (); ++grp)
531 if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
532 &cnt)) != STATUS_SUCCESS)
535 else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
539 for (ULONG i = 0; i < cnt; ++i)
542 PTOKEN_PRIVILEGES tmp;
545 if (!privilege_luid (privstrs[i].Buffer, &priv))
550 DWORD pcnt = privs->PrivilegeCount;
551 LUID_AND_ATTRIBUTES *p = privs->Privileges;
552 for (; pcnt > 0; --pcnt, ++p)
553 if (priv.HighPart == p->Luid.HighPart
554 && priv.LowPart == p->Luid.LowPart)
555 goto next_account_right;
558 tmp_count = privs ? privs->PrivilegeCount : 0;
559 size = sizeof (DWORD)
560 + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
561 tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
566 LsaFreeMemory (privstrs);
567 debug_printf ("realloc (privs) failed.");
570 tmp->PrivilegeCount = tmp_count;
572 privs->Privileges[privs->PrivilegeCount].Luid = priv;
573 privs->Privileges[privs->PrivilegeCount].Attributes =
574 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
575 ++privs->PrivilegeCount;
580 LsaFreeMemory (privstrs);
586 - the requested usersid matches the TokenUser and
587 - if setgroups has been called:
588 the token groups that are listed in /etc/group match the union of
589 the requested primary and supplementary groups in gsids.
590 - else the (unknown) implicitly requested supplementary groups and those
591 in the token are the groups associated with the usersid. We assume
592 they match and verify only the primary groups.
593 The requested primary group must appear in the token.
594 The primary group in the token is a group associated with the usersid,
595 except if the token is internal and the group is in the token SD
596 (see create_token). In that latter case that group must match the
597 requested primary group. */
599 verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
607 if (!GetTokenInformation (token, TokenSource,
608 &ts, sizeof ts, &size))
609 debug_printf ("GetTokenInformation(), %E");
611 *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
614 cygsid tok_usersid = NO_SID;
615 if (!GetTokenInformation (token, TokenUser,
616 &tok_usersid, sizeof tok_usersid, &size))
617 debug_printf ("GetTokenInformation(), %E");
618 if (usersid != tok_usersid)
621 /* For an internal token, if setgroups was not called and if the sd group
622 is not well_known_null_sid, it must match pgrpsid */
623 if (intern && !groups.issetgroups ())
625 const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR);
626 PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
627 cygpsid gsid (NO_SID);
628 if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
629 sd_buf, sd_buf_siz, &size))
630 debug_printf ("GetKernelObjectSecurity(), %E");
631 else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid,
633 debug_printf ("GetSecurityDescriptorGroup(), %E");
634 if (well_known_null_sid != gsid)
635 return gsid == groups.pgsid;
638 PTOKEN_GROUPS my_grps;
639 bool sawpg = false, ret = false;
641 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
642 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
643 debug_printf ("GetTokenInformation(token, TokenGroups), %E");
644 else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
645 debug_printf ("alloca (my_grps) failed.");
646 else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
647 debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
650 if (groups.issetgroups ()) /* setgroups was called */
653 struct __group32 *gr;
654 bool saw[groups.sgsids.count ()];
655 memset (saw, 0, sizeof(saw));
657 /* token groups found in /etc/group match the user.gsids ? */
658 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
659 if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
661 int pos = groups.sgsids.position (gsid);
664 else if (groups.pgsid == gsid)
667 /* With this `else', verify_token returns false if we find
668 groups in the token, which are not in the group list set
669 with setgroups(). That's rather dangerous. What we're
670 really interested in is that all groups in the setgroups()
671 list are in the token. A token created through ADVAPI
672 should be allowed to contain more groups than requested
673 through setgroups(), esecially since Vista and the
674 addition of integrity groups. So we disable this statement
676 else if (gsid != well_known_world_sid
681 /* user.sgsids groups must be in the token, except for builtin groups.
682 These can be different on domain member machines compared to
683 domain controllers, so these builtin groups may be validly missing
684 from a token created through password or lsaauth logon. */
685 for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
687 && !groups.sgsids.sids[gidx].is_well_known_sid ()
688 && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
691 /* The primary group must be in the token */
693 || sid_in_token_groups (my_grps, groups.pgsid)
694 || groups.pgsid == usersid;
701 create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
704 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
706 cygsidlist tmp_gsids (cygsidlist_auto, 12);
708 SECURITY_QUALITY_OF_SERVICE sqos =
709 { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
710 OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
711 LUID auth_luid = SYSTEM_LUID;
712 LARGE_INTEGER exp = { QuadPart:INT64_MAX };
715 PTOKEN_GROUPS new_tok_gsids = NULL;
716 PTOKEN_PRIVILEGES privs = NULL;
718 TOKEN_PRIMARY_GROUP pgrp;
719 TOKEN_DEFAULT_DACL dacl = {};
721 TOKEN_STATISTICS stats;
722 memcpy (source.SourceName, "Cygwin.1", 8);
723 source.SourceIdentifier.HighPart = 0;
724 source.SourceIdentifier.LowPart = 0x0101;
726 HANDLE token = INVALID_HANDLE_VALUE;
727 HANDLE primary_token = INVALID_HANDLE_VALUE;
729 PTOKEN_GROUPS my_tok_gsids = NULL;
733 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
734 push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
736 /* Open policy object. */
737 if ((lsa = open_local_policy (POLICY_EXECUTE)) == INVALID_HANDLE_VALUE)
740 /* User, owner, primary group. */
741 user.User.Sid = usersid;
742 user.User.Attributes = 0;
743 owner.Owner = usersid;
745 /* Retrieve authentication id and group list from own process. */
748 /* Switching user context to SYSTEM doesn't inherit the authentication
749 id of the user account running current process. */
750 if (usersid == well_known_system_sid)
752 else if (!GetTokenInformation (hProcToken, TokenStatistics,
753 &stats, sizeof stats, &size))
755 ("GetTokenInformation(hProcToken, TokenStatistics), %E");
757 auth_luid = stats.AuthenticationId;
759 /* Retrieving current processes group list to be able to inherit
760 some important well known group sids. */
761 if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size)
762 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
763 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
764 else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
765 debug_printf ("malloc (my_tok_gsids) failed.");
766 else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
769 debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
775 /* Create list of groups, the user is member in. */
777 if (new_groups.issetgroups ())
778 get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
779 auth_luid, auth_pos);
780 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
781 my_tok_gsids, auth_luid, auth_pos))
785 pgrp.PrimaryGroup = new_groups.pgsid;
787 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
788 new_tok_gsids = (PTOKEN_GROUPS)
789 alloca (sizeof (DWORD) + (tmp_gsids.count () + 1)
790 * sizeof (SID_AND_ATTRIBUTES));
791 new_tok_gsids->GroupCount = tmp_gsids.count ();
792 for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
794 new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
795 new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
796 | SE_GROUP_ENABLED_BY_DEFAULT
800 new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
802 /* On systems supporting Mandatory Integrity Control, add a MIC SID. */
803 if (wincap.has_mandatory_integrity_control ())
805 new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes =
806 SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
807 if (usersid == well_known_system_sid)
808 new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
809 = mandatory_system_integrity_sid;
810 else if (tmp_gsids.contains (well_known_admins_sid))
811 new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
812 = mandatory_high_integrity_sid;
814 new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
815 = mandatory_medium_integrity_sid;
818 /* Retrieve list of privileges of that user. */
819 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
822 /* Let's be heroic... */
823 ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
824 &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
825 &pgrp, &dacl, &source);
827 __seterrno_from_nt_status (ret);
830 /* Convert to primary token. */
831 if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
832 SecurityImpersonation, TokenPrimary,
836 debug_printf ("DuplicateTokenEx %E");
841 pop_self_privilege ();
842 if (token != INVALID_HANDLE_VALUE)
848 close_local_policy (lsa);
850 debug_printf ("%p = create_token ()", primary_token);
851 return primary_token;
855 lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
857 cygsidlist tmp_gsids (cygsidlist_auto, 12);
860 HANDLE lsa_hdl = NULL, lsa = INVALID_HANDLE_VALUE;
861 LSA_OPERATIONAL_MODE sec_mode;
863 ULONG package_id, size;
864 LUID auth_luid = SYSTEM_LUID;
869 DWORD ulen = UNLEN + 1;
870 DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
872 cyglsa_t *authinf = NULL;
875 PCYG_TOKEN_GROUPS gsids = NULL;
876 PTOKEN_PRIVILEGES privs = NULL;
878 PVOID profile = NULL;
881 size_t psize = 0, gsize = 0, dsize = 0;
882 OFFSET offset, sids_offset;
883 int tmpidx, non_well_known_cnt;
885 HANDLE user_token = NULL;
887 push_self_privilege (SE_TCB_PRIVILEGE, true);
889 /* Register as logon process. */
890 str2lsa (name, "Cygwin");
892 ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
893 if (ret != STATUS_SUCCESS)
895 debug_printf ("LsaRegisterLogonProcess: %p", ret);
896 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
899 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
901 debug_printf ("Couldn't load Secur32.dll");
904 /* Get handle to our own LSA package. */
905 str2lsa (name, CYG_LSA_PKGNAME);
906 ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
907 if (ret != STATUS_SUCCESS)
909 debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
910 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
914 /* Open policy object. */
915 if ((lsa = open_local_policy (POLICY_EXECUTE)) == INVALID_HANDLE_VALUE)
919 str2buf2lsa (origin.str, origin.buf, "Cygwin");
920 /* Create token source. */
921 memcpy (ts.SourceName, "Cygwin.1", 8);
922 ts.SourceIdentifier.HighPart = 0;
923 ts.SourceIdentifier.LowPart = 0x0103;
925 /* Create list of groups, the user is member in. */
927 if (new_groups.issetgroups ())
928 get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
930 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
931 NULL, auth_luid, auth_pos))
933 /* The logon SID entry is not generated automatically on Windows 2000
934 and earlier for some reason. So add fake logon sid here, which is
935 filled with logon id values in the authentication package. */
936 if (wincap.needs_logon_sid_in_sid_list ())
937 tmp_gsids += fake_logon_sid;
939 tmp_gsids.debug_print ("tmp_gsids");
941 /* Evaluate size of TOKEN_GROUPS list */
942 non_well_known_cnt = tmp_gsids.non_well_known_count ();
943 gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
945 for (int i = 0; i < non_well_known_cnt; ++i)
946 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
947 gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
949 /* Retrieve list of privileges of that user. */
950 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
953 /* Create DefaultDacl. */
954 dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
955 + GetLengthSid (usersid)
956 + GetLengthSid (well_known_admins_sid)
957 + GetLengthSid (well_known_system_sid);
958 dacl = (PACL) alloca (dsize);
959 if (!InitializeAcl (dacl, dsize, ACL_REVISION))
961 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
963 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
964 well_known_admins_sid))
966 if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
967 well_known_system_sid))
970 /* Evaluate authinf size and allocate authinf. */
971 authinf_size = (authinf->data - (PBYTE) authinf);
972 authinf_size += GetLengthSid (usersid); /* User SID */
973 authinf_size += gsize; /* Groups + Group SIDs */
974 /* When trying to define the admins group as primary group on Vista,
975 LsaLogonUser fails with error STATUS_INVALID_OWNER. As workaround
976 we define "Local" as primary group here. Seteuid32 sets the primary
977 group to the group set in /etc/passwd anyway. */
978 if (new_groups.pgsid == well_known_admins_sid)
979 pgrpsid = well_known_local_sid;
981 pgrpsid = new_groups.pgsid;
983 authinf_size += GetLengthSid (pgrpsid); /* Primary Group SID */
985 authinf_size += psize; /* Privileges */
986 authinf_size += 0; /* Owner SID */
987 authinf_size += dsize; /* Default DACL */
989 authinf = (cyglsa_t *) alloca (authinf_size);
990 authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
992 authinf->magic = CYG_LSA_MAGIC;
994 if (!LookupAccountSidW (NULL, usersid, authinf->username, &ulen,
995 authinf->domain, &dlen, &use))
1001 /* Store stuff in authinf with offset relative to start of "inf" member,
1002 instead of using pointers. */
1003 offset = authinf->data - (PBYTE) &authinf->inf;
1005 authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
1006 authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
1008 authinf->inf.User.User.Sid = offset;
1009 authinf->inf.User.User.Attributes = 0;
1010 CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
1012 offset += GetLengthSid (usersid);
1014 authinf->inf.Groups = offset;
1015 gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
1016 sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
1017 * sizeof (SID_AND_ATTRIBUTES);
1018 gsids->GroupCount = non_well_known_cnt;
1021 for (int i = 0; i < non_well_known_cnt; ++i)
1023 if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
1025 gsids->Groups[i].Sid = sids_offset;
1026 gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
1027 | SE_GROUP_ENABLED_BY_DEFAULT
1029 /* Mark logon SID as logon SID :) */
1030 if (wincap.needs_logon_sid_in_sid_list ()
1031 && tmp_gsids.sids[tmpidx] == fake_logon_sid)
1032 gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
1033 CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
1034 (PSID) ((PBYTE) &authinf->inf + sids_offset),
1035 tmp_gsids.sids[tmpidx]);
1036 sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
1039 /* Primary Group SID */
1040 authinf->inf.PrimaryGroup.PrimaryGroup = offset;
1041 CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
1043 offset += GetLengthSid (pgrpsid);
1045 authinf->inf.Privileges = offset;
1046 memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
1049 authinf->inf.Owner.Owner = 0;
1051 authinf->inf.DefaultDacl.DefaultDacl = offset;
1052 memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
1054 authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
1055 CYGWIN_VERSION_DLL_MINOR);
1058 csp = (PDWORD) &authinf->username;
1059 csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
1060 while (csp < csp_end)
1061 authinf->checksum += *csp++;
1063 /* Try to logon... */
1064 ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
1065 authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
1066 &user_token, "a, &ret2);
1067 if (ret != STATUS_SUCCESS)
1069 debug_printf ("LsaLogonUser: %p", ret);
1070 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1075 #ifdef JUST_ANOTHER_NONWORKING_SOLUTION
1076 /* See ../lsaauth/cyglsa.c. */
1077 cygprf_t *prf = (cygprf_t *) profile;
1078 if (prf->magic_pre == MAGIC_PRE && prf->magic_post == MAGIC_POST
1081 CloseHandle (user_token);
1082 user_token = prf->token;
1083 system_printf ("Got token through profile: %p", user_token);
1085 #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */
1086 LsaFreeReturnBuffer (profile);
1089 if (wincap.has_mandatory_integrity_control ())
1091 TOKEN_LINKED_TOKEN linked;
1093 if (GetTokenInformation (user_token, TokenLinkedToken,
1094 (PVOID) &linked, sizeof linked, &size))
1096 debug_printf ("Linked Token: %p", linked.LinkedToken);
1097 if (linked.LinkedToken)
1099 CloseHandle (user_token);
1100 user_token = linked.LinkedToken;
1105 /* The token returned by LsaLogonUser is not inheritable. Make it so. */
1106 if (!SetHandleInformation (user_token, HANDLE_FLAG_INHERIT,
1107 HANDLE_FLAG_INHERIT))
1108 system_printf ("SetHandleInformation %E");
1113 close_local_policy (lsa);
1115 LsaDeregisterLogonProcess (lsa_hdl);
1116 pop_self_privilege ();
1118 debug_printf ("%p = lsaauth ()", user_token);
1122 #define SFU_LSA_KEY_SUFFIX L"_microsoft_sfu_utility"
1125 lsaprivkeyauth (struct passwd *pw)
1128 HANDLE lsa = INVALID_HANDLE_VALUE;
1129 HANDLE token = NULL;
1131 WCHAR domain[MAX_DOMAIN_NAME_LEN + 1];
1132 WCHAR user[UNLEN + 1];
1133 WCHAR key_name[MAX_DOMAIN_NAME_LEN + UNLEN + wcslen (SFU_LSA_KEY_SUFFIX) + 2];
1135 PUNICODE_STRING data;
1138 push_self_privilege (SE_TCB_PRIVILEGE, true);
1140 /* Open policy object. */
1141 if ((lsa = open_local_policy (POLICY_GET_PRIVATE_INFORMATION))
1142 == INVALID_HANDLE_VALUE)
1145 /* Needed for Interix key and LogonUser. */
1146 extract_nt_dom_user (pw, domain, user);
1148 /* First test for a Cygwin entry. */
1149 if (psid.getfrompw (pw) && psid.string (sid))
1151 wcpcpy (wcpcpy (key_name, CYGWIN_LSA_KEY_PREFIX), sid);
1152 RtlInitUnicodeString (&key, key_name);
1153 status = LsaRetrievePrivateData (lsa, &key, &data);
1154 if (!NT_SUCCESS (status))
1156 /* No Cygwin key, try Interix key. */
1159 __small_swprintf (key_name, L"%W_%W%W",
1160 domain, user, SFU_LSA_KEY_SUFFIX);
1161 RtlInitUnicodeString (&key, key_name);
1162 status = LsaRetrievePrivateData (lsa, &key, &data);
1163 if (!NT_SUCCESS (status))
1168 /* The key is not 0-terminated. */
1170 passwd = (PWCHAR) alloca (data->Length + sizeof (WCHAR));
1171 *wcpncpy (passwd, data->Buffer, data->Length / sizeof (WCHAR)) = L'\0';
1172 LsaFreeMemory (data);
1173 debug_printf ("Try logon for %W\\%W", domain, user);
1174 if (!LogonUserW (user, domain, passwd, LOGON32_LOGON_INTERACTIVE,
1175 LOGON32_PROVIDER_DEFAULT, &token))
1182 if (wincap.has_mandatory_integrity_control ())
1184 TOKEN_LINKED_TOKEN linked;
1187 if (GetTokenInformation (token, TokenLinkedToken,
1188 (PVOID) &linked, sizeof linked, &size))
1190 debug_printf ("Linked Token: %p", linked.LinkedToken);
1191 if (linked.LinkedToken)
1193 CloseHandle (token);
1194 token = linked.LinkedToken;
1198 if (!SetHandleInformation (token, HANDLE_FLAG_INHERIT,
1199 HANDLE_FLAG_INHERIT))
1202 CloseHandle (token);
1208 close_local_policy (lsa);
1209 pop_self_privilege ();