static uint64_t generateLuid() { LUID luid; if (AllocateLocallyUniqueId(&luid)) { uint64_t id = luid.HighPart; return id << 32 | luid.LowPart; } throw std::system_error( GetLastError(), Win32ErrorCategory::get(), "Failed to generate the luid"); }
/** * Creates MidpSession for the specified XRPC client id. Invoked on the XRPC * thread under synchronization. */ STATIC MidpSession* GWENG_MidpCreateSession(EcmtGateway* gw, int xrpcSid) { MidpSession* ses = MEM_New(MidpSession); if (ses) { LUID luid; /* Just in case if AllocateLocallyUniqueId fails... */ luid.LowPart = (DWORD)ses; AllocateLocallyUniqueId(&luid); memset(ses, 0, sizeof(*ses)); ses->key.xrpcSid = xrpcSid; ses->key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); ses->sid = luid.LowPart; ASSERT(!HASH_Contains(&gw->ecmtSessionMap,(HashKey)ses->sid)); ASSERT(!HASH_Contains(&gw->midpSessionMap,&ses->key)); if (HASH_Init(&ses->connMap, 1, NULL, NULL, hashFreeValueProc)) { /* Create context for the control connection (number zero) */ MidpConnection* conn = MEM_New(MidpConnection); if (conn) { memset(conn, 0, sizeof(*conn)); if (HASH_Put(&ses->connMap, (HashKey)0, conn)) { if (HASH_Put(&gw->ecmtSessionMap,(HashKey)ses->sid,ses)) { if (HASH_Put(&gw->midpSessionMap, &ses->key, ses)) { if (MUTEX_Init(&ses->xrpcMutex)) { ses->xrpcWorkThread = WKQ_Create(); if (ses->xrpcWorkThread) { ses->xrpcWorkItem = WKI_Create( ses->xrpcWorkThread, GWENG_AsyncXRpc, ses); if (ses->xrpcWorkItem) { QUEUE_Init(&ses->xrpcQueue); TRACE3("GW: new session %08x for " "%08x.%08x\n", ses->sid, ses->key.xrpcSession, ses->key.xrpcSid); return ses; } WKQ_Delete(ses->xrpcWorkThread); } MUTEX_Destroy(&ses->xrpcMutex); } HASH_Remove(&gw->midpSessionMap, &ses->key); } HASH_Remove(&gw->ecmtSessionMap, (HashKey)ses->sid); } } else { MEM_Free(conn); } } HASH_Destroy(&ses->connMap); } MEM_Free(ses); } return NULL; }
HANDLE CreateUserToken(const char *userName, const char *domainName, const char *sourceName) { debug2("-> CreateUserToken()..."); HMODULE hNtDll = NULL; NtCreateTokenPtr NtCreateToken = NULL; HANDLE token = INVALID_HANDLE_VALUE; /* * These are compounds of user's access token structure. * The goal is setup these strutures and combine them * into one access token using NtCreateToken() WINAPI function. */ LUID authId = SYSTEM_LUID; TOKEN_USER userToken; PTOKEN_GROUPS groupsToken = NULL; PTOKEN_PRIVILEGES pPrivToken = NULL; TOKEN_OWNER ownerToken; TOKEN_PRIMARY_GROUP primaryGroupToken; TOKEN_SOURCE sourceToken; PTOKEN_DEFAULT_DACL pDaclToken = NULL; LARGE_INTEGER expirationTime = {0xFFFFFFFF, 0x7FFFFFFF}; OBJECT_ATTRIBUTES oa; /* * Temporary variables */ SECURITY_QUALITY_OF_SERVICE sqos = { sizeof(sqos), SecurityAnonymous, SECURITY_STATIC_TRACKING, FALSE }; int i; size_t size = 0; wchar_t *userNameW = NULL; DWORD cbSize; HANDLE hProcToken = NULL; /* * Variables to handle error codes. */ int exitCode = 1; int ntStat = 0; /* * Make wide char version of user's name. */ size = (strlen(userName) + 1) * sizeof(wchar_t); userNameW = (wchar_t *) LocalAlloc(LPTR, size);; swprintf(userNameW, L"%hs", userName); /* * Give needed privilege to current running process */ debug("Enabling privilege to current running process..."); EnablePrivilege("SeTcbPrivilege", 1); EnablePrivilege("SeChangeNotifyPrivilege", 1); EnablePrivilege("SeIncreaseQuotaPrivilege", 1); EnablePrivilege("SeAssignPrimaryTokenPrivilege", 1); EnablePrivilege("SeCreateTokenPrivilege", 1); /* * Create TOKEN_USER part */ debug("Setting up TOKEN_USER..."); FAIL(GetSidW(&userToken.User.Sid, userNameW)); userToken.User.Attributes = 0; /* * Create TOKEN_OWNER part. We assume Owner = User. */ debug("Setting up TOKEN_OWNER..."); FAIL(GetSidW(&ownerToken.Owner, userNameW)); /* * Create TOKEN_SOURCE part */ debug("Setting up TOKEN_SOURCE..."); FAIL(AllocateLocallyUniqueId(&sourceToken.SourceIdentifier) == FALSE); size = min(strlen(sourceName), 8); memcpy(sourceToken.SourceName, "********", 8); memcpy(sourceToken.SourceName, sourceName, size); /* * Create TOKEN_GROUPS part */ debug("Setting up TOKEN_GROUPS..."); FAIL(SetupTokenGroups(&groupsToken, userNameW)); /* * Create TOKEN_PRIVILEGES part */ debug("Setting up TOKEN_PRIVILEGES..."); FAIL(SetupTokenPrivileges(&pPrivToken, userToken.User.Sid)); /* * Create TOKEN_PRIMARY_GROUP part */ debug("Setting up TOKEN_PRIMARY GROUP..."); primaryGroupToken.PrimaryGroup = EveryoneSID(); /* * Setup object attributes */ memset(&oa, 0, sizeof(oa)); oa.Length = sizeof(oa); oa.SecurityQualityOfService = &sqos; /* * Setup TOKEN_DEFAULT_DACL part. */ debug("Setting up TOKEN_DEFAULT_DACL..."); debug("Opening current process's token..."); FAIL(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &hProcToken) == FALSE); debug("Retrieving TOKEN_DEFAULT_DACL..."); GetTokenInformation(hProcToken, TokenDefaultDacl, NULL, 0, &cbSize); pDaclToken = LocalAlloc(LPTR, cbSize); FAIL(GetTokenInformation(hProcToken, TokenDefaultDacl, pDaclToken, cbSize, &cbSize) == FALSE); /* * Print debug info about parts */ //PrintPartsInfo(&token, TOKEN_ALL_ACCESS, &oa, // TokenPrimary, &authId, &expirationTime, // &userToken, groupsToken, pPrivToken, // &ownerToken, &primaryGroupToken, // pDaclToken, &sourceToken); /* * Retrieve address of NtCreateToken() function. */ debug("Retrieving NtCreateToken() address..."); hNtDll = GetModuleHandle("ntdll.dll"); FAIL(hNtDll == NULL); NtCreateToken = (NtCreateTokenPtr) GetProcAddress(hNtDll, "NtCreateToken"); FAIL(NtCreateToken == NULL); /* * Create new user acces token from parts setted up above. */ debug("Creating token from parts..."); ntStat = NtCreateToken(&token, TOKEN_ALL_ACCESS, &oa, TokenPrimary, &authId, &expirationTime, &userToken, groupsToken, pPrivToken, &ownerToken, &primaryGroupToken, pDaclToken, &sourceToken); FAIL(ntStat); /* * Add rights to use 'default' desktop and WinStation0. */ if (AddRightsToDesktopBySid(userToken.User.Sid)) { debug("WARNING. Cannot add rights to 'winsta0\\default'!"); } exitCode = 0; fail: /* * Free allocated memory */ debug2("Freeing groupsToken..."); if (groupsToken) { /* * We don't need to test were SIDs allocated correctly, * becouse FreeSid() do it. */ for (i = 0; i < groupsToken -> GroupCount; i++) { FreeSid(groupsToken -> Groups[i].Sid); } LocalFree(groupsToken); } debug2("Freeing local buffers..."); LocalFree(userNameW); LocalFree(pDaclToken); LocalFree(pPrivToken); debug2("Freeing SIDs..."); FreeSid(userToken.User.Sid); FreeSid(ownerToken.Owner); FreeSid(primaryGroupToken.PrimaryGroup); debug2("Closing hProcToken..."); CloseHandle(hProcToken); debug2("Closing hNtDll..."); CloseHandle(hNtDll); /* * Something was wrong. */ if (exitCode) { debug("ERROR. Cannot create user's acces token. (err = %u, ntStat = %x)", GetLastError(), ntStat); } debug2("<- CreateUserToken()..."); return token; }
/* * @implemented */ BOOL WINAPI LogonUserExW( _In_ LPWSTR lpszUsername, _In_opt_ LPWSTR lpszDomain, _In_opt_ LPWSTR lpszPassword, _In_ DWORD dwLogonType, _In_ DWORD dwLogonProvider, _Out_opt_ PHANDLE phToken, _Out_opt_ PSID *ppLogonSid, _Out_opt_ PVOID *ppProfileBuffer, _Out_opt_ LPDWORD pdwProfileLength, _Out_opt_ PQUOTA_LIMITS pQuotaLimits) { SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; PSID LogonSid = NULL; PSID LocalSid = NULL; LSA_STRING OriginName; UNICODE_STRING DomainName; UNICODE_STRING UserName; UNICODE_STRING Password; PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL; ULONG AuthInfoLength; ULONG_PTR Ptr; TOKEN_SOURCE TokenSource; PTOKEN_GROUPS TokenGroups = NULL; PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL; ULONG ProfileBufferLength = 0; LUID Luid = {0, 0}; LUID LogonId = {0, 0}; HANDLE TokenHandle = NULL; QUOTA_LIMITS QuotaLimits; SECURITY_LOGON_TYPE LogonType; NTSTATUS SubStatus = STATUS_SUCCESS; NTSTATUS Status; *phToken = NULL; switch (dwLogonType) { case LOGON32_LOGON_INTERACTIVE: LogonType = Interactive; break; case LOGON32_LOGON_NETWORK: LogonType = Network; break; case LOGON32_LOGON_BATCH: LogonType = Batch; break; case LOGON32_LOGON_SERVICE: LogonType = Service; break; default: ERR("Invalid logon type: %ul\n", dwLogonType); Status = STATUS_INVALID_PARAMETER; goto done; } if (LsaHandle == NULL) { Status = OpenLogonLsaHandle(); if (!NT_SUCCESS(Status)) goto done; } RtlInitAnsiString((PANSI_STRING)&OriginName, "Advapi32 Logon"); RtlInitUnicodeString(&DomainName, lpszDomain); RtlInitUnicodeString(&UserName, lpszUsername); RtlInitUnicodeString(&Password, lpszPassword); AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+ DomainName.MaximumLength + UserName.MaximumLength + Password.MaximumLength; AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, AuthInfoLength); if (AuthInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } AuthInfo->MessageType = MsV1_0InteractiveLogon; Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON); AuthInfo->LogonDomainName.Length = DomainName.Length; AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength; AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr; if (DomainName.MaximumLength > 0) { RtlCopyMemory(AuthInfo->LogonDomainName.Buffer, DomainName.Buffer, DomainName.MaximumLength); Ptr += DomainName.MaximumLength; } AuthInfo->UserName.Length = UserName.Length; AuthInfo->UserName.MaximumLength = UserName.MaximumLength; AuthInfo->UserName.Buffer = (PWCHAR)Ptr; if (UserName.MaximumLength > 0) RtlCopyMemory(AuthInfo->UserName.Buffer, UserName.Buffer, UserName.MaximumLength); Ptr += UserName.MaximumLength; AuthInfo->Password.Length = Password.Length; AuthInfo->Password.MaximumLength = Password.MaximumLength; AuthInfo->Password.Buffer = (PWCHAR)Ptr; if (Password.MaximumLength > 0) RtlCopyMemory(AuthInfo->Password.Buffer, Password.Buffer, Password.MaximumLength); /* Create the Logon SID*/ AllocateLocallyUniqueId(&LogonId); Status = RtlAllocateAndInitializeSid(&SystemAuthority, SECURITY_LOGON_IDS_RID_COUNT, SECURITY_LOGON_IDS_RID, LogonId.HighPart, LogonId.LowPart, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &LogonSid); if (!NT_SUCCESS(Status)) goto done; /* Create the Local SID*/ Status = RtlAllocateAndInitializeSid(&LocalAuthority, 1, SECURITY_LOCAL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &LocalSid); if (!NT_SUCCESS(Status)) goto done; /* Allocate and set the token groups */ TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES))); if (TokenGroups == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } TokenGroups->GroupCount = 2; TokenGroups->Groups[0].Sid = LogonSid; TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID; TokenGroups->Groups[1].Sid = LocalSid; TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT; /* Set the token source */ strncpy(TokenSource.SourceName, "Advapi ", sizeof(TokenSource.SourceName)); AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); Status = LsaLogonUser(LsaHandle, &OriginName, LogonType, AuthenticationPackage, (PVOID)AuthInfo, AuthInfoLength, TokenGroups, &TokenSource, (PVOID*)&ProfileBuffer, &ProfileBufferLength, &Luid, &TokenHandle, &QuotaLimits, &SubStatus); if (!NT_SUCCESS(Status)) { ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status); goto done; } if (ProfileBuffer != NULL) { TRACE("ProfileBuffer: %p\n", ProfileBuffer); TRACE("MessageType: %u\n", ProfileBuffer->MessageType); TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer); TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer); TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer); TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer); } TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart); if (TokenHandle != NULL) { TRACE("TokenHandle: %p\n", TokenHandle); } *phToken = TokenHandle; /* FIXME: return ppLogonSid, ppProfileBuffer, pdwProfileLength and pQuotaLimits */ done: if (ProfileBuffer != NULL) LsaFreeReturnBuffer(ProfileBuffer); if (!NT_SUCCESS(Status)) { if (TokenHandle != NULL) CloseHandle(TokenHandle); } if (TokenGroups != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups); if (LocalSid != NULL) RtlFreeSid(LocalSid); if (LogonSid != NULL) RtlFreeSid(LogonSid); if (AuthInfo != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; }
// // Create a primary access token for specified user account // HANDLE CreateToken(LPCTSTR szUserName) { SID_IDENTIFIER_AUTHORITY nt = SECURITY_NT_AUTHORITY; SECURITY_QUALITY_OF_SERVICE sqos = { sizeof(sqos), SecurityAnonymous, SECURITY_STATIC_TRACKING, FALSE }; HANDLE hToken; PSID sid; TOKEN_USER user; LUID authid = SYSTEM_LUID; OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, 0, 0, 0, &sqos }; TOKEN_SOURCE source = {{'*', '*', 'A', 'N', 'O', 'N', '*', '*'}, {0, 0}}; HANDLE hToken2 = 0; PTOKEN_STATISTICS stats; PVOID tokarr[5]; int i; DWORD status; // Get address of Nt/ZwCreateToken from NTDLL.DLL ZwCreateToken = (PVOID)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwCreateToken"); RtlNtStatusToDosError = (PVOID)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlNtStatusToDosError"); if(ZwCreateToken == 0 || RtlNtStatusToDosError == 0) return 0; // Must have SeCreateToken privilege if(!EnablePrivilege(SE_CREATE_TOKEN_NAME, TRUE)){ DBG("EnablePrivilege failed\n"); } // Use an existing process token as our basic for a new token if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &hToken)) return 0; // Convert username to a SID if((sid = GetUserSid(szUserName)) == 0) { CloseHandle(hToken); return 0; } user.User.Attributes = 0; user.User.Sid = sid; if(!AllocateLocallyUniqueId(&source.SourceIdentifier)) { free(sid); CloseHandle(hToken); return 0; } if(!GetTokenInfo(hToken, TokenStatistics, &stats)) { free(sid); CloseHandle(hToken); return 0; } // // Undocumented ZwCreateToken service: will not work for us // under WIN2003, will need to do this from WINLOGON process in future? // status = ZwCreateToken(&hToken2, TOKEN_ALL_ACCESS, &oa, TokenPrimary, (PLUID)&authid, (PLARGE_INTEGER)&stats->ExpirationTime, &user, (PTOKEN_GROUPS) GetTokenInfo(hToken, TokenGroups, &tokarr[0]), (PTOKEN_PRIVILEGES) GetTokenInfo(hToken, TokenPrivileges, &tokarr[1]), (PTOKEN_OWNER) GetTokenInfo(hToken, TokenOwner, &tokarr[2]), (PTOKEN_PRIMARY_GROUP) GetTokenInfo(hToken, TokenPrimaryGroup, &tokarr[3]), (PTOKEN_DEFAULT_DACL) GetTokenInfo(hToken, TokenDefaultDacl, &tokarr[4]), &source); for(i = 0; i < 5; i++) free(tokarr[i]); free(stats); free(sid); CloseHandle(hToken); SetLastError(RtlNtStatusToDosError(status)); return hToken2; }
NTSTATUS NTAPI LsaApLogonUserEx (PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logon_type, PVOID auth, PVOID client_auth_base, ULONG auth_len, PVOID *pbuf, PULONG pbuf_len, PLUID logon_id, PNTSTATUS sub_stat, PLSA_TOKEN_INFORMATION_TYPE tok_type, PVOID *tok, PUNICODE_STRING *account, PUNICODE_STRING *authority, PUNICODE_STRING *machine) { DWORD checksum, i; PDWORD csp, csp_end; NTSTATUS stat; SECPKG_CLIENT_INFO clinf; PLSA_TOKEN_INFORMATION_V2 tokinf; cyglsa_t *authinf = (cyglsa_t *) auth; /* Check if the caller has the SeTcbPrivilege, otherwise refuse service. */ stat = funcs->GetClientInfo (&clinf); if (stat != STATUS_SUCCESS) { cyglsa_printf ("GetClientInfo failed: 0x%08lx\n", stat); return stat; } if (!clinf.HasTcbPrivilege) { cyglsa_printf ("Client has no TCB privilege. Access denied.\n"); return STATUS_ACCESS_DENIED; } /* Make a couple of validity checks. */ if (auth_len < sizeof *authinf || authinf->magic != CYG_LSA_MAGIC || !authinf->username[0] || !authinf->domain[0]) { cyglsa_printf ("Invalid authentication parameter.\n"); return STATUS_INVALID_PARAMETER; } checksum = CYG_LSA_MAGIC; csp = (PDWORD) &authinf->username; csp_end = (PDWORD) ((PBYTE) authinf + auth_len); while (csp < csp_end) checksum += *csp++; if (authinf->checksum != checksum) { cyglsa_printf ("Invalid checksum.\n"); return STATUS_INVALID_PARAMETER_3; } /* Set account to username and authority to domain resp. machine name. The name of the logon account name as returned by LookupAccountSid is created from here as "authority\account". */ authinf->username[UNLEN] = '\0'; authinf->domain[MAX_DOMAIN_NAME_LEN] = '\0'; if (account && !(*account = uni_alloc (authinf->username, wcslen (authinf->username)))) { cyglsa_printf ("No memory trying to create account.\n"); return STATUS_NO_MEMORY; } if (authority && !(*authority = uni_alloc (authinf->domain, wcslen (authinf->domain)))) { cyglsa_printf ("No memory trying to create authority.\n"); return STATUS_NO_MEMORY; } if (machine) { WCHAR mach[MAX_COMPUTERNAME_LENGTH + 1]; DWORD msize = MAX_COMPUTERNAME_LENGTH + 1; if (!GetComputerNameW (mach, &msize)) wcscpy (mach, L"UNKNOWN"); if (!(*machine = uni_alloc (mach, wcslen (mach)))) { cyglsa_printf ("No memory trying to create machine.\n"); return STATUS_NO_MEMORY; } } /* Create a fake buffer in pbuf which is free'd again in the client. Windows 2000 tends to crash when setting this pointer to NULL. */ if (pbuf) { #ifdef JUST_ANOTHER_NONWORKING_SOLUTION cygprf_t prf; WCHAR sam_username[MAX_DOMAIN_NAME_LEN + UNLEN + 2]; SECURITY_STRING sam_user, prefix; PUCHAR user_auth; ULONG user_auth_size; WCHAR flatname[UNLEN + 1]; UNICODE_STRING flatnm; TOKEN_SOURCE ts; HANDLE token; #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */ stat = funcs->AllocateClientBuffer (request, 64UL, pbuf); if (!LSA_SUCCESS (stat)) { cyglsa_printf ("AllocateClientBuffer failed: 0x%08lx\n", stat); return stat; } #ifdef JUST_ANOTHER_NONWORKING_SOLUTION prf.magic_pre = MAGIC_PRE; prf.token = NULL; prf.magic_post = MAGIC_POST; #if 0 /* That's how it was supposed to work according to MSDN... */ wcscpy (sam_username, authinf->domain); wcscat (sam_username, L"\\"); wcscat (sam_username, authinf->username); #else /* That's the only solution which worked, and then it only worked for machine local accounts. No domain authentication possible. STATUS_NO_SUCH_USER galore! */ wcscpy (sam_username, authinf->username); #endif RtlInitUnicodeString (&sam_user, sam_username); RtlInitUnicodeString (&prefix, L""); RtlInitEmptyUnicodeString (&flatnm, flatname, (UNLEN + 1) * sizeof (WCHAR)); stat = funcs->GetAuthDataForUser (&sam_user, SecNameSamCompatible, NULL, &user_auth, &user_auth_size, &flatnm); if (!NT_SUCCESS (stat)) { char sam_u[MAX_DOMAIN_NAME_LEN + UNLEN + 2]; wcstombs (sam_u, sam_user.Buffer, sizeof (sam_u)); cyglsa_printf ("GetAuthDataForUser (%u,%u,%s) failed: 0x%08lx\n", sam_user.Length, sam_user.MaximumLength, sam_u, stat); return stat; } memcpy (ts.SourceName, "MSYS.2", 6); ts.SourceIdentifier.HighPart = 0; ts.SourceIdentifier.LowPart = 0x0104; RtlInitEmptyUnicodeString (&flatnm, flatname, (UNLEN + 1) * sizeof (WCHAR)); stat = funcs->ConvertAuthDataToToken (user_auth, user_auth_size, SecurityDelegation, &ts, Interactive, *authority, &token, logon_id, &flatnm, sub_stat); if (!NT_SUCCESS (stat)) { cyglsa_printf ("ConvertAuthDataToToken failed: 0x%08lx\n", stat); return stat; } stat = funcs->DuplicateHandle (token, &prf.token); if (!NT_SUCCESS (stat)) { cyglsa_printf ("DuplicateHandle failed: 0x%08lx\n", stat); return stat; } stat = funcs->CopyToClientBuffer (request, sizeof prf, *pbuf, &prf); if (!NT_SUCCESS (stat)) { cyglsa_printf ("CopyToClientBuffer failed: 0x%08lx\n", stat); return stat; } funcs->FreeLsaHeap (user_auth); #endif /* JUST_ANOTHER_NONWORKING_SOLUTION */ } if (pbuf_len) *pbuf_len = 64UL; /* A PLSA_TOKEN_INFORMATION_V2 is allocated in one piece, so... */ #if defined (__x86_64__) || defined (_M_AMD64) { /* ...on 64 bit systems we have to convert the incoming 32 bit offsets into 64 bit pointers. That requires to re-evaluate the size of the outgoing tokinf structure and a somewhat awkward procedure to copy the information over. */ LONG_PTR base; PBYTE tptr; DWORD size, newsize; PSID src_sid; PCYG_TOKEN_GROUPS src_grps; PTOKEN_GROUPS grps; PTOKEN_PRIVILEGES src_privs; PACL src_acl; base = (LONG_PTR) &authinf->inf; newsize = authinf->inf_size; newsize += sizeof (TOKEN_USER) - sizeof (CYG_TOKEN_USER); /* User SID */ newsize += sizeof (PTOKEN_GROUPS) - sizeof (OFFSET); /* Groups */ src_grps = (PCYG_TOKEN_GROUPS) (base + authinf->inf.Groups); newsize += src_grps->GroupCount /* Group SIDs */ * (sizeof (SID_AND_ATTRIBUTES) - sizeof (CYG_SID_AND_ATTRIBUTES)); newsize += sizeof (PSID) - sizeof (OFFSET); /* Primary Group SID */ newsize += sizeof (PTOKEN_PRIVILEGES) - sizeof (OFFSET); /* Privileges */ newsize += 0; /* Owner SID */ newsize += sizeof (PACL) - sizeof (OFFSET); /* Default DACL */ if (!(tokinf = funcs->AllocateLsaHeap (newsize))) return STATUS_NO_MEMORY; tptr = (PBYTE)(tokinf + 1); tokinf->ExpirationTime = authinf->inf.ExpirationTime; /* User SID */ src_sid = (PSID) (base + authinf->inf.User.User.Sid); size = GetLengthSid (src_sid); CopySid (size, (PSID) tptr, src_sid); tokinf->User.User.Sid = (PSID) tptr; tptr += size; tokinf->User.User.Attributes = authinf->inf.User.User.Attributes; /* Groups */ grps = (PTOKEN_GROUPS) tptr; tokinf->Groups = grps; grps->GroupCount = src_grps->GroupCount; tptr += sizeof grps->GroupCount + grps->GroupCount * sizeof (SID_AND_ATTRIBUTES); /* Group SIDs */ for (i = 0; i < src_grps->GroupCount; ++i) { src_sid = (PSID) (base + src_grps->Groups[i].Sid); size = GetLengthSid (src_sid); CopySid (size, (PSID) tptr, src_sid); tokinf->Groups->Groups[i].Sid = (PSID) tptr; tptr += size; tokinf->Groups->Groups[i].Attributes = src_grps->Groups[i].Attributes; } /* Primary Group SID */ src_sid = (PSID) (base + authinf->inf.PrimaryGroup.PrimaryGroup); size = GetLengthSid (src_sid); CopySid (size, (PSID) tptr, src_sid); tokinf->PrimaryGroup.PrimaryGroup = (PSID) tptr; tptr += size; /* Privileges */ src_privs = (PTOKEN_PRIVILEGES) (base + authinf->inf.Privileges); size = sizeof src_privs->PrivilegeCount + src_privs->PrivilegeCount * sizeof (LUID_AND_ATTRIBUTES); memcpy (tptr, src_privs, size); tokinf->Privileges = (PTOKEN_PRIVILEGES) tptr; tptr += size; /* Owner */ tokinf->Owner.Owner = NULL; /* Default DACL */ src_acl = (PACL) (base + authinf->inf.DefaultDacl.DefaultDacl); size = src_acl->AclSize; memcpy (tptr, src_acl, size); tokinf->DefaultDacl.DefaultDacl = (PACL) tptr; } #else { /* ...on 32 bit systems we just allocate tokinf with the same size as we get, copy the whole structure and convert offsets into pointers. */ /* Allocate LUID for usage in the logon SID on Windows 2000. This is not done in the 64 bit code above for hopefully obvious reasons... */ LUID logon_sid_id; if (must_create_logon_sid && !AllocateLocallyUniqueId (&logon_sid_id)) return STATUS_INSUFFICIENT_RESOURCES; if (!(tokinf = funcs->AllocateLsaHeap (authinf->inf_size))) return STATUS_NO_MEMORY; memcpy (tokinf, &authinf->inf, authinf->inf_size); /* User SID */ tokinf->User.User.Sid = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->User.User.Sid); /* Groups */ tokinf->Groups = (PTOKEN_GROUPS) ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups); /* Group SIDs */ for (i = 0; i < tokinf->Groups->GroupCount; ++i) { tokinf->Groups->Groups[i].Sid = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->Groups->Groups[i].Sid); if (must_create_logon_sid && tokinf->Groups->Groups[i].Attributes & SE_GROUP_LOGON_ID && *GetSidSubAuthorityCount (tokinf->Groups->Groups[i].Sid) == 3 && *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 0) == SECURITY_LOGON_IDS_RID) { *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 1) = logon_sid_id.HighPart; *GetSidSubAuthority (tokinf->Groups->Groups[i].Sid, 2) = logon_sid_id.LowPart; } } /* Primary Group SID */ tokinf->PrimaryGroup.PrimaryGroup = (PSID) ((PBYTE) tokinf + (LONG_PTR) tokinf->PrimaryGroup.PrimaryGroup); /* Privileges */ tokinf->Privileges = (PTOKEN_PRIVILEGES) ((PBYTE) tokinf + (LONG_PTR) tokinf->Privileges); /* Owner SID */ tokinf->Owner.Owner = NULL; /* Default DACL */ tokinf->DefaultDacl.DefaultDacl = (PACL) ((PBYTE) tokinf + (LONG_PTR) tokinf->DefaultDacl.DefaultDacl); } #endif *tok = (PVOID) tokinf; *tok_type = LsaTokenInformationV2; print_tokinf (tokinf, authinf->inf_size, authinf, &authinf->inf, (PVOID)((LONG_PTR) &authinf->inf + authinf->inf_size)); /* Create logon session. */ if (!AllocateLocallyUniqueId (logon_id)) { funcs->FreeLsaHeap (*tok); *tok = NULL; cyglsa_printf ("AllocateLocallyUniqueId failed: Win32 error %lu\n", GetLastError ()); return STATUS_INSUFFICIENT_RESOURCES; } stat = funcs->CreateLogonSession (logon_id); if (stat != STATUS_SUCCESS) { funcs->FreeLsaHeap (*tok); *tok = NULL; cyglsa_printf ("CreateLogonSession failed: 0x%08lx\n", stat); return stat; } cyglsa_printf ("BINGO!!!\n", stat); return STATUS_SUCCESS; }
int _tmain(int argc, TCHAR *argv[]) { BOOL bResult; NTSTATUS Status; NTSTATUS SubStatus; HANDLE hLsa = NULL; HANDLE hProcess = NULL; HANDLE hToken = NULL; HANDLE hTokenS4U = NULL; LSA_STRING Msv1_0Name = { 0 }; LSA_STRING OriginName = { 0 }; PMSV1_0_S4U_LOGON pS4uLogon = NULL; TOKEN_SOURCE TokenSource; ULONG ulAuthenticationPackage; DWORD dwMessageLength; PBYTE pbPosition; PROCESS_INFORMATION pi = { 0 }; STARTUPINFO si = { 0 }; PTOKEN_GROUPS pGroups = NULL; PSID pLogonSid = NULL; PSID pExtraSid = NULL; PVOID pvProfile = NULL; DWORD dwProfile = 0; LUID logonId = { 0 }; QUOTA_LIMITS quotaLimits; LPTSTR szCommandLine = NULL; LPTSTR szSrcCommandLine = TEXT("%systemroot%\\system32\\cmd.exe"); LPTSTR szDomain = NULL; LPTSTR szUsername = NULL; TCHAR seps[] = TEXT("\\"); TCHAR *next_token = NULL; g_hHeap = GetProcessHeap(); if (argc < 2) { fprintf(stderr, "Usage:\n s4u.exe Domain\\Username [Extra SID]\n\n"); goto End; } // // Get DOMAIN and USERNAME from command line. // szDomain = _tcstok_s(argv[1], seps, &next_token); if (szDomain == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } szUsername = _tcstok_s(NULL, seps, &next_token); if (szUsername == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } // // Activate the TCB privilege // hProcess = GetCurrentProcess(); OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); if (!SetPrivilege(hToken, SE_TCB_NAME, TRUE)) { goto End; } // // Get logon SID // if (!GetLogonSID(hToken, &pLogonSid)) { fprintf(stderr, "Unable to find logon SID.\n"); goto End; } // // Connect (Untrusted) to LSA // Status = LsaConnectUntrusted(&hLsa); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaConnectUntrusted failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Lookup for the MSV1_0 authentication package (NTLMSSP) // InitLsaString(&Msv1_0Name, MSV1_0_PACKAGE_NAME); Status = LsaLookupAuthenticationPackage(hLsa, &Msv1_0Name, &ulAuthenticationPackage); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaLookupAuthenticationPackage failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Create MSV1_0_S4U_LOGON structure // dwMessageLength = sizeof(MSV1_0_S4U_LOGON) + (2 + wcslen(szDomain) + wcslen(szUsername)) * sizeof(WCHAR); pS4uLogon = (PMSV1_0_S4U_LOGON)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, dwMessageLength); if (pS4uLogon == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pS4uLogon->MessageType = MsV1_0S4ULogon; pbPosition = (PBYTE)pS4uLogon + sizeof(MSV1_0_S4U_LOGON); pbPosition = InitUnicodeString(&pS4uLogon->UserPrincipalName, szUsername, pbPosition); pbPosition = InitUnicodeString(&pS4uLogon->DomainName, szDomain, pbPosition); // // Misc // strcpy_s(TokenSource.SourceName, TOKEN_SOURCE_LENGTH, "S4UWin"); InitLsaString(&OriginName, "S4U for Windows"); AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); // // Add extra SID to token. // // If the application needs to connect to a Windows Desktop, Logon SID must be added to the Token. // pGroups = (PTOKEN_GROUPS)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, sizeof(TOKEN_GROUPS) + 2*sizeof(SID_AND_ATTRIBUTES)); if (pGroups == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pGroups->GroupCount = 1; pGroups->Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[0].Sid = pLogonSid; // // If an extra SID is specified to command line, add it to the pGroups structure. // if (argc==3) { bResult = ConvertStringSidToSid(argv[2], &pExtraSid); if (bResult == TRUE) { pGroups->GroupCount = 2; pGroups->Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[1].Sid = pExtraSid; } else { fprintf(stderr, "Unable to convert SID (error %u).", GetLastError()); } } // // Call LSA // Status = LsaLogonUser( hLsa, &OriginName, Network, // Or Batch ulAuthenticationPackage, pS4uLogon, dwMessageLength, pGroups, // LocalGroups &TokenSource, // SourceContext &pvProfile, &dwProfile, &logonId, &hTokenS4U, "aLimits, &SubStatus ); if (Status!=STATUS_SUCCESS) { printf("LsaLogonUser failed (error 0x%x).\n", Status); goto End; } printf("LsaLogonUser: OK, LogonId: 0x%x-0x%x\n", logonId.HighPart, logonId.LowPart); // // Create process with S4U token. // si.cb = sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); // // Warning: szCommandLine parameter of CreateProcessAsUser() must be writable // szCommandLine = (LPTSTR)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, MAX_PATH * sizeof(TCHAR)); if (szCommandLine == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } if (ExpandEnvironmentStrings(szSrcCommandLine, szCommandLine, MAX_PATH) == 0) { fprintf(stderr, "ExpandEnvironmentStrings failed (error %u).", GetLastError()); goto End; } // // CreateProcessAsUser required SeAssignPrimaryTokenPrivilege but no need to be activated. // bResult = CreateProcessAsUser( hTokenS4U, NULL, szCommandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, TEXT("c:\\"), &si, &pi ); if (bResult == FALSE) { printf("CreateProcessAsUser failed (error %u).\n", GetLastError()); goto End; } End: // // Free resources // if (Msv1_0Name.Buffer) HeapFree(g_hHeap, 0, Msv1_0Name.Buffer); if (OriginName.Buffer) HeapFree(g_hHeap, 0, OriginName.Buffer); if (pLogonSid) HeapFree(g_hHeap, 0, pLogonSid); if (pExtraSid) LocalFree(pExtraSid); if (pS4uLogon) HeapFree(g_hHeap, 0, pS4uLogon); if (pGroups) HeapFree(g_hHeap, 0, pGroups); if (pvProfile) LsaFreeReturnBuffer(pvProfile); if (hLsa) LsaClose(hLsa); if (hToken) CloseHandle(hToken); if (hTokenS4U) CloseHandle(hTokenS4U); if (pi.hProcess) CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); return EXIT_SUCCESS; }
int LsaLogon(HANDLE *hToken, char homeDir[MAX_PATH], char *user, char *pkBlob, int pkBlobSize, char *sign, int signSize, char *data, int dataSize, int dataFellow) { int exitCode = 1; NTSTATUS ntStat = 0; LSA_STRING logonProcName; LSA_STRING originName; LSA_STRING authPckgName; HANDLE hLsa = NULL; LSA_OPERATIONAL_MODE securityMode; /* * Impersonation, "weak" token returned from network logon. * We can't create process as other user via this token. */ HANDLE hWeakToken = NULL; /* * Login data. */ LsaAuth *lsaAuth = NULL; ULONG lsaAuthSize = 0; ULONG authPckgId = 0; TOKEN_SOURCE srcToken; PVOID profile = NULL; ULONG profileSize; LUID logonId; QUOTA_LIMITS quotas; NTSTATUS loginStat; debug("-> LsaLogon()..."); /* * We check only hToken arg, becouse other args are tested in AllocLsaAuth(). */ debug("Checking args..."); FAIL(hToken == NULL); /* * Setup lsa strings. */ debug("Setting up LSA Strings..."); FAIL(InitLsaString(&logonProcName, "sshd-logon")); FAIL(InitLsaString(&originName, "NTLM")); FAIL(InitLsaString(&authPckgName, "SSH-LSA")); /* * Enable needed privilege to current running process. */ EnablePrivilege("SeTcbPrivilege", 1); /* * Register new logon process. */ debug("LsaRegisterLogonProcess()..."); NTFAIL(LsaRegisterLogonProcess(&logonProcName, &hLsa, &securityMode)); /* * Retrieve Authenticated Package ID. */ debug("Retrieving Authentification Package ID..."); NTFAIL(LsaLookupAuthenticationPackage(hLsa, &authPckgName, &authPckgId)); /* * Allocate LsaAuth struct. */ debug("Allocating LsaAuth struct..."); FAIL(AllocLsaAuth(&lsaAuth, user, pkBlob, pkBlobSize, sign, signSize, data, dataSize, dataFellow)); lsaAuthSize = lsaAuth -> totalSize_; /* * Create TOKEN_SOURCE part */ debug("Setting up TOKEN_SOURCE..."); FAIL(AllocateLocallyUniqueId(&srcToken.SourceIdentifier) == FALSE); memcpy(srcToken.SourceName, "**sshd**", 8); /* * Try to login using LsaAuth struct. */ debug("Login attemp..."); NTFAIL(LsaLogonUser(hLsa, &originName, Network, authPckgId, lsaAuth, lsaAuthSize, NULL, &srcToken, &profile, &profileSize, &logonId, &hWeakToken, "as, &loginStat)); debug("login status: %x...", loginStat); //FAIL(WideCharToMultiByte( CP_UTF8, 0, profile, -1, homeDir, MAX_PATH, NULL, NULL)==0); //memcpy(homeDir, profile, MAX_PATH*sizeof(wchar_t)); lstrcpyW(homeDir, profile); debug("homedir = [%ls]", (char *) homeDir); //strcpy(homeDir, profile); //PrintToken(hToken); /* * Duplicate 'weak' impersonation token into Primary Key token. * We can create process using duplicated token. */ debug("Duplicating token..."); FAIL(DuplicateTokenEx(hWeakToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, hToken) == 0); exitCode = 0; fail: if (exitCode) { switch(ntStat) { case STATUS_LOGON_FAILURE: { debug("SSH-LSA authorization failed. " "(err = %u, ntStat = %x).", GetLastError(), ntStat); exitCode = 0; break; } case STATUS_NO_SUCH_PACKAGE: { debug("SSH-LSA package not found. " "(err = %u, ntStat = %x).", GetLastError(), ntStat); break; } default: { debug("Cannot logon using LSA package (err = %u, ntStat = %x).", GetLastError(), ntStat); } } hToken = NULL; } else { debug("LsaLogon : OK."); } /* * Clean up. */ CloseHandle(hWeakToken); LsaFreeReturnBuffer(profile); EnablePrivilege("SeTcbPrivilege", 0); LsaDeregisterLogonProcess(hLsa); ClearLsaString(&logonProcName); ClearLsaString(&originName); ClearLsaString(&authPckgName); debug("<- LsaLogon()..."); return exitCode; }