1 /* cyglsa.c: LSA authentication module for Cygwin
3 Copyright 2006, 2008 Red Hat, Inc.
5 Written by Corinna Vinschen <corinna@vinschen.de>
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */
13 #define _CRT_SECURE_NO_DEPRECATE
15 #define WIN32_NO_STATUS
25 #include "../cygwin/cyglsa.h"
26 #include "../cygwin/include/cygwin/version.h"
28 static PLSA_SECPKG_FUNCS funcs;
29 static BOOL must_create_logon_sid;
32 DllMain (HINSTANCE inst, DWORD reason, LPVOID res)
36 case DLL_PROCESS_ATTACH:
37 case DLL_THREAD_ATTACH:
38 case DLL_THREAD_DETACH:
39 case DLL_PROCESS_DETACH:
45 #ifndef RtlInitEmptyUnicodeString
47 RtlInitEmptyUnicodeString(PUNICODE_STRING dest, PCWSTR buf, USHORT len)
50 dest->MaximumLength = len;
51 dest->Buffer = (PWSTR) buf;
55 static PUNICODE_STRING
56 uni_alloc (PWCHAR src, USHORT len)
60 if (!(tgt = funcs->AllocateLsaHeap (sizeof (UNICODE_STRING))))
62 tgt->Length = len * sizeof (WCHAR);
63 tgt->MaximumLength = tgt->Length + sizeof (WCHAR);
64 if (!(tgt->Buffer = funcs->AllocateLsaHeap (tgt->MaximumLength)))
66 funcs->FreeLsaHeap (tgt);
69 wcscpy (tgt->Buffer, src);
73 /* No, I don't want to include stdio.h so I take what ntdll offers. */
74 extern int _vsnprintf (char *, size_t, const char *, va_list);
76 static HANDLE fh = INVALID_HANDLE_VALUE;
79 printf (const char *format, ...)
86 if (fh == INVALID_HANDLE_VALUE)
89 va_start (ap, format);
90 ret = _vsnprintf (buf, 256, format, ap);
97 WriteFile (fh, buf, ret, &wr, NULL);
102 print_sid (const char *prefix, int idx, PISID sid)
106 printf ("%s", prefix);
108 printf ("[%d] ", idx);
109 printf ("(0x%08x) ", (INT_PTR) sid);
112 else if (IsBadReadPtr (sid, 8))
113 printf ("INVALID POINTER\n");
114 else if (!IsValidSid ((PSID) sid))
115 printf ("INVALID SID\n");
116 else if (IsBadReadPtr (sid, 8 + sizeof (DWORD) * sid->SubAuthorityCount))
117 printf ("INVALID POINTER SPACE\n");
120 printf ("S-%d-%d", sid->Revision, sid->IdentifierAuthority.Value[5]);
121 for (i = 0; i < sid->SubAuthorityCount; ++i)
122 printf ("-%lu", sid->SubAuthority[i]);
128 print_groups (PTOKEN_GROUPS grps)
132 printf ("Groups: (0x%08x) ", (INT_PTR) grps);
135 else if (IsBadReadPtr (grps, sizeof (DWORD)))
136 printf ("INVALID POINTER\n");
137 else if (IsBadReadPtr (grps, sizeof (DWORD) + sizeof (SID_AND_ATTRIBUTES)
139 printf ("INVALID POINTER SPACE\n");
142 printf ("Count: %lu\n", grps->GroupCount);
143 for (i = 0; i < grps->GroupCount; ++i)
145 printf ("(attr: 0x%lx)", grps->Groups[i].Attributes);
146 print_sid (" ", i, (PISID) grps->Groups[i].Sid);
152 print_privs (PTOKEN_PRIVILEGES privs)
156 printf ("Privileges: (0x%08x) ", (INT_PTR) privs);
159 else if (IsBadReadPtr (privs, sizeof (DWORD)))
160 printf ("INVALID POINTER\n");
161 else if (IsBadReadPtr (privs, sizeof (DWORD) + sizeof (LUID_AND_ATTRIBUTES)
162 * privs->PrivilegeCount))
163 printf ("INVALID POINTER SPACE\n");
166 printf ("Count: %lu\n", privs->PrivilegeCount);
167 for (i = 0; i < privs->PrivilegeCount; ++i)
168 printf ("Luid: {%ld, %lu} Attributes: 0x%lx\n",
169 privs->Privileges[i].Luid.HighPart,
170 privs->Privileges[i].Luid.LowPart,
171 privs->Privileges[i].Attributes);
176 print_dacl (PACL dacl)
180 printf ("DefaultDacl: (0x%08x) ", (INT_PTR) dacl);
183 else if (IsBadReadPtr (dacl, sizeof (ACL)))
184 printf ("INVALID POINTER\n");
185 else if (IsBadReadPtr (dacl, dacl->AclSize))
186 printf ("INVALID POINTER SPACE\n");
189 printf ("Rev: %d, Count: %d\n", dacl->AclRevision, dacl->AceCount);
190 for (i = 0; i < dacl->AceCount; ++i)
193 PACCESS_ALLOWED_ACE ace;
195 if (!GetAce (dacl, i, &vace))
196 printf ("[%lu] GetAce error %lu\n", i, GetLastError ());
199 ace = (PACCESS_ALLOWED_ACE) vace;
200 printf ("Type: %x, Flags: %x, Access: %lx,",
201 ace->Header.AceType, ace->Header.AceFlags, (DWORD) ace->Mask);
202 print_sid (" ", i, (PISID) &ace->SidStart);
209 print_tokinf (PLSA_TOKEN_INFORMATION_V2 ptok, size_t size,
210 PVOID got_start, PVOID gotinf_start, PVOID gotinf_end)
212 if (fh == INVALID_HANDLE_VALUE)
215 printf ("INCOMING: start: 0x%08x infstart: 0x%08x infend: 0x%08x\n",
216 (INT_PTR) got_start, (INT_PTR) gotinf_start,
217 (INT_PTR) gotinf_end);
219 printf ("LSA_TOKEN_INFORMATION_V2: 0x%08x - 0x%08x\n",
220 (INT_PTR) ptok, (INT_PTR) ptok + size);
223 printf ("User: (attr: 0x%lx)", ptok->User.User.Attributes);
224 print_sid (" ", -1, (PISID) ptok->User.User.Sid);
227 print_groups (ptok->Groups);
229 /* Primary Group SID */
230 print_sid ("Primary Group: ", -1, (PISID)ptok->PrimaryGroup.PrimaryGroup);
233 print_privs (ptok->Privileges);
236 print_sid ("Owner: ", -1, (PISID) ptok->Owner.Owner);
239 print_dacl (ptok->DefaultDacl.DefaultDacl);
245 LsaApInitializePackage (ULONG authp_id, PLSA_SECPKG_FUNCS dpt,
246 PLSA_STRING dummy1, PLSA_STRING dummy2,
247 PLSA_STRING *authp_name)
249 PLSA_STRING name = NULL;
250 DWORD vers, major, minor;
252 /* Set global pointer to lsa helper function table. */
255 /* Allocate and set the name of the authentication package. This is the
256 name which has to be used in LsaLookupAuthenticationPackage. */
257 if (!(name = funcs->AllocateLsaHeap (sizeof *name)))
258 return STATUS_NO_MEMORY;
259 if (!(name->Buffer = funcs->AllocateLsaHeap (sizeof (CYG_LSA_PKGNAME))))
261 funcs->FreeLsaHeap (name);
262 return STATUS_NO_MEMORY;
264 name->Length = sizeof (CYG_LSA_PKGNAME) - 1;
265 name->MaximumLength = sizeof (CYG_LSA_PKGNAME);
266 strcpy (name->Buffer, CYG_LSA_PKGNAME);
267 (*authp_name) = name;
269 vers = GetVersion ();
270 major = LOBYTE (LOWORD (vers));
271 minor = HIBYTE (LOWORD (vers));
272 /* Check if we're running on Windows 2000 or lower. If so, we must create
273 the logon sid in the group list by ourselves. */
274 if (major < 5 || (major == 5 && minor == 0))
275 must_create_logon_sid = TRUE;
278 fh = CreateFile ("C:\\cyglsa.dbgout", GENERIC_WRITE,
279 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
280 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
281 printf ("Initialized\n");
282 #endif /* DEBUGGING */
284 return STATUS_SUCCESS;
288 LsaApLogonUserEx (PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logon_type,
289 PVOID auth, PVOID client_auth_base, ULONG auth_len,
290 PVOID *pbuf, PULONG pbuf_len, PLUID logon_id,
291 PNTSTATUS sub_stat, PLSA_TOKEN_INFORMATION_TYPE tok_type,
292 PVOID *tok, PUNICODE_STRING *account,
293 PUNICODE_STRING *authority, PUNICODE_STRING *machine)
298 SECPKG_CLIENT_INFO clinf;
299 PLSA_TOKEN_INFORMATION_V2 tokinf;
301 cyglsa_t *authinf = (cyglsa_t *) auth;
303 /* Check if the caller has the SeTcbPrivilege, otherwise refuse service. */
304 stat = funcs->GetClientInfo (&clinf);
305 if (stat != STATUS_SUCCESS)
307 printf ("GetClientInfo failed: 0x%08lx\n", stat);
310 if (!clinf.HasTcbPrivilege)
312 printf ("Client has no TCB privilege. Access denied.\n");
313 return STATUS_ACCESS_DENIED;
316 /* Make a couple of validity checks. */
317 if (auth_len < sizeof *authinf
318 || authinf->magic != CYG_LSA_MAGIC
319 || !authinf->username[0]
320 || !authinf->domain[0])
322 printf ("Invalid authentication parameter.\n");
323 return STATUS_INVALID_PARAMETER;
325 checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
326 CYGWIN_VERSION_DLL_MINOR);
327 csp = (PDWORD) &authinf->username;
328 csp_end = (PDWORD) ((PBYTE) authinf + auth_len);
329 while (csp < csp_end)
331 if (authinf->checksum != checksum)
333 printf ("Invalid checksum.\n");
334 return STATUS_INVALID_PARAMETER_3;
337 /* Set account to username and authority to domain resp. machine name.
338 The name of the logon account name as returned by LookupAccountSid
339 is created from here as "authority\account". */
340 authinf->username[UNLEN] = '\0';
341 authinf->domain[MAX_DOMAIN_NAME_LEN] = '\0';
342 if (account && !(*account = uni_alloc (authinf->username,
343 wcslen (authinf->username))))
345 printf ("No memory trying to create account.\n");
346 return STATUS_NO_MEMORY;
348 if (authority && !(*authority = uni_alloc (authinf->domain,
349 wcslen (authinf->domain))))
351 printf ("No memory trying to create authority.\n");
352 return STATUS_NO_MEMORY;
356 WCHAR mach[MAX_COMPUTERNAME_LENGTH + 1];
357 DWORD msize = MAX_COMPUTERNAME_LENGTH + 1;
358 if (!GetComputerNameW (mach, &msize))
359 wcscpy (mach, L"UNKNOWN");
360 if (!(*machine = uni_alloc (mach, wcslen (mach))))
362 printf ("No memory trying to create machine.\n");
363 return STATUS_NO_MEMORY;
366 /* Create a fake buffer in pbuf which is free'd again in the client.
367 Windows 2000 tends to crash when setting this pointer to NULL. */
370 #ifdef JUST_ANOTHER_NONWORKING_SOLUTION
372 WCHAR sam_username[MAX_DOMAIN_NAME_LEN + UNLEN + 2];
373 SECURITY_STRING sam_user, prefix;
375 ULONG user_auth_size;
376 WCHAR flatname[UNLEN + 1];
377 UNICODE_STRING flatnm;
380 #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */
382 stat = funcs->AllocateClientBuffer (request, 64UL, pbuf);
383 if (!LSA_SUCCESS (stat))
385 printf ("AllocateClientBuffer failed: 0x%08lx\n", stat);
388 #ifdef JUST_ANOTHER_NONWORKING_SOLUTION
389 prf.magic_pre = MAGIC_PRE;
391 prf.magic_post = MAGIC_POST;
394 /* That's how it was supposed to work according to MSDN... */
395 wcscpy (sam_username, authinf->domain);
396 wcscat (sam_username, L"\\");
397 wcscat (sam_username, authinf->username);
399 /* That's the only solution which worked, and then it only worked
400 for machine local accounts. No domain authentication possible.
401 STATUS_NO_SUCH_USER galore! */
402 wcscpy (sam_username, authinf->username);
404 RtlInitUnicodeString (&sam_user, sam_username);
405 RtlInitUnicodeString (&prefix, L"");
406 RtlInitEmptyUnicodeString (&flatnm, flatname,
407 (UNLEN + 1) * sizeof (WCHAR));
409 stat = funcs->GetAuthDataForUser (&sam_user, SecNameSamCompatible,
411 &user_auth_size, &flatnm);
412 if (!NT_SUCCESS (stat))
414 char sam_u[MAX_DOMAIN_NAME_LEN + UNLEN + 2];
415 wcstombs (sam_u, sam_user.Buffer, sizeof (sam_u));
416 printf ("GetAuthDataForUser (%u,%u,%s) failed: 0x%08lx\n",
417 sam_user.Length, sam_user.MaximumLength, sam_u, stat);
421 memcpy (ts.SourceName, "Cygwin.1", 8);
422 ts.SourceIdentifier.HighPart = 0;
423 ts.SourceIdentifier.LowPart = 0x0104;
424 RtlInitEmptyUnicodeString (&flatnm, flatname,
425 (UNLEN + 1) * sizeof (WCHAR));
426 stat = funcs->ConvertAuthDataToToken (user_auth, user_auth_size,
427 SecurityDelegation, &ts,
428 Interactive, *authority,
429 &token, logon_id, &flatnm,
431 if (!NT_SUCCESS (stat))
433 printf ("ConvertAuthDataToToken failed: 0x%08lx\n", stat);
437 stat = funcs->DuplicateHandle (token, &prf.token);
438 if (!NT_SUCCESS (stat))
440 printf ("DuplicateHandle failed: 0x%08lx\n", stat);
444 stat = funcs->CopyToClientBuffer (request, sizeof prf, *pbuf, &prf);
445 if (!NT_SUCCESS (stat))
447 printf ("CopyToClientBuffer failed: 0x%08lx\n", stat);
450 funcs->FreeLsaHeap (user_auth);
451 #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */
456 /* A PLSA_TOKEN_INFORMATION_V2 is allocated in one piece, so... */
457 #if defined (__x86_64__) || defined (_M_AMD64)
459 /* ...on 64 bit systems we have to convert the incoming 32 bit offsets
460 into 64 bit pointers. That requires to re-evaluate the size of the
461 outgoing tokinf structure and a somewhat awkward procedure to copy
462 the information over. */
467 PCYG_TOKEN_GROUPS src_grps;
469 PTOKEN_PRIVILEGES src_privs;
472 base = (LONG_PTR) &authinf->inf;
474 newsize = authinf->inf_size;
475 newsize += sizeof (TOKEN_USER) - sizeof (CYG_TOKEN_USER); /* User SID */
476 newsize += sizeof (PTOKEN_GROUPS) - sizeof (OFFSET); /* Groups */
477 src_grps = (PCYG_TOKEN_GROUPS) (base + authinf->inf.Groups);
478 newsize += src_grps->GroupCount /* Group SIDs */
479 * (sizeof (SID_AND_ATTRIBUTES)
480 - sizeof (CYG_SID_AND_ATTRIBUTES));
481 newsize += sizeof (PSID) - sizeof (OFFSET); /* Primary Group SID */
482 newsize += sizeof (PTOKEN_PRIVILEGES) - sizeof (OFFSET); /* Privileges */
483 newsize += 0; /* Owner SID */
484 newsize += sizeof (PACL) - sizeof (OFFSET); /* Default DACL */
486 if (!(tokinf = funcs->AllocateLsaHeap (newsize)))
487 return STATUS_NO_MEMORY;
488 tptr = (PBYTE)(tokinf + 1);
490 tokinf->ExpirationTime = authinf->inf.ExpirationTime;
492 src_sid = (PSID) (base + authinf->inf.User.User.Sid);
493 size = GetLengthSid (src_sid);
494 CopySid (size, (PSID) tptr, src_sid);
495 tokinf->User.User.Sid = (PSID) tptr;
497 tokinf->User.User.Attributes = authinf->inf.User.User.Attributes;
499 grps = (PTOKEN_GROUPS) tptr;
500 tokinf->Groups = grps;
501 grps->GroupCount = src_grps->GroupCount;
502 tptr += sizeof grps->GroupCount
503 + grps->GroupCount * sizeof (SID_AND_ATTRIBUTES);
505 for (i = 0; i < src_grps->GroupCount; ++i)
507 src_sid = (PSID) (base + src_grps->Groups[i].Sid);
508 size = GetLengthSid (src_sid);
509 CopySid (size, (PSID) tptr, src_sid);
510 tokinf->Groups->Groups[i].Sid = (PSID) tptr;
512 tokinf->Groups->Groups[i].Attributes = src_grps->Groups[i].Attributes;
514 /* Primary Group SID */
515 src_sid = (PSID) (base + authinf->inf.PrimaryGroup.PrimaryGroup);
516 size = GetLengthSid (src_sid);
517 CopySid (size, (PSID) tptr, src_sid);
518 tokinf->PrimaryGroup.PrimaryGroup = (PSID) tptr;
521 src_privs = (PTOKEN_PRIVILEGES) (base + authinf->inf.Privileges);
522 size = sizeof src_privs->PrivilegeCount
523 + src_privs->PrivilegeCount * sizeof (LUID_AND_ATTRIBUTES);
524 memcpy (tptr, src_privs, size);
525 tokinf->Privileges = (PTOKEN_PRIVILEGES) tptr;
528 tokinf->Owner.Owner = NULL;
530 src_acl = (PACL) (base + authinf->inf.DefaultDacl.DefaultDacl);
531 size = src_acl->AclSize;
532 memcpy (tptr, src_acl, size);
533 tokinf->DefaultDacl.DefaultDacl = (PACL) tptr;
537 /* ...on 32 bit systems we just allocate tokinf with the same size as
538 we get, copy the whole structure and convert offsets into pointers. */
540 /* Allocate LUID for usage in the logon SID on Windows 2000. This is
541 not done in the 64 bit code above for hopefully obvious reasons... */
544 if (must_create_logon_sid && !AllocateLocallyUniqueId (&logon_sid_id))
545 return STATUS_INSUFFICIENT_RESOURCES;
547 if (!(tokinf = funcs->AllocateLsaHeap (authinf->inf_size)))
548 return STATUS_NO_MEMORY;
549 memcpy (tokinf, &authinf->inf, authinf->inf_size);
552 tokinf->User.User.Sid = (PSID)
553 ((PBYTE) tokinf + (LONG_PTR) tokinf->User.User.Sid);
555 tokinf->Groups = (PTOKEN_GROUPS)
556 ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups);
558 for (i = 0; i < tokinf->Groups->GroupCount; ++i)
560 tokinf->Groups->Groups[i].Sid = (PSID)
561 ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups->Groups[i].Sid);
562 if (must_create_logon_sid
563 && tokinf->Groups->Groups[i].Attributes & SE_GROUP_LOGON_ID
564 && *GetSidSubAuthorityCount (tokinf->Groups->Groups[i].Sid) == 3
565 && *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 0)
566 == SECURITY_LOGON_IDS_RID)
568 *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 1)
569 = logon_sid_id.HighPart;
570 *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 2)
571 = logon_sid_id.LowPart;
575 /* Primary Group SID */
576 tokinf->PrimaryGroup.PrimaryGroup = (PSID)
577 ((PBYTE) tokinf + (LONG_PTR) tokinf->PrimaryGroup.PrimaryGroup);
579 tokinf->Privileges = (PTOKEN_PRIVILEGES)
580 ((PBYTE) tokinf + (LONG_PTR) tokinf->Privileges);
582 tokinf->Owner.Owner = NULL;
584 tokinf->DefaultDacl.DefaultDacl = (PACL)
585 ((PBYTE) tokinf + (LONG_PTR) tokinf->DefaultDacl.DefaultDacl);
590 *tok = (PVOID) tokinf;
591 *tok_type = LsaTokenInformationV2;
593 print_tokinf (tokinf, authinf->inf_size, authinf, &authinf->inf,
594 (PVOID)((LONG_PTR) &authinf->inf + authinf->inf_size));
596 /* Create logon session. */
597 if (!AllocateLocallyUniqueId (logon_id))
599 funcs->FreeLsaHeap (*tok);
601 printf ("AllocateLocallyUniqueId failed: Win32 error %lu\n",
603 return STATUS_INSUFFICIENT_RESOURCES;
605 stat = funcs->CreateLogonSession (logon_id);
606 if (stat != STATUS_SUCCESS)
608 funcs->FreeLsaHeap (*tok);
610 printf ("CreateLogonSession failed: 0x%08lx\n", stat);
614 printf ("BINGO!!!\n", stat);
615 return STATUS_SUCCESS;
619 LsaApLogonTerminated(PLUID LogonId)
624 LsaApCallPackage (PLSA_CLIENT_REQUEST request, PVOID authinf,
625 PVOID client_auth_base, ULONG auth_len, PVOID *ret_buf,
626 PULONG ret_buf_len, PNTSTATUS ret_stat)
628 return STATUS_NOT_IMPLEMENTED;