[{"data":1,"prerenderedAt":30443},["ShallowReactive",2],{"post-windows-2fa-credential-provider":3},{"id":4,"title":5,"body":6,"category":30423,"date":30424,"description":30425,"draft":30426,"extension":30427,"image":30428,"links":30429,"meta":30434,"navigation":650,"path":30435,"readingTime":1587,"seo":30436,"stem":30437,"tags":30438,"__hash__":30442},"posts\u002Fposts\u002Fwindows-2fa-credential-provider.md","Build Your Own 2FA for the Windows Logon",{"type":7,"value":8,"toc":30369},"minimark",[9,14,18,21,24,27,38,41,51,55,76,79,83,86,92,106,109,112,118,121,125,130,137,140,144,147,157,168,171,183,190,194,197,269,273,276,346,356,362,366,369,375,378,381,553,556,560,563,578,585,591,982,987,3216,3219,3258,3261,3277,3297,3306,3316,3322,3326,3329,5009,5029,5038,5042,5047,5461,5466,8574,8577,8584,8595,8610,8613,8670,8674,8677,8707,8713,8730,8733,8737,8740,8744,10398,10401,10407,10422,10428,10431,10438,10444,10447,10451,10454,10460,10870,10877,10881,10886,11486,11491,14560,14563,14593,14611,14614,14617,14623,14642,14647,14654,14672,14676,14681,15477,15482,20507,20512,20515,20529,20532,20538,20544,20562,20571,20577,20589,20598,20602,20608,20615,20621,20624,20627,20631,20637,20687,20702,20706,20709,20712,20715,20720,21020,21025,21877,21880,21889,21898,21904,21916,21926,21932,21938,21942,21945,21951,22039,22042,22047,22277,22282,22957,22960,22992,23009,23012,23089,23092,23096,23099,23102,23107,23398,23403,24099,24107,24112,24115,24133,24137,24140,24149,24163,24168,24507,24511,26510,26519,26534,26538,26755,26760,26843,26848,27687,27691,27697,27708,27711,27724,28584,28587,28618,28628,28631,28634,28638,28643,28646,28652,28656,29021,29030,29037,29041,29044,29050,29054,29338,29350,29354,29360,29525,29530,29568,29573,29630,29633,29637,29640,29644,29655,29661,29672,29678,29682,29687,29705,29711,29714,29718,29721,29727,29730,29736,29739,29742,29746,29753,29796,29802,29808,29814,29820,29823,29829,29832,29838,29841,29847,29850,29856,29862,29866,29872,29888,29891,29894,29897,29900,30111,30114,30127,30131,30134,30137,30148,30154,30160,30163,30167,30170,30174,30177,30180,30191,30194,30197,30220,30223,30227,30237,30244,30248,30258,30262,30265,30269,30272,30310,30314,30317,30320,30340,30343,30347,30350,30353,30359,30362,30365],[10,11,13],"h2",{"id":12},"foreword","Foreword",[15,16,17],"p",{},"This is going to be a long one. Make sure you have enough coffee.",[15,19,20],{},"In this entry I would like to show you how 2FA on the Windows logon screen actually works. Products like AuthLite do exactly this and I always wanted to know what happens behind the scenes. So I built it myself.",[15,22,23],{},"At the end we have a working 2FA for local Windows accounts. You log in with your password and a 6-digit code from your authenticator app (Google Authenticator, Microsoft Authenticator or whatever you use).",[15,25,26],{},"I have not found a guide on the internet that explains the whole thing from start to finish. Most tutorials just add a text field to the logon screen and call it 2FA. As you will see, that is not enough.",[15,28,29,30,37],{},"All the code is in this article. You can build everything with one command. If you'd rather clone it, the project is also on GitHub: ",[31,32,36],"a",{"href":33,"rel":34},"https:\u002F\u002Fgithub.com\u002FNobrac\u002Fdoppio",[35],"nofollow","Doppio",". A doppio is a double espresso. Two shots, two factors.",[15,39,40],{},"I am by no means claiming that this is production ready. It is a demo for learning. I will show you exactly where the limits are.",[42,43,44],"blockquote",{},[15,45,46,50],{},[47,48,49],"strong",{},"Important:"," Only do this in a VM and take a snapshot before every install. If the Credential Provider is broken, you can no longer log in. There is no error message, you are just locked out.",[10,52,54],{"id":53},"prerequisites","Prerequisites",[56,57,58,62,65,73],"ul",{},[59,60,61],"li",{},"A Windows 10\u002F11 VM (please really use a VM)",[59,63,64],{},"Visual Studio 2026 or 2022 (Community is enough) or the Build Tools, with the \"Desktop development with C++\" workload. The Windows SDK is included.",[59,66,67,68,72],{},"Nothing extra on the test VM. The C++ runtime is linked statically (",[69,70,71],"code",{},"\u002FMT","), so no Visual C++ Redistributable is needed.",[59,74,75],{},"An authenticator app on your phone",[15,77,78],{},"I built and tested everything on one Windows VM in my homelab. Visual Studio runs on the same VM, so there is nothing to copy between machines.",[10,80,82],{"id":81},"what-this-protects-and-what-not","What this protects and what not",[15,84,85],{},"Before we start, it is important to understand what this demo can do.",[15,87,88,91],{},[47,89,90],{},"Protected:"," The interactive logon and the unlock of local accounts. This means the console and RDP sessions that end up on our tile. Without a valid code the password is never sent to Windows.",[15,93,94,97,98,101,102,105],{},[47,95,96],{},"Not protected:"," Everything that does not go through our tile. Network logons (",[69,99,100],{},"\\\\host\\share","), ",[69,103,104],{},"runas",", scheduled tasks, WinRM, PowerShell remoting, WMI and UAC prompts.",[15,107,108],{},"The UAC part is important for local accounts. If someone sits at an unlocked session and knows the password of a local admin, they can elevate without the code.",[15,110,111],{},"You can close most of the network paths with the usual hardening, for example \"Deny access to this computer from the network\" for local accounts. This is not enabled by default. Out of the box a local account can still log on via SMB with just the password.",[15,113,114,117],{},[47,115,116],{},"Physical access is a different story."," Whoever can reboot the machine can go around the logon screen completely, for example with Safe Mode or by editing the registry offline. No Credential Provider can stop that. This has its own chapter: \"Attacks that never touch the tile\".",[15,119,120],{},"Why this is the case is explained in the next chapter.",[10,122,124],{"id":123},"how-the-windows-logon-works","How the Windows logon works",[126,127,129],"h3",{"id":128},"from-gina-to-credential-providers","From GINA to Credential Providers",[15,131,132,133,136],{},"Up to Windows XP you had to replace the ",[69,134,135],{},"msgina.dll"," if you wanted to change the logon. GINA stands for \"Graphical Identification and Authentication\". There could only be one GINA per machine. If two vendors wanted to change the logon, you had a problem. And if the GINA was broken, nobody could log in anymore.",[15,138,139],{},"With Windows Vista Microsoft replaced this with Credential Providers. These are COM objects (DLLs) and there can be as many as you want. Each Credential Provider can show one or more tiles on the logon screen. This is still the model today, from Windows 7 to Windows 11 and Server 2025.",[126,141,143],{"id":142},"the-logon-chain","The logon chain",[15,145,146],{},"This is the most important part of the whole article. When you log in, the following happens:",[148,149,155],"pre",{"className":150,"code":152,"language":153,"meta":154},[151],"language-text","  Winlogon.exe         manages the session and the Secure Desktop,\n      |                handles Ctrl+Alt+Del\n      v\n  LogonUI.exe          shows the logon screen and loads the Credential Providers\n      |\n      v\n  Credential           shows the tile, collects the input and\n  Provider (DLL)       packs it into a blob (serialization)\n      |\n      v\n  LSA (lsass.exe)      receives the blob and passes it to an authentication package\n      |\n      v\n  Authentication       MSV1_0 (NTLM \u002F local SAM), Kerberos or a custom package.\n  Package              This is where the password is actually checked.\n","text","",[69,156,152],{"__ignoreMap":154},[15,158,159,160,163,164,167],{},"The Credential Provider does not check the password. It only collects the input and packs it into a blob. The check happens in LSA (Local Security Authority, ",[69,161,162],{},"lsass.exe","). For a local account LSA passes the blob to ",[69,165,166],{},"MSV1_0",", which checks it against the local SAM database. The provider never finds out if the password was correct. It just hands over the blob.",[15,169,170],{},"This is important for everything that follows. It has two consequences:",[172,173,174,177],"ol",{},[59,175,176],{},"The provider can refuse to create the blob. No blob, no logon. This is our 2FA: if the code is wrong, we simply don't create the blob.",[59,178,179,180,182],{},"The provider only sees logons that go through its tile. Network logons, ",[69,181,104],{},", services and UAC prompts go to LSA on another way. Our code is never called for them.",[15,184,185,186,189],{},"The second point is a limit of every Credential Provider. That's why AuthLite has two parts: a Credential Provider for the tile and a component directly in LSA. There every logon is checked, no matter where it comes from. The LSA part is a lot harder and more risky. If you have a bug there, ",[69,187,188],{},"lsass"," crashes and takes the whole machine with it. In this article I build the first part.",[126,191,193],{"id":192},"the-interfaces","The interfaces",[15,195,196],{},"A Credential Provider is not just one object. It is a set of COM interfaces. In this project I use five of them:",[56,198,199,225,239,249,263],{},[59,200,201,204,205,208,209,212,213,216,217,220,221,224],{},[69,202,203],{},"ICredentialProvider"," is the provider itself. LogonUI asks it how many tiles there are (",[69,206,207],{},"GetCredentialCount","), which fields a tile has (",[69,210,211],{},"GetFieldDescriptorCount",", ",[69,214,215],{},"GetFieldDescriptorAt",") and for the tiles themselves (",[69,218,219],{},"GetCredentialAt","). With ",[69,222,223],{},"SetUsageScenario"," LogonUI tells it the situation, more about this below.",[59,226,227,230,231,234,235,238],{},[69,228,229],{},"ICredentialProviderCredential"," is one tile. It stores the input (",[69,232,233],{},"SetStringValue",") and has the most important function: ",[69,236,237],{},"GetSerialization",". This is where the input becomes the blob for LSA.",[59,240,241,244,245,248],{},[69,242,243],{},"ICredentialProviderCredential2"," is the same with one more function: ",[69,246,247],{},"GetUserSid",". With this a tile belongs to a user account. Windows then shows the name and the round profile picture of that account, like on the normal tiles.",[59,250,251,254,255,258,259,262],{},[69,252,253],{},"ICredentialProviderSetUserArray"," belongs to the provider. LogonUI uses ",[69,256,257],{},"SetUserArray"," to give us the list of users that should be shown. For every user I read the name (",[69,260,261],{},"PC\\user",") and the SID.",[59,264,265,268],{},[69,266,267],{},"ICredentialProviderFilter"," decides which providers are shown. I use it to hide password, PIN and Windows Hello. Without the filter you could simply choose the normal password tile and skip the code.",[126,270,272],{"id":271},"usage-scenarios","Usage scenarios",[15,274,275],{},"Windows calls the providers in different situations. These are called usage scenarios:",[277,278,279,292],"table",{},[280,281,282],"thead",{},[283,284,285,289],"tr",{},[286,287,288],"th",{},"Scenario",[286,290,291],{},"When",[293,294,295,306,316,326,336],"tbody",{},[283,296,297,303],{},[298,299,300],"td",{},[69,301,302],{},"CPUS_LOGON",[298,304,305],{},"Normal logon",[283,307,308,313],{},[298,309,310],{},[69,311,312],{},"CPUS_UNLOCK_WORKSTATION",[298,314,315],{},"Unlock after locking the screen",[283,317,318,323],{},[298,319,320],{},[69,321,322],{},"CPUS_CHANGE_PASSWORD",[298,324,325],{},"Password change",[283,327,328,333],{},[298,329,330],{},[69,331,332],{},"CPUS_CREDUI",[298,334,335],{},"Credential prompts, including UAC",[283,337,338,343],{},[298,339,340],{},[69,341,342],{},"CPUS_PLAP",[298,344,345],{},"Pre-logon access (e.g. VPN before logon)",[15,347,348,349,352,353,355],{},"We only support logon and unlock. For everything else the provider returns ",[69,350,351],{},"E_NOTIMPL",". This is important. ",[69,354,332],{}," is used for every UAC prompt and every application that asks for Windows credentials. If a provider does something wrong there, credential prompts can stop working in the whole system. So only support what you really need.",[15,357,358,359,361],{},"This is also where the UAC gap comes from. We don't take part in ",[69,360,332],{},", so UAC still uses the normal password prompt without a code.",[10,363,365],{"id":364},"architecture-of-the-demo","Architecture of the demo",[15,367,368],{},"The demo consists of three parts that share the same TOTP code:",[148,370,373],{"className":371,"code":372,"language":153,"meta":154},[151],"  enroll.exe (admin, once per user)\n      |  creates a 160-bit secret, encodes it in Base32,\n      |  prints an otpauth:\u002F\u002F URI for the phone,\n      |  encrypts the secret with DPAPI and saves it\n      v\n  HKLM\\SOFTWARE\\TheAdminCafe\\2FA\\\u003CSID>         (REG_BINARY, DPAPI blob,\n                                                only SYSTEM + Admins have access)\n  HKLM\\SOFTWARE\\TheAdminCafe\\2FA\\State\\\u003CSID>   (REG_BINARY: last used time step,\n                                                wrong codes in a row, locked until)\n      ^\n      |  read, decrypt and update at logon (LogonUI runs as SYSTEM)\n      |\n  TacProvider.dll\n      |- CTacProvider    one tile per local user, only logon + unlock\n      |- CTacCredential  username + password + code, checks the code\n      |                  and only then sends the password to LSA\n      |- VerifyOtp       replay protection, lock after wrong codes\n      |- LogEvent        every attempt goes to the Application log\n      |- CTacFilter      hides all other tiles, forwards RDP credentials\n      v\n  LSA -> Negotiate -> MSV1_0 (local SAM)\n",[69,374,372],{"__ignoreMap":154},[15,376,377],{},"The secret is encrypted with DPAPI and stored in the registry. The key is only readable for SYSTEM and administrators. Why both are needed is explained in the chapter about the secret store.",[15,379,380],{},"The project consists of these files:",[277,382,383,393],{},[280,384,385],{},[283,386,387,390],{},[286,388,389],{},"File",[286,391,392],{},"Purpose",[293,394,395,405,415,425,435,445,455,465,475,488,498,514,527,537],{},[283,396,397,402],{},[298,398,399],{},[69,400,401],{},"totp.h\u002F.cpp",[298,403,404],{},"TOTP (RFC 6238) and Base32 with CNG (bcrypt)",[283,406,407,412],{},[298,408,409],{},[69,410,411],{},"store.h\u002F.cpp",[298,413,414],{},"Secret store with DPAPI and a protected registry key, state per account",[283,416,417,422],{},[298,418,419],{},[69,420,421],{},"verify.h\u002F.cpp",[298,423,424],{},"Replay protection and lock after wrong codes",[283,426,427,432],{},[298,428,429],{},[69,430,431],{},"eventlog.h\u002F.cpp",[298,433,434],{},"Events in the Application log",[283,436,437,442],{},[298,438,439],{},[69,440,441],{},"enroll.cpp",[298,443,444],{},"Console tool to enroll a user",[283,446,447,452],{},[298,448,449],{},[69,450,451],{},"common.h",[298,453,454],{},"Fields of the tile",[283,456,457,462],{},[298,458,459],{},[69,460,461],{},"CTacProvider.h\u002F.cpp",[298,463,464],{},"The provider, one tile per local user",[283,466,467,472],{},[298,468,469],{},[69,470,471],{},"CTacCredential.h\u002F.cpp",[298,473,474],{},"One tile with the code check",[283,476,477,482],{},[298,478,479],{},[69,480,481],{},"CTacFilter.h\u002F.cpp",[298,483,484,485,487],{},"The filter (",[69,486,267],{},")",[283,489,490,495],{},[298,491,492],{},[69,493,494],{},"helpers.h\u002F.cpp",[298,496,497],{},"Helper functions for the serialization",[283,499,500,511],{},[298,501,502,212,505,212,508],{},[69,503,504],{},"dll.h\u002F.cpp",[69,506,507],{},"guid.h",[69,509,510],{},"TacProvider.def",[298,512,513],{},"COM stuff: class factory, exports, CLSIDs",[283,515,516,524],{},[298,517,518,212,521],{},[69,519,520],{},"build.bat",[69,522,523],{},"CMakeLists.txt",[298,525,526],{},"Build",[283,528,529,534],{},[298,530,531],{},[69,532,533],{},"new-guids.ps1",[298,535,536],{},"Creates your own CLSIDs",[283,538,539,550],{},[298,540,541,212,544,212,547],{},[69,542,543],{},"register.reg",[69,545,546],{},"register-filter.reg",[69,548,549],{},"unregister.reg",[298,551,552],{},"Registration in Windows",[15,554,555],{},"Let's start with the part that has nothing to do with the logon.",[10,557,559],{"id":558},"totp","TOTP",[15,561,562],{},"TOTP (RFC 6238) creates a 6-digit code from a secret and the current time. It works in three steps:",[172,564,565,568,575],{},[59,566,567],{},"Take the unix time and divide it by 30. This is a counter that changes every 30 seconds. The phone and the PC get the same counter, as long as the clocks are correct.",[59,569,570,571,574],{},"Calculate ",[69,572,573],{},"HMAC-SHA1(secret, counter)",". The result has 20 bytes. Only someone with the secret can calculate it.",[59,576,577],{},"Make 6 digits out of the 20 bytes. This is called dynamic truncation (RFC 4226). The last 4 bits of the hash are an offset. From there you read 4 bytes, remove the highest bit so the number is not negative, and take the result modulo 1'000'000.",[15,579,580,581,584],{},"For the HMAC I use CNG (",[69,582,583],{},"bcrypt",") from Windows, so no external libraries are needed. The whole thing has about 160 lines.",[15,586,587,590],{},[69,588,589],{},"totp.h",":",[148,592,596],{"className":593,"code":594,"language":595,"meta":154,"style":154},"language-cpp shiki shiki-themes github-dark","#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccstdint>\n#include \u003Cstring>\n#include \u003Cvector>\n\nnamespace tac\n{\n    bool        Base32Decode(const std::string& in, std::vector\u003CBYTE>& out);\n    std::string Base32Encode(const BYTE* data, size_t len);\n\n    \u002F\u002F RFC 6238 code for a given unix time. Returns false if the HMAC fails.\n    bool TotpAt(const std::vector\u003CBYTE>& key, uint64_t unixTime,\n                uint32_t step, int digits, uint32_t& code);\n\n    \u002F\u002F Accepts the time step of `now` and +\u002F- window steps around it, but only\n    \u002F\u002F steps greater than lastStep (replay protection, 0 = nothing used yet).\n    \u002F\u002F On success matchedStep is the step the code belongs to.\n    bool ValidateTotp(const std::vector\u003CBYTE>& key, const std::wstring& input,\n                      uint64_t now, uint64_t lastStep, uint64_t& matchedStep,\n                      uint32_t step = 30, int digits = 6, int window = 1);\n}\n","cpp",[69,597,598,611,621,629,637,645,652,661,668,726,762,767,774,814,841,846,852,858,864,910,936,976],{"__ignoreMap":154},[599,600,603,607],"span",{"class":601,"line":602},"line",1,[599,604,606],{"class":605},"snl16","#pragma",[599,608,610],{"class":609},"svObZ"," once\n",[599,612,614,617],{"class":601,"line":613},2,[599,615,616],{"class":605},"#include",[599,618,620],{"class":619},"sU2Wk"," \u003Cwindows.h>\n",[599,622,624,626],{"class":601,"line":623},3,[599,625,616],{"class":605},[599,627,628],{"class":619}," \u003Ccstdint>\n",[599,630,632,634],{"class":601,"line":631},4,[599,633,616],{"class":605},[599,635,636],{"class":619}," \u003Cstring>\n",[599,638,640,642],{"class":601,"line":639},5,[599,641,616],{"class":605},[599,643,644],{"class":619}," \u003Cvector>\n",[599,646,648],{"class":601,"line":647},6,[599,649,651],{"emptyLinePlaceholder":650},true,"\n",[599,653,655,658],{"class":601,"line":654},7,[599,656,657],{"class":605},"namespace",[599,659,660],{"class":609}," tac\n",[599,662,664],{"class":601,"line":663},8,[599,665,667],{"class":666},"s95oV","{\n",[599,669,671,674,677,680,683,686,689,692,695,699,701,704,706,709,712,715,718,720,723],{"class":601,"line":670},9,[599,672,673],{"class":605},"    bool",[599,675,676],{"class":609},"        Base32Decode",[599,678,679],{"class":666},"(",[599,681,682],{"class":605},"const",[599,684,685],{"class":609}," std",[599,687,688],{"class":666},"::",[599,690,691],{"class":609},"string",[599,693,694],{"class":605},"&",[599,696,698],{"class":697},"s9osk"," in",[599,700,212],{"class":666},[599,702,703],{"class":609},"std",[599,705,688],{"class":666},[599,707,708],{"class":609},"vector",[599,710,711],{"class":666},"\u003C",[599,713,714],{"class":609},"BYTE",[599,716,717],{"class":666},">",[599,719,694],{"class":605},[599,721,722],{"class":697}," out",[599,724,725],{"class":666},");\n",[599,727,729,732,734,736,739,741,743,746,749,752,754,757,760],{"class":601,"line":728},10,[599,730,731],{"class":609},"    std",[599,733,688],{"class":666},[599,735,691],{"class":609},[599,737,738],{"class":609}," Base32Encode",[599,740,679],{"class":666},[599,742,682],{"class":605},[599,744,745],{"class":609}," BYTE",[599,747,748],{"class":605},"*",[599,750,751],{"class":697}," data",[599,753,212],{"class":666},[599,755,756],{"class":605},"size_t",[599,758,759],{"class":697}," len",[599,761,725],{"class":666},[599,763,765],{"class":601,"line":764},11,[599,766,651],{"emptyLinePlaceholder":650},[599,768,770],{"class":601,"line":769},12,[599,771,773],{"class":772},"sAwPA","    \u002F\u002F RFC 6238 code for a given unix time. Returns false if the HMAC fails.\n",[599,775,777,779,782,784,786,788,790,792,794,796,798,800,803,805,808,811],{"class":601,"line":776},13,[599,778,673],{"class":605},[599,780,781],{"class":609}," TotpAt",[599,783,679],{"class":666},[599,785,682],{"class":605},[599,787,685],{"class":609},[599,789,688],{"class":666},[599,791,708],{"class":609},[599,793,711],{"class":666},[599,795,714],{"class":609},[599,797,717],{"class":666},[599,799,694],{"class":605},[599,801,802],{"class":697}," key",[599,804,212],{"class":666},[599,806,807],{"class":605},"uint64_t",[599,809,810],{"class":697}," unixTime",[599,812,813],{"class":666},",\n",[599,815,817,820,823,825,828,831,833,836,839],{"class":601,"line":816},14,[599,818,819],{"class":605},"                uint32_t",[599,821,822],{"class":697}," step",[599,824,212],{"class":666},[599,826,827],{"class":605},"int",[599,829,830],{"class":697}," digits",[599,832,212],{"class":666},[599,834,835],{"class":605},"uint32_t&",[599,837,838],{"class":697}," code",[599,840,725],{"class":666},[599,842,844],{"class":601,"line":843},15,[599,845,651],{"emptyLinePlaceholder":650},[599,847,849],{"class":601,"line":848},16,[599,850,851],{"class":772},"    \u002F\u002F Accepts the time step of `now` and +\u002F- window steps around it, but only\n",[599,853,855],{"class":601,"line":854},17,[599,856,857],{"class":772},"    \u002F\u002F steps greater than lastStep (replay protection, 0 = nothing used yet).\n",[599,859,861],{"class":601,"line":860},18,[599,862,863],{"class":772},"    \u002F\u002F On success matchedStep is the step the code belongs to.\n",[599,865,867,869,872,874,876,878,880,882,884,886,888,890,892,894,896,898,900,903,905,908],{"class":601,"line":866},19,[599,868,673],{"class":605},[599,870,871],{"class":609}," ValidateTotp",[599,873,679],{"class":666},[599,875,682],{"class":605},[599,877,685],{"class":609},[599,879,688],{"class":666},[599,881,708],{"class":609},[599,883,711],{"class":666},[599,885,714],{"class":609},[599,887,717],{"class":666},[599,889,694],{"class":605},[599,891,802],{"class":697},[599,893,212],{"class":666},[599,895,682],{"class":605},[599,897,685],{"class":609},[599,899,688],{"class":666},[599,901,902],{"class":609},"wstring",[599,904,694],{"class":605},[599,906,907],{"class":697}," input",[599,909,813],{"class":666},[599,911,913,916,919,921,923,926,928,931,934],{"class":601,"line":912},20,[599,914,915],{"class":605},"                      uint64_t",[599,917,918],{"class":697}," now",[599,920,212],{"class":666},[599,922,807],{"class":605},[599,924,925],{"class":697}," lastStep",[599,927,212],{"class":666},[599,929,930],{"class":605},"uint64_t&",[599,932,933],{"class":697}," matchedStep",[599,935,813],{"class":666},[599,937,939,942,944,947,951,953,955,957,959,962,964,966,969,971,974],{"class":601,"line":938},21,[599,940,941],{"class":605},"                      uint32_t",[599,943,822],{"class":697},[599,945,946],{"class":605}," =",[599,948,950],{"class":949},"sDLfK"," 30",[599,952,212],{"class":666},[599,954,827],{"class":605},[599,956,830],{"class":697},[599,958,946],{"class":605},[599,960,961],{"class":949}," 6",[599,963,212],{"class":666},[599,965,827],{"class":605},[599,967,968],{"class":697}," window",[599,970,946],{"class":605},[599,972,973],{"class":949}," 1",[599,975,725],{"class":666},[599,977,979],{"class":601,"line":978},22,[599,980,981],{"class":666},"}\n",[15,983,984,590],{},[69,985,986],{},"totp.cpp",[148,988,990],{"className":593,"code":989,"language":595,"meta":154,"style":154},"#include \"totp.h\"\n#include \u003Cbcrypt.h>\n\n#pragma comment(lib, \"bcrypt.lib\")\n\nnamespace tac\n{\n    static const char kAlphabet[] = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\";\n\n    static int Base32Value(char c)\n    {\n        if (c >= 'A' && c \u003C= 'Z') return c - 'A';\n        if (c >= 'a' && c \u003C= 'z') return c - 'a';\n        if (c >= '2' && c \u003C= '7') return c - '2' + 26;\n        return -1;\n    }\n\n    bool Base32Decode(const std::string& in, std::vector\u003CBYTE>& out)\n    {\n        uint32_t buffer = 0;\n        int bits = 0;\n        out.clear();\n\n        for (char c : in)\n        {\n            if (c == '=' || c == ' ')\n                continue;\n            int v = Base32Value(c);\n            if (v \u003C 0)\n                return false;\n\n            buffer = (buffer \u003C\u003C 5) | static_cast\u003Cuint32_t>(v);\n            bits += 5;\n            if (bits >= 8)\n            {\n                bits -= 8;\n                out.push_back(static_cast\u003CBYTE>(buffer >> bits));\n                buffer &= (1u \u003C\u003C bits) - 1;   \u002F\u002F keep only the bits not consumed yet\n            }\n        }\n        return true;\n    }\n\n    std::string Base32Encode(const BYTE* data, size_t len)\n    {\n        std::string out;\n        uint32_t buffer = 0;\n        int bits = 0;\n\n        for (size_t i = 0; i \u003C len; ++i)\n        {\n            buffer = (buffer \u003C\u003C 8) | data[i];\n            bits += 8;\n            while (bits >= 5)\n            {\n                bits -= 5;\n                out += kAlphabet[(buffer >> bits) & 0x1F];\n            }\n            buffer &= (1u \u003C\u003C bits) - 1;\n        }\n        if (bits > 0)\n            out += kAlphabet[(buffer \u003C\u003C (5 - bits)) & 0x1F];\n        return out;\n    }\n\n    static bool HmacSha1(const std::vector\u003CBYTE>& key, const BYTE* msg, ULONG cbMsg, BYTE mac[20])\n    {\n        BCRYPT_ALG_HANDLE  hAlg  = nullptr;\n        BCRYPT_HASH_HANDLE hHash = nullptr;\n        bool ok = false;\n\n        if (BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM, nullptr,\n                                        BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0)\n            return false;\n\n        if (BCryptCreateHash(hAlg, &hHash, nullptr, 0, const_cast\u003CPUCHAR>(key.data()),\n                             static_cast\u003CULONG>(key.size()), 0) == 0)\n        {\n            ok = BCryptHashData(hHash, const_cast\u003CPUCHAR>(msg), cbMsg, 0) == 0 &&\n                 BCryptFinishHash(hHash, mac, 20, 0) == 0;\n            BCryptDestroyHash(hHash);\n        }\n        BCryptCloseAlgorithmProvider(hAlg, 0);\n        return ok;\n    }\n\n    bool TotpAt(const std::vector\u003CBYTE>& key, uint64_t unixTime,\n                uint32_t step, int digits, uint32_t& code)\n    {\n        \u002F\u002F The counter is the number of time steps since 1970, as 8 bytes big-endian.\n        uint64_t counter = unixTime \u002F step;\n        BYTE msg[8];\n        for (int i = 7; i >= 0; --i)\n        {\n            msg[i] = static_cast\u003CBYTE>(counter & 0xFF);\n            counter >>= 8;\n        }\n\n        BYTE mac[20];\n        if (!HmacSha1(key, msg, sizeof(msg), mac))\n            return false;\n\n        \u002F\u002F Dynamic truncation (RFC 4226, 5.3): the low nibble of the last byte\n        \u002F\u002F selects 4 bytes; the top bit is dropped to avoid signed values.\n        int offset = mac[19] & 0x0F;\n        uint32_t bin = ((mac[offset]     & 0x7Fu) \u003C\u003C 24) |\n                       ((mac[offset + 1] & 0xFFu) \u003C\u003C 16) |\n                       ((mac[offset + 2] & 0xFFu) \u003C\u003C  8) |\n                        (mac[offset + 3] & 0xFFu);\n\n        uint32_t mod = 1;\n        for (int i = 0; i \u003C digits; ++i)\n            mod *= 10;\n        code = bin % mod;\n        return true;\n    }\n\n    bool ValidateTotp(const std::vector\u003CBYTE>& key, const std::wstring& input,\n                      uint64_t now, uint64_t lastStep, uint64_t& matchedStep,\n                      uint32_t step, int digits, int window)\n    {\n        matchedStep = 0;\n\n        \u002F\u002F Exactly `digits` ASCII digits. wcstoul would also accept \"12abc\" or \"0\".\n        if (input.size() != static_cast\u003Csize_t>(digits))\n            return false;\n        uint32_t entered = 0;\n        for (wchar_t c : input)\n        {\n            if (c \u003C L'0' || c > L'9')\n                return false;\n            entered = entered * 10 + static_cast\u003Cuint32_t>(c - L'0');\n        }\n\n        const uint64_t current = now \u002F step;\n        for (int w = -window; w \u003C= window; ++w)\n        {\n            if (w \u003C 0 && current \u003C static_cast\u003Cuint64_t>(-w))\n                continue;\n            const uint64_t counter = current + static_cast\u003Cint64_t>(w);\n\n            \u002F\u002F \"\u003C=\" and not \"==\": a step at or before the last used one is never\n            \u002F\u002F accepted again. This also stops an old code after the clock was\n            \u002F\u002F turned back.\n            if (counter \u003C= lastStep)\n                continue;\n\n            uint32_t expected = 0;\n            if (TotpAt(key, counter * step, step, digits, expected) && expected == entered)\n            {\n                matchedStep = counter;\n                return true;\n            }\n        }\n        return false;\n    }\n}\n",[69,991,992,999,1006,1010,1030,1034,1040,1044,1067,1071,1091,1096,1137,1169,1207,1220,1225,1229,1270,1274,1289,1303,1314,1319,1333,1339,1365,1373,1389,1403,1414,1419,1447,1460,1475,1481,1494,1521,1553,1559,1565,1575,1580,1585,1614,1619,1632,1645,1658,1663,1693,1698,1718,1729,1743,1748,1759,1785,1790,1813,1818,1831,1861,1868,1873,1878,1944,1949,1965,1980,1995,2000,2022,2035,2045,2050,2094,2122,2127,2161,2184,2193,2198,2210,2218,2223,2228,2263,2284,2289,2295,2315,2329,2359,2364,2391,2404,2409,2414,2426,2448,2457,2462,2468,2474,2501,2535,2567,2598,2621,2626,2640,2666,2680,2696,2705,2710,2715,2758,2779,2800,2805,2817,2822,2828,2849,2858,2872,2885,2890,2913,2922,2949,2954,2959,2980,3009,3014,3042,3049,3071,3076,3082,3088,3094,3107,3114,3119,3134,3162,3167,3178,3187,3192,3197,3206,3211],{"__ignoreMap":154},[599,993,994,996],{"class":601,"line":602},[599,995,616],{"class":605},[599,997,998],{"class":619}," \"totp.h\"\n",[599,1000,1001,1003],{"class":601,"line":613},[599,1002,616],{"class":605},[599,1004,1005],{"class":619}," \u003Cbcrypt.h>\n",[599,1007,1008],{"class":601,"line":623},[599,1009,651],{"emptyLinePlaceholder":650},[599,1011,1012,1014,1017,1019,1022,1024,1027],{"class":601,"line":631},[599,1013,606],{"class":605},[599,1015,1016],{"class":609}," comment",[599,1018,679],{"class":666},[599,1020,1021],{"class":609},"lib",[599,1023,212],{"class":666},[599,1025,1026],{"class":619},"\"bcrypt.lib\"",[599,1028,1029],{"class":666},")\n",[599,1031,1032],{"class":601,"line":639},[599,1033,651],{"emptyLinePlaceholder":650},[599,1035,1036,1038],{"class":601,"line":647},[599,1037,657],{"class":605},[599,1039,660],{"class":609},[599,1041,1042],{"class":601,"line":654},[599,1043,667],{"class":666},[599,1045,1046,1049,1052,1055,1058,1061,1064],{"class":601,"line":663},[599,1047,1048],{"class":605},"    static",[599,1050,1051],{"class":605}," const",[599,1053,1054],{"class":605}," char",[599,1056,1057],{"class":666}," kAlphabet[] ",[599,1059,1060],{"class":605},"=",[599,1062,1063],{"class":619}," \"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\"",[599,1065,1066],{"class":666},";\n",[599,1068,1069],{"class":601,"line":670},[599,1070,651],{"emptyLinePlaceholder":650},[599,1072,1073,1075,1078,1081,1083,1086,1089],{"class":601,"line":728},[599,1074,1048],{"class":605},[599,1076,1077],{"class":605}," int",[599,1079,1080],{"class":609}," Base32Value",[599,1082,679],{"class":666},[599,1084,1085],{"class":605},"char",[599,1087,1088],{"class":697}," c",[599,1090,1029],{"class":666},[599,1092,1093],{"class":601,"line":764},[599,1094,1095],{"class":666},"    {\n",[599,1097,1098,1101,1104,1107,1110,1113,1116,1119,1122,1125,1128,1130,1133,1135],{"class":601,"line":769},[599,1099,1100],{"class":605},"        if",[599,1102,1103],{"class":666}," (c ",[599,1105,1106],{"class":605},">=",[599,1108,1109],{"class":619}," 'A'",[599,1111,1112],{"class":605}," &&",[599,1114,1115],{"class":666}," c ",[599,1117,1118],{"class":605},"\u003C=",[599,1120,1121],{"class":619}," 'Z'",[599,1123,1124],{"class":666},") ",[599,1126,1127],{"class":605},"return",[599,1129,1115],{"class":666},[599,1131,1132],{"class":605},"-",[599,1134,1109],{"class":619},[599,1136,1066],{"class":666},[599,1138,1139,1141,1143,1145,1148,1150,1152,1154,1157,1159,1161,1163,1165,1167],{"class":601,"line":776},[599,1140,1100],{"class":605},[599,1142,1103],{"class":666},[599,1144,1106],{"class":605},[599,1146,1147],{"class":619}," 'a'",[599,1149,1112],{"class":605},[599,1151,1115],{"class":666},[599,1153,1118],{"class":605},[599,1155,1156],{"class":619}," 'z'",[599,1158,1124],{"class":666},[599,1160,1127],{"class":605},[599,1162,1115],{"class":666},[599,1164,1132],{"class":605},[599,1166,1147],{"class":619},[599,1168,1066],{"class":666},[599,1170,1171,1173,1175,1177,1180,1182,1184,1186,1189,1191,1193,1195,1197,1199,1202,1205],{"class":601,"line":816},[599,1172,1100],{"class":605},[599,1174,1103],{"class":666},[599,1176,1106],{"class":605},[599,1178,1179],{"class":619}," '2'",[599,1181,1112],{"class":605},[599,1183,1115],{"class":666},[599,1185,1118],{"class":605},[599,1187,1188],{"class":619}," '7'",[599,1190,1124],{"class":666},[599,1192,1127],{"class":605},[599,1194,1115],{"class":666},[599,1196,1132],{"class":605},[599,1198,1179],{"class":619},[599,1200,1201],{"class":605}," +",[599,1203,1204],{"class":949}," 26",[599,1206,1066],{"class":666},[599,1208,1209,1212,1215,1218],{"class":601,"line":843},[599,1210,1211],{"class":605},"        return",[599,1213,1214],{"class":605}," -",[599,1216,1217],{"class":949},"1",[599,1219,1066],{"class":666},[599,1221,1222],{"class":601,"line":848},[599,1223,1224],{"class":666},"    }\n",[599,1226,1227],{"class":601,"line":854},[599,1228,651],{"emptyLinePlaceholder":650},[599,1230,1231,1233,1236,1238,1240,1242,1244,1246,1248,1250,1252,1254,1256,1258,1260,1262,1264,1266,1268],{"class":601,"line":860},[599,1232,673],{"class":605},[599,1234,1235],{"class":609}," Base32Decode",[599,1237,679],{"class":666},[599,1239,682],{"class":605},[599,1241,685],{"class":609},[599,1243,688],{"class":666},[599,1245,691],{"class":609},[599,1247,694],{"class":605},[599,1249,698],{"class":697},[599,1251,212],{"class":666},[599,1253,703],{"class":609},[599,1255,688],{"class":666},[599,1257,708],{"class":609},[599,1259,711],{"class":666},[599,1261,714],{"class":609},[599,1263,717],{"class":666},[599,1265,694],{"class":605},[599,1267,722],{"class":697},[599,1269,1029],{"class":666},[599,1271,1272],{"class":601,"line":866},[599,1273,1095],{"class":666},[599,1275,1276,1279,1282,1284,1287],{"class":601,"line":912},[599,1277,1278],{"class":605},"        uint32_t",[599,1280,1281],{"class":666}," buffer ",[599,1283,1060],{"class":605},[599,1285,1286],{"class":949}," 0",[599,1288,1066],{"class":666},[599,1290,1291,1294,1297,1299,1301],{"class":601,"line":938},[599,1292,1293],{"class":605},"        int",[599,1295,1296],{"class":666}," bits ",[599,1298,1060],{"class":605},[599,1300,1286],{"class":949},[599,1302,1066],{"class":666},[599,1304,1305,1308,1311],{"class":601,"line":978},[599,1306,1307],{"class":666},"        out.",[599,1309,1310],{"class":609},"clear",[599,1312,1313],{"class":666},"();\n",[599,1315,1317],{"class":601,"line":1316},23,[599,1318,651],{"emptyLinePlaceholder":650},[599,1320,1322,1325,1328,1330],{"class":601,"line":1321},24,[599,1323,1324],{"class":605},"        for",[599,1326,1327],{"class":666}," (",[599,1329,1085],{"class":605},[599,1331,1332],{"class":666}," c : in)\n",[599,1334,1336],{"class":601,"line":1335},25,[599,1337,1338],{"class":666},"        {\n",[599,1340,1342,1345,1347,1350,1353,1356,1358,1360,1363],{"class":601,"line":1341},26,[599,1343,1344],{"class":605},"            if",[599,1346,1103],{"class":666},[599,1348,1349],{"class":605},"==",[599,1351,1352],{"class":619}," '='",[599,1354,1355],{"class":605}," ||",[599,1357,1115],{"class":666},[599,1359,1349],{"class":605},[599,1361,1362],{"class":619}," ' '",[599,1364,1029],{"class":666},[599,1366,1368,1371],{"class":601,"line":1367},27,[599,1369,1370],{"class":605},"                continue",[599,1372,1066],{"class":666},[599,1374,1376,1379,1382,1384,1386],{"class":601,"line":1375},28,[599,1377,1378],{"class":605},"            int",[599,1380,1381],{"class":666}," v ",[599,1383,1060],{"class":605},[599,1385,1080],{"class":609},[599,1387,1388],{"class":666},"(c);\n",[599,1390,1392,1394,1397,1399,1401],{"class":601,"line":1391},29,[599,1393,1344],{"class":605},[599,1395,1396],{"class":666}," (v ",[599,1398,711],{"class":605},[599,1400,1286],{"class":949},[599,1402,1029],{"class":666},[599,1404,1406,1409,1412],{"class":601,"line":1405},30,[599,1407,1408],{"class":605},"                return",[599,1410,1411],{"class":949}," false",[599,1413,1066],{"class":666},[599,1415,1417],{"class":601,"line":1416},31,[599,1418,651],{"emptyLinePlaceholder":650},[599,1420,1422,1425,1427,1430,1433,1436,1438,1441,1444],{"class":601,"line":1421},32,[599,1423,1424],{"class":666},"            buffer ",[599,1426,1060],{"class":605},[599,1428,1429],{"class":666}," (buffer ",[599,1431,1432],{"class":605},"\u003C\u003C",[599,1434,1435],{"class":949}," 5",[599,1437,1124],{"class":666},[599,1439,1440],{"class":605},"|",[599,1442,1443],{"class":605}," static_cast\u003Cuint32_t>",[599,1445,1446],{"class":666},"(v);\n",[599,1448,1450,1453,1456,1458],{"class":601,"line":1449},33,[599,1451,1452],{"class":666},"            bits ",[599,1454,1455],{"class":605},"+=",[599,1457,1435],{"class":949},[599,1459,1066],{"class":666},[599,1461,1463,1465,1468,1470,1473],{"class":601,"line":1462},34,[599,1464,1344],{"class":605},[599,1466,1467],{"class":666}," (bits ",[599,1469,1106],{"class":605},[599,1471,1472],{"class":949}," 8",[599,1474,1029],{"class":666},[599,1476,1478],{"class":601,"line":1477},35,[599,1479,1480],{"class":666},"            {\n",[599,1482,1484,1487,1490,1492],{"class":601,"line":1483},36,[599,1485,1486],{"class":666},"                bits ",[599,1488,1489],{"class":605},"-=",[599,1491,1472],{"class":949},[599,1493,1066],{"class":666},[599,1495,1497,1500,1503,1505,1508,1510,1512,1515,1518],{"class":601,"line":1496},37,[599,1498,1499],{"class":666},"                out.",[599,1501,1502],{"class":609},"push_back",[599,1504,679],{"class":666},[599,1506,1507],{"class":605},"static_cast\u003C",[599,1509,714],{"class":666},[599,1511,717],{"class":605},[599,1513,1514],{"class":666},"(buffer ",[599,1516,1517],{"class":605},">>",[599,1519,1520],{"class":666}," bits));\n",[599,1522,1524,1527,1530,1532,1534,1537,1540,1543,1545,1547,1550],{"class":601,"line":1523},38,[599,1525,1526],{"class":666},"                buffer ",[599,1528,1529],{"class":605},"&=",[599,1531,1327],{"class":666},[599,1533,1217],{"class":949},[599,1535,1536],{"class":605},"u",[599,1538,1539],{"class":605}," \u003C\u003C",[599,1541,1542],{"class":666}," bits) ",[599,1544,1132],{"class":605},[599,1546,973],{"class":949},[599,1548,1549],{"class":666},";",[599,1551,1552],{"class":772},"   \u002F\u002F keep only the bits not consumed yet\n",[599,1554,1556],{"class":601,"line":1555},39,[599,1557,1558],{"class":666},"            }\n",[599,1560,1562],{"class":601,"line":1561},40,[599,1563,1564],{"class":666},"        }\n",[599,1566,1568,1570,1573],{"class":601,"line":1567},41,[599,1569,1211],{"class":605},[599,1571,1572],{"class":949}," true",[599,1574,1066],{"class":666},[599,1576,1578],{"class":601,"line":1577},42,[599,1579,1224],{"class":666},[599,1581,1583],{"class":601,"line":1582},43,[599,1584,651],{"emptyLinePlaceholder":650},[599,1586,1588,1590,1592,1594,1596,1598,1600,1602,1604,1606,1608,1610,1612],{"class":601,"line":1587},44,[599,1589,731],{"class":609},[599,1591,688],{"class":666},[599,1593,691],{"class":609},[599,1595,738],{"class":609},[599,1597,679],{"class":666},[599,1599,682],{"class":605},[599,1601,745],{"class":609},[599,1603,748],{"class":605},[599,1605,751],{"class":697},[599,1607,212],{"class":666},[599,1609,756],{"class":605},[599,1611,759],{"class":697},[599,1613,1029],{"class":666},[599,1615,1617],{"class":601,"line":1616},45,[599,1618,1095],{"class":666},[599,1620,1622,1625,1627,1629],{"class":601,"line":1621},46,[599,1623,1624],{"class":609},"        std",[599,1626,688],{"class":666},[599,1628,691],{"class":609},[599,1630,1631],{"class":666}," out;\n",[599,1633,1635,1637,1639,1641,1643],{"class":601,"line":1634},47,[599,1636,1278],{"class":605},[599,1638,1281],{"class":666},[599,1640,1060],{"class":605},[599,1642,1286],{"class":949},[599,1644,1066],{"class":666},[599,1646,1648,1650,1652,1654,1656],{"class":601,"line":1647},48,[599,1649,1293],{"class":605},[599,1651,1296],{"class":666},[599,1653,1060],{"class":605},[599,1655,1286],{"class":949},[599,1657,1066],{"class":666},[599,1659,1661],{"class":601,"line":1660},49,[599,1662,651],{"emptyLinePlaceholder":650},[599,1664,1666,1668,1670,1672,1675,1677,1679,1682,1684,1687,1690],{"class":601,"line":1665},50,[599,1667,1324],{"class":605},[599,1669,1327],{"class":666},[599,1671,756],{"class":605},[599,1673,1674],{"class":666}," i ",[599,1676,1060],{"class":605},[599,1678,1286],{"class":949},[599,1680,1681],{"class":666},"; i ",[599,1683,711],{"class":605},[599,1685,1686],{"class":666}," len; ",[599,1688,1689],{"class":605},"++",[599,1691,1692],{"class":666},"i)\n",[599,1694,1696],{"class":601,"line":1695},51,[599,1697,1338],{"class":666},[599,1699,1701,1703,1705,1707,1709,1711,1713,1715],{"class":601,"line":1700},52,[599,1702,1424],{"class":666},[599,1704,1060],{"class":605},[599,1706,1429],{"class":666},[599,1708,1432],{"class":605},[599,1710,1472],{"class":949},[599,1712,1124],{"class":666},[599,1714,1440],{"class":605},[599,1716,1717],{"class":666}," data[i];\n",[599,1719,1721,1723,1725,1727],{"class":601,"line":1720},53,[599,1722,1452],{"class":666},[599,1724,1455],{"class":605},[599,1726,1472],{"class":949},[599,1728,1066],{"class":666},[599,1730,1732,1735,1737,1739,1741],{"class":601,"line":1731},54,[599,1733,1734],{"class":605},"            while",[599,1736,1467],{"class":666},[599,1738,1106],{"class":605},[599,1740,1435],{"class":949},[599,1742,1029],{"class":666},[599,1744,1746],{"class":601,"line":1745},55,[599,1747,1480],{"class":666},[599,1749,1751,1753,1755,1757],{"class":601,"line":1750},56,[599,1752,1486],{"class":666},[599,1754,1489],{"class":605},[599,1756,1435],{"class":949},[599,1758,1066],{"class":666},[599,1760,1762,1765,1767,1770,1772,1774,1776,1779,1782],{"class":601,"line":1761},57,[599,1763,1764],{"class":666},"                out ",[599,1766,1455],{"class":605},[599,1768,1769],{"class":666}," kAlphabet[(buffer ",[599,1771,1517],{"class":605},[599,1773,1542],{"class":666},[599,1775,694],{"class":605},[599,1777,1778],{"class":605}," 0x",[599,1780,1781],{"class":949},"1F",[599,1783,1784],{"class":666},"];\n",[599,1786,1788],{"class":601,"line":1787},58,[599,1789,1558],{"class":666},[599,1791,1793,1795,1797,1799,1801,1803,1805,1807,1809,1811],{"class":601,"line":1792},59,[599,1794,1424],{"class":666},[599,1796,1529],{"class":605},[599,1798,1327],{"class":666},[599,1800,1217],{"class":949},[599,1802,1536],{"class":605},[599,1804,1539],{"class":605},[599,1806,1542],{"class":666},[599,1808,1132],{"class":605},[599,1810,973],{"class":949},[599,1812,1066],{"class":666},[599,1814,1816],{"class":601,"line":1815},60,[599,1817,1564],{"class":666},[599,1819,1821,1823,1825,1827,1829],{"class":601,"line":1820},61,[599,1822,1100],{"class":605},[599,1824,1467],{"class":666},[599,1826,717],{"class":605},[599,1828,1286],{"class":949},[599,1830,1029],{"class":666},[599,1832,1834,1837,1839,1841,1843,1845,1848,1850,1853,1855,1857,1859],{"class":601,"line":1833},62,[599,1835,1836],{"class":666},"            out ",[599,1838,1455],{"class":605},[599,1840,1769],{"class":666},[599,1842,1432],{"class":605},[599,1844,1327],{"class":666},[599,1846,1847],{"class":949},"5",[599,1849,1214],{"class":605},[599,1851,1852],{"class":666}," bits)) ",[599,1854,694],{"class":605},[599,1856,1778],{"class":605},[599,1858,1781],{"class":949},[599,1860,1784],{"class":666},[599,1862,1864,1866],{"class":601,"line":1863},63,[599,1865,1211],{"class":605},[599,1867,1631],{"class":666},[599,1869,1871],{"class":601,"line":1870},64,[599,1872,1224],{"class":666},[599,1874,1876],{"class":601,"line":1875},65,[599,1877,651],{"emptyLinePlaceholder":650},[599,1879,1881,1883,1886,1889,1891,1893,1895,1897,1899,1901,1903,1905,1907,1909,1911,1913,1915,1917,1920,1922,1925,1928,1930,1932,1935,1938,1941],{"class":601,"line":1880},66,[599,1882,1048],{"class":605},[599,1884,1885],{"class":605}," bool",[599,1887,1888],{"class":609}," HmacSha1",[599,1890,679],{"class":666},[599,1892,682],{"class":605},[599,1894,685],{"class":609},[599,1896,688],{"class":666},[599,1898,708],{"class":609},[599,1900,711],{"class":666},[599,1902,714],{"class":609},[599,1904,717],{"class":666},[599,1906,694],{"class":605},[599,1908,802],{"class":697},[599,1910,212],{"class":666},[599,1912,682],{"class":605},[599,1914,745],{"class":609},[599,1916,748],{"class":605},[599,1918,1919],{"class":697}," msg",[599,1921,212],{"class":666},[599,1923,1924],{"class":609},"ULONG",[599,1926,1927],{"class":697}," cbMsg",[599,1929,212],{"class":666},[599,1931,714],{"class":609},[599,1933,1934],{"class":697}," mac",[599,1936,1937],{"class":666},"[",[599,1939,1940],{"class":949},"20",[599,1942,1943],{"class":666},"])\n",[599,1945,1947],{"class":601,"line":1946},67,[599,1948,1095],{"class":666},[599,1950,1952,1955,1958,1960,1963],{"class":601,"line":1951},68,[599,1953,1954],{"class":609},"        BCRYPT_ALG_HANDLE",[599,1956,1957],{"class":666},"  hAlg  ",[599,1959,1060],{"class":605},[599,1961,1962],{"class":949}," nullptr",[599,1964,1066],{"class":666},[599,1966,1968,1971,1974,1976,1978],{"class":601,"line":1967},69,[599,1969,1970],{"class":609},"        BCRYPT_HASH_HANDLE",[599,1972,1973],{"class":666}," hHash ",[599,1975,1060],{"class":605},[599,1977,1962],{"class":949},[599,1979,1066],{"class":666},[599,1981,1983,1986,1989,1991,1993],{"class":601,"line":1982},70,[599,1984,1985],{"class":605},"        bool",[599,1987,1988],{"class":666}," ok ",[599,1990,1060],{"class":605},[599,1992,1411],{"class":949},[599,1994,1066],{"class":666},[599,1996,1998],{"class":601,"line":1997},71,[599,1999,651],{"emptyLinePlaceholder":650},[599,2001,2003,2005,2007,2010,2012,2014,2017,2020],{"class":601,"line":2002},72,[599,2004,1100],{"class":605},[599,2006,1327],{"class":666},[599,2008,2009],{"class":609},"BCryptOpenAlgorithmProvider",[599,2011,679],{"class":666},[599,2013,694],{"class":605},[599,2015,2016],{"class":666},"hAlg, BCRYPT_SHA1_ALGORITHM, ",[599,2018,2019],{"class":949},"nullptr",[599,2021,813],{"class":666},[599,2023,2025,2028,2031,2033],{"class":601,"line":2024},73,[599,2026,2027],{"class":666},"                                        BCRYPT_ALG_HANDLE_HMAC_FLAG) ",[599,2029,2030],{"class":605},"!=",[599,2032,1286],{"class":949},[599,2034,1029],{"class":666},[599,2036,2038,2041,2043],{"class":601,"line":2037},74,[599,2039,2040],{"class":605},"            return",[599,2042,1411],{"class":949},[599,2044,1066],{"class":666},[599,2046,2048],{"class":601,"line":2047},75,[599,2049,651],{"emptyLinePlaceholder":650},[599,2051,2053,2055,2057,2060,2063,2065,2068,2070,2072,2075,2077,2080,2083,2085,2088,2091],{"class":601,"line":2052},76,[599,2054,1100],{"class":605},[599,2056,1327],{"class":666},[599,2058,2059],{"class":609},"BCryptCreateHash",[599,2061,2062],{"class":666},"(hAlg, ",[599,2064,694],{"class":605},[599,2066,2067],{"class":666},"hHash, ",[599,2069,2019],{"class":949},[599,2071,212],{"class":666},[599,2073,2074],{"class":949},"0",[599,2076,212],{"class":666},[599,2078,2079],{"class":605},"const_cast\u003C",[599,2081,2082],{"class":666},"PUCHAR",[599,2084,717],{"class":605},[599,2086,2087],{"class":666},"(key.",[599,2089,2090],{"class":609},"data",[599,2092,2093],{"class":666},"()),\n",[599,2095,2097,2100,2102,2104,2106,2109,2112,2114,2116,2118,2120],{"class":601,"line":2096},77,[599,2098,2099],{"class":605},"                             static_cast\u003C",[599,2101,1924],{"class":666},[599,2103,717],{"class":605},[599,2105,2087],{"class":666},[599,2107,2108],{"class":609},"size",[599,2110,2111],{"class":666},"()), ",[599,2113,2074],{"class":949},[599,2115,1124],{"class":666},[599,2117,1349],{"class":605},[599,2119,1286],{"class":949},[599,2121,1029],{"class":666},[599,2123,2125],{"class":601,"line":2124},78,[599,2126,1338],{"class":666},[599,2128,2130,2133,2135,2138,2141,2143,2145,2147,2150,2152,2154,2156,2158],{"class":601,"line":2129},79,[599,2131,2132],{"class":666},"            ok ",[599,2134,1060],{"class":605},[599,2136,2137],{"class":609}," BCryptHashData",[599,2139,2140],{"class":666},"(hHash, ",[599,2142,2079],{"class":605},[599,2144,2082],{"class":666},[599,2146,717],{"class":605},[599,2148,2149],{"class":666},"(msg), cbMsg, ",[599,2151,2074],{"class":949},[599,2153,1124],{"class":666},[599,2155,1349],{"class":605},[599,2157,1286],{"class":949},[599,2159,2160],{"class":605}," &&\n",[599,2162,2164,2167,2170,2172,2174,2176,2178,2180,2182],{"class":601,"line":2163},80,[599,2165,2166],{"class":609},"                 BCryptFinishHash",[599,2168,2169],{"class":666},"(hHash, mac, ",[599,2171,1940],{"class":949},[599,2173,212],{"class":666},[599,2175,2074],{"class":949},[599,2177,1124],{"class":666},[599,2179,1349],{"class":605},[599,2181,1286],{"class":949},[599,2183,1066],{"class":666},[599,2185,2187,2190],{"class":601,"line":2186},81,[599,2188,2189],{"class":609},"            BCryptDestroyHash",[599,2191,2192],{"class":666},"(hHash);\n",[599,2194,2196],{"class":601,"line":2195},82,[599,2197,1564],{"class":666},[599,2199,2201,2204,2206,2208],{"class":601,"line":2200},83,[599,2202,2203],{"class":609},"        BCryptCloseAlgorithmProvider",[599,2205,2062],{"class":666},[599,2207,2074],{"class":949},[599,2209,725],{"class":666},[599,2211,2213,2215],{"class":601,"line":2212},84,[599,2214,1211],{"class":605},[599,2216,2217],{"class":666}," ok;\n",[599,2219,2221],{"class":601,"line":2220},85,[599,2222,1224],{"class":666},[599,2224,2226],{"class":601,"line":2225},86,[599,2227,651],{"emptyLinePlaceholder":650},[599,2229,2231,2233,2235,2237,2239,2241,2243,2245,2247,2249,2251,2253,2255,2257,2259,2261],{"class":601,"line":2230},87,[599,2232,673],{"class":605},[599,2234,781],{"class":609},[599,2236,679],{"class":666},[599,2238,682],{"class":605},[599,2240,685],{"class":609},[599,2242,688],{"class":666},[599,2244,708],{"class":609},[599,2246,711],{"class":666},[599,2248,714],{"class":609},[599,2250,717],{"class":666},[599,2252,694],{"class":605},[599,2254,802],{"class":697},[599,2256,212],{"class":666},[599,2258,807],{"class":605},[599,2260,810],{"class":697},[599,2262,813],{"class":666},[599,2264,2266,2268,2270,2272,2274,2276,2278,2280,2282],{"class":601,"line":2265},88,[599,2267,819],{"class":605},[599,2269,822],{"class":697},[599,2271,212],{"class":666},[599,2273,827],{"class":605},[599,2275,830],{"class":697},[599,2277,212],{"class":666},[599,2279,835],{"class":605},[599,2281,838],{"class":697},[599,2283,1029],{"class":666},[599,2285,2287],{"class":601,"line":2286},89,[599,2288,1095],{"class":666},[599,2290,2292],{"class":601,"line":2291},90,[599,2293,2294],{"class":772},"        \u002F\u002F The counter is the number of time steps since 1970, as 8 bytes big-endian.\n",[599,2296,2298,2301,2304,2306,2309,2312],{"class":601,"line":2297},91,[599,2299,2300],{"class":605},"        uint64_t",[599,2302,2303],{"class":666}," counter ",[599,2305,1060],{"class":605},[599,2307,2308],{"class":666}," unixTime ",[599,2310,2311],{"class":605},"\u002F",[599,2313,2314],{"class":666}," step;\n",[599,2316,2318,2321,2324,2327],{"class":601,"line":2317},92,[599,2319,2320],{"class":609},"        BYTE",[599,2322,2323],{"class":666}," msg[",[599,2325,2326],{"class":949},"8",[599,2328,1784],{"class":666},[599,2330,2332,2334,2336,2338,2340,2342,2345,2347,2349,2351,2354,2357],{"class":601,"line":2331},93,[599,2333,1324],{"class":605},[599,2335,1327],{"class":666},[599,2337,827],{"class":605},[599,2339,1674],{"class":666},[599,2341,1060],{"class":605},[599,2343,2344],{"class":949}," 7",[599,2346,1681],{"class":666},[599,2348,1106],{"class":605},[599,2350,1286],{"class":949},[599,2352,2353],{"class":666},"; ",[599,2355,2356],{"class":605},"--",[599,2358,1692],{"class":666},[599,2360,2362],{"class":601,"line":2361},94,[599,2363,1338],{"class":666},[599,2365,2367,2370,2372,2375,2377,2379,2382,2384,2386,2389],{"class":601,"line":2366},95,[599,2368,2369],{"class":666},"            msg[i] ",[599,2371,1060],{"class":605},[599,2373,2374],{"class":605}," static_cast\u003C",[599,2376,714],{"class":666},[599,2378,717],{"class":605},[599,2380,2381],{"class":666},"(counter ",[599,2383,694],{"class":605},[599,2385,1778],{"class":605},[599,2387,2388],{"class":949},"FF",[599,2390,725],{"class":666},[599,2392,2394,2397,2400,2402],{"class":601,"line":2393},96,[599,2395,2396],{"class":666},"            counter ",[599,2398,2399],{"class":605},">>=",[599,2401,1472],{"class":949},[599,2403,1066],{"class":666},[599,2405,2407],{"class":601,"line":2406},97,[599,2408,1564],{"class":666},[599,2410,2412],{"class":601,"line":2411},98,[599,2413,651],{"emptyLinePlaceholder":650},[599,2415,2417,2419,2422,2424],{"class":601,"line":2416},99,[599,2418,2320],{"class":609},[599,2420,2421],{"class":666}," mac[",[599,2423,1940],{"class":949},[599,2425,1784],{"class":666},[599,2427,2429,2431,2433,2436,2439,2442,2445],{"class":601,"line":2428},100,[599,2430,1100],{"class":605},[599,2432,1327],{"class":666},[599,2434,2435],{"class":605},"!",[599,2437,2438],{"class":609},"HmacSha1",[599,2440,2441],{"class":666},"(key, msg, ",[599,2443,2444],{"class":605},"sizeof",[599,2446,2447],{"class":666},"(msg), mac))\n",[599,2449,2451,2453,2455],{"class":601,"line":2450},101,[599,2452,2040],{"class":605},[599,2454,1411],{"class":949},[599,2456,1066],{"class":666},[599,2458,2460],{"class":601,"line":2459},102,[599,2461,651],{"emptyLinePlaceholder":650},[599,2463,2465],{"class":601,"line":2464},103,[599,2466,2467],{"class":772},"        \u002F\u002F Dynamic truncation (RFC 4226, 5.3): the low nibble of the last byte\n",[599,2469,2471],{"class":601,"line":2470},104,[599,2472,2473],{"class":772},"        \u002F\u002F selects 4 bytes; the top bit is dropped to avoid signed values.\n",[599,2475,2477,2479,2482,2484,2486,2489,2492,2494,2496,2499],{"class":601,"line":2476},105,[599,2478,1293],{"class":605},[599,2480,2481],{"class":666}," offset ",[599,2483,1060],{"class":605},[599,2485,2421],{"class":666},[599,2487,2488],{"class":949},"19",[599,2490,2491],{"class":666},"] ",[599,2493,694],{"class":605},[599,2495,1778],{"class":605},[599,2497,2498],{"class":949},"0F",[599,2500,1066],{"class":666},[599,2502,2504,2506,2509,2511,2514,2516,2518,2521,2523,2525,2527,2530,2532],{"class":601,"line":2503},106,[599,2505,1278],{"class":605},[599,2507,2508],{"class":666}," bin ",[599,2510,1060],{"class":605},[599,2512,2513],{"class":666}," ((mac[offset]     ",[599,2515,694],{"class":605},[599,2517,1778],{"class":605},[599,2519,2520],{"class":949},"7F",[599,2522,1536],{"class":605},[599,2524,1124],{"class":666},[599,2526,1432],{"class":605},[599,2528,2529],{"class":949}," 24",[599,2531,1124],{"class":666},[599,2533,2534],{"class":605},"|\n",[599,2536,2538,2541,2544,2546,2548,2550,2552,2554,2556,2558,2560,2563,2565],{"class":601,"line":2537},107,[599,2539,2540],{"class":666},"                       ((mac[offset ",[599,2542,2543],{"class":605},"+",[599,2545,973],{"class":949},[599,2547,2491],{"class":666},[599,2549,694],{"class":605},[599,2551,1778],{"class":605},[599,2553,2388],{"class":949},[599,2555,1536],{"class":605},[599,2557,1124],{"class":666},[599,2559,1432],{"class":605},[599,2561,2562],{"class":949}," 16",[599,2564,1124],{"class":666},[599,2566,2534],{"class":605},[599,2568,2570,2572,2574,2577,2579,2581,2583,2585,2587,2589,2591,2594,2596],{"class":601,"line":2569},108,[599,2571,2540],{"class":666},[599,2573,2543],{"class":605},[599,2575,2576],{"class":949}," 2",[599,2578,2491],{"class":666},[599,2580,694],{"class":605},[599,2582,1778],{"class":605},[599,2584,2388],{"class":949},[599,2586,1536],{"class":605},[599,2588,1124],{"class":666},[599,2590,1432],{"class":605},[599,2592,2593],{"class":949},"  8",[599,2595,1124],{"class":666},[599,2597,2534],{"class":605},[599,2599,2601,2604,2606,2609,2611,2613,2615,2617,2619],{"class":601,"line":2600},109,[599,2602,2603],{"class":666},"                        (mac[offset ",[599,2605,2543],{"class":605},[599,2607,2608],{"class":949}," 3",[599,2610,2491],{"class":666},[599,2612,694],{"class":605},[599,2614,1778],{"class":605},[599,2616,2388],{"class":949},[599,2618,1536],{"class":605},[599,2620,725],{"class":666},[599,2622,2624],{"class":601,"line":2623},110,[599,2625,651],{"emptyLinePlaceholder":650},[599,2627,2629,2631,2634,2636,2638],{"class":601,"line":2628},111,[599,2630,1278],{"class":605},[599,2632,2633],{"class":666}," mod ",[599,2635,1060],{"class":605},[599,2637,973],{"class":949},[599,2639,1066],{"class":666},[599,2641,2643,2645,2647,2649,2651,2653,2655,2657,2659,2662,2664],{"class":601,"line":2642},112,[599,2644,1324],{"class":605},[599,2646,1327],{"class":666},[599,2648,827],{"class":605},[599,2650,1674],{"class":666},[599,2652,1060],{"class":605},[599,2654,1286],{"class":949},[599,2656,1681],{"class":666},[599,2658,711],{"class":605},[599,2660,2661],{"class":666}," digits; ",[599,2663,1689],{"class":605},[599,2665,1692],{"class":666},[599,2667,2669,2672,2675,2678],{"class":601,"line":2668},113,[599,2670,2671],{"class":666},"            mod ",[599,2673,2674],{"class":605},"*=",[599,2676,2677],{"class":949}," 10",[599,2679,1066],{"class":666},[599,2681,2683,2686,2688,2690,2693],{"class":601,"line":2682},114,[599,2684,2685],{"class":666},"        code ",[599,2687,1060],{"class":605},[599,2689,2508],{"class":666},[599,2691,2692],{"class":605},"%",[599,2694,2695],{"class":666}," mod;\n",[599,2697,2699,2701,2703],{"class":601,"line":2698},115,[599,2700,1211],{"class":605},[599,2702,1572],{"class":949},[599,2704,1066],{"class":666},[599,2706,2708],{"class":601,"line":2707},116,[599,2709,1224],{"class":666},[599,2711,2713],{"class":601,"line":2712},117,[599,2714,651],{"emptyLinePlaceholder":650},[599,2716,2718,2720,2722,2724,2726,2728,2730,2732,2734,2736,2738,2740,2742,2744,2746,2748,2750,2752,2754,2756],{"class":601,"line":2717},118,[599,2719,673],{"class":605},[599,2721,871],{"class":609},[599,2723,679],{"class":666},[599,2725,682],{"class":605},[599,2727,685],{"class":609},[599,2729,688],{"class":666},[599,2731,708],{"class":609},[599,2733,711],{"class":666},[599,2735,714],{"class":609},[599,2737,717],{"class":666},[599,2739,694],{"class":605},[599,2741,802],{"class":697},[599,2743,212],{"class":666},[599,2745,682],{"class":605},[599,2747,685],{"class":609},[599,2749,688],{"class":666},[599,2751,902],{"class":609},[599,2753,694],{"class":605},[599,2755,907],{"class":697},[599,2757,813],{"class":666},[599,2759,2761,2763,2765,2767,2769,2771,2773,2775,2777],{"class":601,"line":2760},119,[599,2762,915],{"class":605},[599,2764,918],{"class":697},[599,2766,212],{"class":666},[599,2768,807],{"class":605},[599,2770,925],{"class":697},[599,2772,212],{"class":666},[599,2774,930],{"class":605},[599,2776,933],{"class":697},[599,2778,813],{"class":666},[599,2780,2782,2784,2786,2788,2790,2792,2794,2796,2798],{"class":601,"line":2781},120,[599,2783,941],{"class":605},[599,2785,822],{"class":697},[599,2787,212],{"class":666},[599,2789,827],{"class":605},[599,2791,830],{"class":697},[599,2793,212],{"class":666},[599,2795,827],{"class":605},[599,2797,968],{"class":697},[599,2799,1029],{"class":666},[599,2801,2803],{"class":601,"line":2802},121,[599,2804,1095],{"class":666},[599,2806,2808,2811,2813,2815],{"class":601,"line":2807},122,[599,2809,2810],{"class":666},"        matchedStep ",[599,2812,1060],{"class":605},[599,2814,1286],{"class":949},[599,2816,1066],{"class":666},[599,2818,2820],{"class":601,"line":2819},123,[599,2821,651],{"emptyLinePlaceholder":650},[599,2823,2825],{"class":601,"line":2824},124,[599,2826,2827],{"class":772},"        \u002F\u002F Exactly `digits` ASCII digits. wcstoul would also accept \"12abc\" or \"0\".\n",[599,2829,2831,2833,2836,2838,2841,2843,2846],{"class":601,"line":2830},125,[599,2832,1100],{"class":605},[599,2834,2835],{"class":666}," (input.",[599,2837,2108],{"class":609},[599,2839,2840],{"class":666},"() ",[599,2842,2030],{"class":605},[599,2844,2845],{"class":605}," static_cast\u003Csize_t>",[599,2847,2848],{"class":666},"(digits))\n",[599,2850,2852,2854,2856],{"class":601,"line":2851},126,[599,2853,2040],{"class":605},[599,2855,1411],{"class":949},[599,2857,1066],{"class":666},[599,2859,2861,2863,2866,2868,2870],{"class":601,"line":2860},127,[599,2862,1278],{"class":605},[599,2864,2865],{"class":666}," entered ",[599,2867,1060],{"class":605},[599,2869,1286],{"class":949},[599,2871,1066],{"class":666},[599,2873,2875,2877,2879,2882],{"class":601,"line":2874},128,[599,2876,1324],{"class":605},[599,2878,1327],{"class":666},[599,2880,2881],{"class":605},"wchar_t",[599,2883,2884],{"class":666}," c : input)\n",[599,2886,2888],{"class":601,"line":2887},129,[599,2889,1338],{"class":666},[599,2891,2893,2895,2897,2899,2902,2904,2906,2908,2911],{"class":601,"line":2892},130,[599,2894,1344],{"class":605},[599,2896,1103],{"class":666},[599,2898,711],{"class":605},[599,2900,2901],{"class":619}," L'0'",[599,2903,1355],{"class":605},[599,2905,1115],{"class":666},[599,2907,717],{"class":605},[599,2909,2910],{"class":619}," L'9'",[599,2912,1029],{"class":666},[599,2914,2916,2918,2920],{"class":601,"line":2915},131,[599,2917,1408],{"class":605},[599,2919,1411],{"class":949},[599,2921,1066],{"class":666},[599,2923,2925,2928,2930,2932,2934,2936,2938,2940,2943,2945,2947],{"class":601,"line":2924},132,[599,2926,2927],{"class":666},"            entered ",[599,2929,1060],{"class":605},[599,2931,2865],{"class":666},[599,2933,748],{"class":605},[599,2935,2677],{"class":949},[599,2937,1201],{"class":605},[599,2939,1443],{"class":605},[599,2941,2942],{"class":666},"(c ",[599,2944,1132],{"class":605},[599,2946,2901],{"class":619},[599,2948,725],{"class":666},[599,2950,2952],{"class":601,"line":2951},133,[599,2953,1564],{"class":666},[599,2955,2957],{"class":601,"line":2956},134,[599,2958,651],{"emptyLinePlaceholder":650},[599,2960,2962,2965,2968,2971,2973,2976,2978],{"class":601,"line":2961},135,[599,2963,2964],{"class":605},"        const",[599,2966,2967],{"class":605}," uint64_t",[599,2969,2970],{"class":666}," current ",[599,2972,1060],{"class":605},[599,2974,2975],{"class":666}," now ",[599,2977,2311],{"class":605},[599,2979,2314],{"class":666},[599,2981,2983,2985,2987,2989,2992,2994,2996,2999,3001,3004,3006],{"class":601,"line":2982},136,[599,2984,1324],{"class":605},[599,2986,1327],{"class":666},[599,2988,827],{"class":605},[599,2990,2991],{"class":666}," w ",[599,2993,1060],{"class":605},[599,2995,1214],{"class":605},[599,2997,2998],{"class":666},"window; w ",[599,3000,1118],{"class":605},[599,3002,3003],{"class":666}," window; ",[599,3005,1689],{"class":605},[599,3007,3008],{"class":666},"w)\n",[599,3010,3012],{"class":601,"line":3011},137,[599,3013,1338],{"class":666},[599,3015,3017,3019,3022,3024,3026,3028,3030,3032,3035,3037,3039],{"class":601,"line":3016},138,[599,3018,1344],{"class":605},[599,3020,3021],{"class":666}," (w ",[599,3023,711],{"class":605},[599,3025,1286],{"class":949},[599,3027,1112],{"class":605},[599,3029,2970],{"class":666},[599,3031,711],{"class":605},[599,3033,3034],{"class":605}," static_cast\u003Cuint64_t>",[599,3036,679],{"class":666},[599,3038,1132],{"class":605},[599,3040,3041],{"class":666},"w))\n",[599,3043,3045,3047],{"class":601,"line":3044},139,[599,3046,1370],{"class":605},[599,3048,1066],{"class":666},[599,3050,3052,3055,3057,3059,3061,3063,3065,3068],{"class":601,"line":3051},140,[599,3053,3054],{"class":605},"            const",[599,3056,2967],{"class":605},[599,3058,2303],{"class":666},[599,3060,1060],{"class":605},[599,3062,2970],{"class":666},[599,3064,2543],{"class":605},[599,3066,3067],{"class":605}," static_cast\u003Cint64_t>",[599,3069,3070],{"class":666},"(w);\n",[599,3072,3074],{"class":601,"line":3073},141,[599,3075,651],{"emptyLinePlaceholder":650},[599,3077,3079],{"class":601,"line":3078},142,[599,3080,3081],{"class":772},"            \u002F\u002F \"\u003C=\" and not \"==\": a step at or before the last used one is never\n",[599,3083,3085],{"class":601,"line":3084},143,[599,3086,3087],{"class":772},"            \u002F\u002F accepted again. This also stops an old code after the clock was\n",[599,3089,3091],{"class":601,"line":3090},144,[599,3092,3093],{"class":772},"            \u002F\u002F turned back.\n",[599,3095,3097,3099,3102,3104],{"class":601,"line":3096},145,[599,3098,1344],{"class":605},[599,3100,3101],{"class":666}," (counter ",[599,3103,1118],{"class":605},[599,3105,3106],{"class":666}," lastStep)\n",[599,3108,3110,3112],{"class":601,"line":3109},146,[599,3111,1370],{"class":605},[599,3113,1066],{"class":666},[599,3115,3117],{"class":601,"line":3116},147,[599,3118,651],{"emptyLinePlaceholder":650},[599,3120,3122,3125,3128,3130,3132],{"class":601,"line":3121},148,[599,3123,3124],{"class":605},"            uint32_t",[599,3126,3127],{"class":666}," expected ",[599,3129,1060],{"class":605},[599,3131,1286],{"class":949},[599,3133,1066],{"class":666},[599,3135,3137,3139,3141,3144,3147,3149,3152,3155,3157,3159],{"class":601,"line":3136},149,[599,3138,1344],{"class":605},[599,3140,1327],{"class":666},[599,3142,3143],{"class":609},"TotpAt",[599,3145,3146],{"class":666},"(key, counter ",[599,3148,748],{"class":605},[599,3150,3151],{"class":666}," step, step, digits, expected) ",[599,3153,3154],{"class":605},"&&",[599,3156,3127],{"class":666},[599,3158,1349],{"class":605},[599,3160,3161],{"class":666}," entered)\n",[599,3163,3165],{"class":601,"line":3164},150,[599,3166,1480],{"class":666},[599,3168,3170,3173,3175],{"class":601,"line":3169},151,[599,3171,3172],{"class":666},"                matchedStep ",[599,3174,1060],{"class":605},[599,3176,3177],{"class":666}," counter;\n",[599,3179,3181,3183,3185],{"class":601,"line":3180},152,[599,3182,1408],{"class":605},[599,3184,1572],{"class":949},[599,3186,1066],{"class":666},[599,3188,3190],{"class":601,"line":3189},153,[599,3191,1558],{"class":666},[599,3193,3195],{"class":601,"line":3194},154,[599,3196,1564],{"class":666},[599,3198,3200,3202,3204],{"class":601,"line":3199},155,[599,3201,1211],{"class":605},[599,3203,1411],{"class":949},[599,3205,1066],{"class":666},[599,3207,3209],{"class":601,"line":3208},156,[599,3210,1224],{"class":666},[599,3212,3214],{"class":601,"line":3213},157,[599,3215,981],{"class":666},[15,3217,3218],{},"Some things I want to point out:",[56,3220,3221,3243,3252],{},[59,3222,3223,3226,3227,3230,3231,3234,3235,3238,3239,3242],{},[69,3224,3225],{},"ValidateTotp"," only accepts exactly 6 digits. A function like ",[69,3228,3229],{},"wcstoul"," would also accept ",[69,3232,3233],{},"\"12abc\""," or just ",[69,3236,3237],{},"\"0\"",", which would match the code ",[69,3240,3241],{},"000000",".",[59,3244,3245,3247,3248,3251],{},[69,3246,3143],{}," returns ",[69,3249,3250],{},"bool"," and the code via an out parameter. My first version returned a special value on error. The problem is that a user could type exactly this value, and then a failed HMAC would look like a correct code. So don't use a normal value as an error value.",[59,3253,3254,3255,3257],{},"The Base32 buffers are unsigned and masked. Without the mask a signed ",[69,3256,827],{}," overflows with a 32 character secret and that is undefined behavior.",[15,3259,3260],{},"The code accepts one step before and after the current time. This is for clocks that are not exactly in sync. In total a code is valid for about 90 seconds.",[15,3262,3263,3266,3267,3269,3270,3273,3274,3276],{},[47,3264,3265],{},"A code works only once."," 90 seconds is a lot of time. Someone who looks over your shoulder can type the same code on another machine, or on the same machine right after you locked it. That's why ",[69,3268,3225],{}," gets ",[69,3271,3272],{},"lastStep",": the time step of the last code that was accepted for this user. Every step up to and including ",[69,3275,3272],{}," is skipped.",[15,3278,3279,3280,3282,3283,3285,3286,3288,3289,3293,3294,3296],{},"It is important that the check is ",[69,3281,1118],{}," and not ",[69,3284,1349],{},". With ",[69,3287,1349],{}," only the exact same code would be blocked. The code of the step before is still inside the window and would work. And there is a nastier attack: someone writes down your code, later turns the clock back in the BIOS, pulls the network cable so Windows can't sync the time, boots and types the old code. For TOTP the clock of the machine ",[3290,3291,3292],"em",{},"is"," the truth. With ",[69,3295,1118],{}," this doesn't work anymore, because the old step is smaller than the one that was already used.",[15,3298,3299,3301,3302,3305],{},[69,3300,3225],{}," also returns the step that matched (",[69,3303,3304],{},"matchedStep","). This is the value that gets stored, not the current time. If the clocks are a bit off and the code of the next step is used, exactly this step is stored.",[15,3307,3308,3311,3312,3315],{},[69,3309,3310],{},"now"," is a parameter now instead of calling ",[69,3313,3314],{},"time()"," inside the function. This makes the function testable. I can check any point in time without touching the clock.",[15,3317,3318,3319,3321],{},"Where ",[69,3320,3272],{}," is stored and who writes it comes in the chapter about rate limiting.",[126,3323,3325],{"id":3324},"test-the-totp-code-first","Test the TOTP code first",[15,3327,3328],{},"Debugging crypto on the logon screen is no fun. So I tested the algorithm first. This Python script does exactly the same as the C++ code and checks it against the official test values from RFC 6238:",[148,3330,3334],{"className":3331,"code":3332,"language":3333,"meta":154,"style":154},"language-python shiki shiki-themes github-dark","import hmac, hashlib, struct\n\nBASE32=\"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\"\n\n# --- faithful port of my C++ Base32Encode ---\ndef b32enc(data):\n    out=\"\"; buf=0; bits=0\n    for b in data:\n        buf=(buf\u003C\u003C8)|b; bits+=8\n        while bits>=5:\n            bits-=5; out+=BASE32[(buf>>bits)&0x1F]\n        buf &= (1\u003C\u003Cbits)-1\n    if bits>0: out+=BASE32[(buf\u003C\u003C(5-bits))&0x1F]\n    return out\n\n# --- faithful port of my C++ Base32Decode ---\ndef b32dec(s):\n    def val(c):\n        if 'A'\u003C=c\u003C='Z': return ord(c)-65\n        if 'a'\u003C=c\u003C='z': return ord(c)-97\n        if '2'\u003C=c\u003C='7': return ord(c)-ord('2')+26\n        return -1\n    buf=0; bits=0; out=bytearray()\n    for c in s:\n        if c in '= ': continue\n        v=val(c)\n        if v\u003C0: return None\n        buf=(buf\u003C\u003C5)|v; bits+=5\n        if bits>=8:\n            bits-=8; out.append((buf>>bits)&0xFF); buf&=(1\u003C\u003Cbits)-1\n    return bytes(out)\n\n# --- faithful port of my C++ TotpAt ---\ndef totp_at(key, unixtime, step=30, digits=6):\n    counter = unixtime\u002F\u002Fstep\n    msg = struct.pack(\">Q\", counter)          # big-endian 8 bytes == my loop\n    h = hmac.new(key, msg, hashlib.sha1).digest()\n    off = h[19] & 0x0F\n    binv = ((h[off]&0x7F)\u003C\u003C24)|((h[off+1]&0xFF)\u003C\u003C16)|((h[off+2]&0xFF)\u003C\u003C8)|(h[off+3]&0xFF)\n    mod = 10**digits\n    return binv % mod\n\nseed = b\"12345678901234567890\"  # RFC 6238 appendix B (SHA1)\nvectors = {59:94287082, 1111111109:7081804, 1111111111:14050471,\n           1234567890:89005924, 2000000000:69279037, 20000000000:65353130}\n\nprint(\"== RFC 6238 (8-digit) ==\")\nok_all=True\nfor t,exp in vectors.items():\n    got8 = totp_at(seed, t, digits=8)\n    got6 = totp_at(seed, t, digits=6)\n    ok = (got8==exp)\n    ok_all &= ok\n    print(f\"T={t:\u003C12} got8={got8:08d} exp={exp:08d} {'OK' if ok else 'FAIL'}   (6-digit={got6:06d})\")\n\nprint(\"\\n== Base32 round-trip ==\")\nenc=b32enc(seed)\ndec=b32dec(enc)\nprint(\"encode(seed)=\",enc)\nprint(\"decode==seed:\", dec==seed)\n\n# Known: base32 of ASCII \"12345678901234567890\" is GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\nprint(\"matches known GEZD... :\", enc==\"GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\")\n\n# --- faithful port of my C++ ValidateTotp (with replay protection) ---\ndef validate(key, code, now, last_step, step=30, digits=6, window=1):\n    if len(code)!=digits or not all('0'\u003C=c\u003C='9' for c in code): return None\n    current = now\u002F\u002Fstep\n    for w in range(-window, window+1):\n        if w\u003C0 and current \u003C -w: continue\n        counter = current + w\n        if counter \u003C= last_step: continue          # \"\u003C=\", not \"==\"\n        if totp_at(key, counter*step, step, digits) == int(code): return counter\n    return None\n\nprint(\"\\n== Replay protection ==\")\nT=1800000000\nc=f\"{totp_at(seed,T):06d}\"\ns1=validate(seed,c,T,0)\nchecks = {\n    \"fresh code accepted\":             s1==T\u002F\u002F30,\n    \"same code rejected\":              validate(seed,c,T+5,s1) is None,\n    \"previous step rejected\":          validate(seed,f\"{totp_at(seed,T-30):06d}\",T,s1) is None,\n    \"next step accepted\":              validate(seed,f\"{totp_at(seed,T+30):06d}\",T,s1)==T\u002F\u002F30+1,\n    \"old code after clock turned back\":validate(seed,f\"{totp_at(seed,T-3600):06d}\",T-3600,s1) is None,\n    \"'12abc' rejected\":                validate(seed,\"12abc\",T,0) is None,\n}\nfor k,v in checks.items(): print(f\"{k:\u003C34} {'OK' if v else 'FAIL'}\")\nok_all &= all(checks.values())\n\nprint(\"\\nALL CHECKS PASS:\", ok_all)\n","python",[69,3335,3336,3344,3348,3358,3362,3367,3378,3403,3417,3443,3458,3490,3510,3547,3555,3559,3564,3574,3585,3617,3645,3685,3693,3718,3729,3745,3755,3773,3797,3809,3845,3855,3859,3864,3890,3906,3925,3935,3956,4045,4060,4072,4076,4092,4132,4164,4168,4180,4190,4203,4222,4239,4254,4264,4350,4354,4371,4381,4391,4403,4420,4424,4429,4448,4452,4457,4486,4537,4550,4574,4599,4613,4630,4654,4660,4664,4679,4689,4711,4725,4735,4753,4775,4813,4858,4902,4925,4929,4977,4989,4993],{"__ignoreMap":154},[599,3337,3338,3341],{"class":601,"line":602},[599,3339,3340],{"class":605},"import",[599,3342,3343],{"class":666}," hmac, hashlib, struct\n",[599,3345,3346],{"class":601,"line":613},[599,3347,651],{"emptyLinePlaceholder":650},[599,3349,3350,3353,3355],{"class":601,"line":623},[599,3351,3352],{"class":949},"BASE32",[599,3354,1060],{"class":605},[599,3356,3357],{"class":619},"\"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\"\n",[599,3359,3360],{"class":601,"line":631},[599,3361,651],{"emptyLinePlaceholder":650},[599,3363,3364],{"class":601,"line":639},[599,3365,3366],{"class":772},"# --- faithful port of my C++ Base32Encode ---\n",[599,3368,3369,3372,3375],{"class":601,"line":647},[599,3370,3371],{"class":605},"def",[599,3373,3374],{"class":609}," b32enc",[599,3376,3377],{"class":666},"(data):\n",[599,3379,3380,3383,3385,3388,3391,3393,3395,3398,3400],{"class":601,"line":654},[599,3381,3382],{"class":666},"    out",[599,3384,1060],{"class":605},[599,3386,3387],{"class":619},"\"\"",[599,3389,3390],{"class":666},"; buf",[599,3392,1060],{"class":605},[599,3394,2074],{"class":949},[599,3396,3397],{"class":666},"; bits",[599,3399,1060],{"class":605},[599,3401,3402],{"class":949},"0\n",[599,3404,3405,3408,3411,3414],{"class":601,"line":663},[599,3406,3407],{"class":605},"    for",[599,3409,3410],{"class":666}," b ",[599,3412,3413],{"class":605},"in",[599,3415,3416],{"class":666}," data:\n",[599,3418,3419,3422,3424,3427,3429,3431,3433,3435,3438,3440],{"class":601,"line":670},[599,3420,3421],{"class":666},"        buf",[599,3423,1060],{"class":605},[599,3425,3426],{"class":666},"(buf",[599,3428,1432],{"class":605},[599,3430,2326],{"class":949},[599,3432,487],{"class":666},[599,3434,1440],{"class":605},[599,3436,3437],{"class":666},"b; bits",[599,3439,1455],{"class":605},[599,3441,3442],{"class":949},"8\n",[599,3444,3445,3448,3451,3453,3455],{"class":601,"line":728},[599,3446,3447],{"class":605},"        while",[599,3449,3450],{"class":666}," bits",[599,3452,1106],{"class":605},[599,3454,1847],{"class":949},[599,3456,3457],{"class":666},":\n",[599,3459,3460,3463,3465,3467,3470,3472,3474,3477,3479,3482,3485,3487],{"class":601,"line":764},[599,3461,3462],{"class":666},"            bits",[599,3464,1489],{"class":605},[599,3466,1847],{"class":949},[599,3468,3469],{"class":666},"; out",[599,3471,1455],{"class":605},[599,3473,3352],{"class":949},[599,3475,3476],{"class":666},"[(buf",[599,3478,1517],{"class":605},[599,3480,3481],{"class":666},"bits)",[599,3483,3484],{"class":605},"&0x",[599,3486,1781],{"class":949},[599,3488,3489],{"class":666},"]\n",[599,3491,3492,3495,3497,3499,3501,3503,3505,3507],{"class":601,"line":769},[599,3493,3494],{"class":666},"        buf ",[599,3496,1529],{"class":605},[599,3498,1327],{"class":666},[599,3500,1217],{"class":949},[599,3502,1432],{"class":605},[599,3504,3481],{"class":666},[599,3506,1132],{"class":605},[599,3508,3509],{"class":949},"1\n",[599,3511,3512,3515,3517,3519,3521,3524,3526,3528,3530,3532,3534,3536,3538,3541,3543,3545],{"class":601,"line":776},[599,3513,3514],{"class":605},"    if",[599,3516,3450],{"class":666},[599,3518,717],{"class":605},[599,3520,2074],{"class":949},[599,3522,3523],{"class":666},": out",[599,3525,1455],{"class":605},[599,3527,3352],{"class":949},[599,3529,3476],{"class":666},[599,3531,1432],{"class":605},[599,3533,679],{"class":666},[599,3535,1847],{"class":949},[599,3537,1132],{"class":605},[599,3539,3540],{"class":666},"bits))",[599,3542,3484],{"class":605},[599,3544,1781],{"class":949},[599,3546,3489],{"class":666},[599,3548,3549,3552],{"class":601,"line":816},[599,3550,3551],{"class":605},"    return",[599,3553,3554],{"class":666}," out\n",[599,3556,3557],{"class":601,"line":843},[599,3558,651],{"emptyLinePlaceholder":650},[599,3560,3561],{"class":601,"line":848},[599,3562,3563],{"class":772},"# --- faithful port of my C++ Base32Decode ---\n",[599,3565,3566,3568,3571],{"class":601,"line":854},[599,3567,3371],{"class":605},[599,3569,3570],{"class":609}," b32dec",[599,3572,3573],{"class":666},"(s):\n",[599,3575,3576,3579,3582],{"class":601,"line":860},[599,3577,3578],{"class":605},"    def",[599,3580,3581],{"class":609}," val",[599,3583,3584],{"class":666},"(c):\n",[599,3586,3587,3589,3591,3593,3596,3598,3601,3604,3606,3609,3612,3614],{"class":601,"line":866},[599,3588,1100],{"class":605},[599,3590,1109],{"class":619},[599,3592,1118],{"class":605},[599,3594,3595],{"class":666},"c",[599,3597,1118],{"class":605},[599,3599,3600],{"class":619},"'Z'",[599,3602,3603],{"class":666},": ",[599,3605,1127],{"class":605},[599,3607,3608],{"class":949}," ord",[599,3610,3611],{"class":666},"(c)",[599,3613,1132],{"class":605},[599,3615,3616],{"class":949},"65\n",[599,3618,3619,3621,3623,3625,3627,3629,3632,3634,3636,3638,3640,3642],{"class":601,"line":912},[599,3620,1100],{"class":605},[599,3622,1147],{"class":619},[599,3624,1118],{"class":605},[599,3626,3595],{"class":666},[599,3628,1118],{"class":605},[599,3630,3631],{"class":619},"'z'",[599,3633,3603],{"class":666},[599,3635,1127],{"class":605},[599,3637,3608],{"class":949},[599,3639,3611],{"class":666},[599,3641,1132],{"class":605},[599,3643,3644],{"class":949},"97\n",[599,3646,3647,3649,3651,3653,3655,3657,3660,3662,3664,3666,3668,3670,3673,3675,3678,3680,3682],{"class":601,"line":938},[599,3648,1100],{"class":605},[599,3650,1179],{"class":619},[599,3652,1118],{"class":605},[599,3654,3595],{"class":666},[599,3656,1118],{"class":605},[599,3658,3659],{"class":619},"'7'",[599,3661,3603],{"class":666},[599,3663,1127],{"class":605},[599,3665,3608],{"class":949},[599,3667,3611],{"class":666},[599,3669,1132],{"class":605},[599,3671,3672],{"class":949},"ord",[599,3674,679],{"class":666},[599,3676,3677],{"class":619},"'2'",[599,3679,487],{"class":666},[599,3681,2543],{"class":605},[599,3683,3684],{"class":949},"26\n",[599,3686,3687,3689,3691],{"class":601,"line":978},[599,3688,1211],{"class":605},[599,3690,1214],{"class":605},[599,3692,3509],{"class":949},[599,3694,3695,3698,3700,3702,3704,3706,3708,3710,3712,3715],{"class":601,"line":1316},[599,3696,3697],{"class":666},"    buf",[599,3699,1060],{"class":605},[599,3701,2074],{"class":949},[599,3703,3397],{"class":666},[599,3705,1060],{"class":605},[599,3707,2074],{"class":949},[599,3709,3469],{"class":666},[599,3711,1060],{"class":605},[599,3713,3714],{"class":949},"bytearray",[599,3716,3717],{"class":666},"()\n",[599,3719,3720,3722,3724,3726],{"class":601,"line":1321},[599,3721,3407],{"class":605},[599,3723,1115],{"class":666},[599,3725,3413],{"class":605},[599,3727,3728],{"class":666}," s:\n",[599,3730,3731,3733,3735,3737,3740,3742],{"class":601,"line":1335},[599,3732,1100],{"class":605},[599,3734,1115],{"class":666},[599,3736,3413],{"class":605},[599,3738,3739],{"class":619}," '= '",[599,3741,3603],{"class":666},[599,3743,3744],{"class":605},"continue\n",[599,3746,3747,3750,3752],{"class":601,"line":1341},[599,3748,3749],{"class":666},"        v",[599,3751,1060],{"class":605},[599,3753,3754],{"class":666},"val(c)\n",[599,3756,3757,3759,3762,3764,3766,3768,3770],{"class":601,"line":1367},[599,3758,1100],{"class":605},[599,3760,3761],{"class":666}," v",[599,3763,711],{"class":605},[599,3765,2074],{"class":949},[599,3767,3603],{"class":666},[599,3769,1127],{"class":605},[599,3771,3772],{"class":949}," None\n",[599,3774,3775,3777,3779,3781,3783,3785,3787,3789,3792,3794],{"class":601,"line":1375},[599,3776,3421],{"class":666},[599,3778,1060],{"class":605},[599,3780,3426],{"class":666},[599,3782,1432],{"class":605},[599,3784,1847],{"class":949},[599,3786,487],{"class":666},[599,3788,1440],{"class":605},[599,3790,3791],{"class":666},"v; bits",[599,3793,1455],{"class":605},[599,3795,3796],{"class":949},"5\n",[599,3798,3799,3801,3803,3805,3807],{"class":601,"line":1391},[599,3800,1100],{"class":605},[599,3802,3450],{"class":666},[599,3804,1106],{"class":605},[599,3806,2326],{"class":949},[599,3808,3457],{"class":666},[599,3810,3811,3813,3815,3817,3820,3822,3824,3826,3828,3831,3833,3835,3837,3839,3841,3843],{"class":601,"line":1405},[599,3812,3462],{"class":666},[599,3814,1489],{"class":605},[599,3816,2326],{"class":949},[599,3818,3819],{"class":666},"; out.append((buf",[599,3821,1517],{"class":605},[599,3823,3481],{"class":666},[599,3825,3484],{"class":605},[599,3827,2388],{"class":949},[599,3829,3830],{"class":666},"); buf",[599,3832,1529],{"class":605},[599,3834,679],{"class":666},[599,3836,1217],{"class":949},[599,3838,1432],{"class":605},[599,3840,3481],{"class":666},[599,3842,1132],{"class":605},[599,3844,3509],{"class":949},[599,3846,3847,3849,3852],{"class":601,"line":1416},[599,3848,3551],{"class":605},[599,3850,3851],{"class":949}," bytes",[599,3853,3854],{"class":666},"(out)\n",[599,3856,3857],{"class":601,"line":1421},[599,3858,651],{"emptyLinePlaceholder":650},[599,3860,3861],{"class":601,"line":1449},[599,3862,3863],{"class":772},"# --- faithful port of my C++ TotpAt ---\n",[599,3865,3866,3868,3871,3874,3876,3879,3882,3884,3887],{"class":601,"line":1462},[599,3867,3371],{"class":605},[599,3869,3870],{"class":609}," totp_at",[599,3872,3873],{"class":666},"(key, unixtime, step",[599,3875,1060],{"class":605},[599,3877,3878],{"class":949},"30",[599,3880,3881],{"class":666},", digits",[599,3883,1060],{"class":605},[599,3885,3886],{"class":949},"6",[599,3888,3889],{"class":666},"):\n",[599,3891,3892,3895,3897,3900,3903],{"class":601,"line":1477},[599,3893,3894],{"class":666},"    counter ",[599,3896,1060],{"class":605},[599,3898,3899],{"class":666}," unixtime",[599,3901,3902],{"class":605},"\u002F\u002F",[599,3904,3905],{"class":666},"step\n",[599,3907,3908,3911,3913,3916,3919,3922],{"class":601,"line":1483},[599,3909,3910],{"class":666},"    msg ",[599,3912,1060],{"class":605},[599,3914,3915],{"class":666}," struct.pack(",[599,3917,3918],{"class":619},"\">Q\"",[599,3920,3921],{"class":666},", counter)          ",[599,3923,3924],{"class":772},"# big-endian 8 bytes == my loop\n",[599,3926,3927,3930,3932],{"class":601,"line":1496},[599,3928,3929],{"class":666},"    h ",[599,3931,1060],{"class":605},[599,3933,3934],{"class":666}," hmac.new(key, msg, hashlib.sha1).digest()\n",[599,3936,3937,3940,3942,3945,3947,3949,3951,3953],{"class":601,"line":1523},[599,3938,3939],{"class":666},"    off ",[599,3941,1060],{"class":605},[599,3943,3944],{"class":666}," h[",[599,3946,2488],{"class":949},[599,3948,2491],{"class":666},[599,3950,694],{"class":605},[599,3952,1778],{"class":605},[599,3954,3955],{"class":949},"0F\n",[599,3957,3958,3961,3963,3966,3968,3970,3972,3974,3977,3979,3981,3984,3986,3988,3991,3993,3995,3997,3999,4002,4004,4006,4008,4010,4013,4015,4017,4019,4021,4023,4025,4027,4029,4032,4034,4037,4039,4041,4043],{"class":601,"line":1555},[599,3959,3960],{"class":666},"    binv ",[599,3962,1060],{"class":605},[599,3964,3965],{"class":666}," ((h[off]",[599,3967,3484],{"class":605},[599,3969,2520],{"class":949},[599,3971,487],{"class":666},[599,3973,1432],{"class":605},[599,3975,3976],{"class":949},"24",[599,3978,487],{"class":666},[599,3980,1440],{"class":605},[599,3982,3983],{"class":666},"((h[off",[599,3985,2543],{"class":605},[599,3987,1217],{"class":949},[599,3989,3990],{"class":666},"]",[599,3992,3484],{"class":605},[599,3994,2388],{"class":949},[599,3996,487],{"class":666},[599,3998,1432],{"class":605},[599,4000,4001],{"class":949},"16",[599,4003,487],{"class":666},[599,4005,1440],{"class":605},[599,4007,3983],{"class":666},[599,4009,2543],{"class":605},[599,4011,4012],{"class":949},"2",[599,4014,3990],{"class":666},[599,4016,3484],{"class":605},[599,4018,2388],{"class":949},[599,4020,487],{"class":666},[599,4022,1432],{"class":605},[599,4024,2326],{"class":949},[599,4026,487],{"class":666},[599,4028,1440],{"class":605},[599,4030,4031],{"class":666},"(h[off",[599,4033,2543],{"class":605},[599,4035,4036],{"class":949},"3",[599,4038,3990],{"class":666},[599,4040,3484],{"class":605},[599,4042,2388],{"class":949},[599,4044,1029],{"class":666},[599,4046,4047,4050,4052,4054,4057],{"class":601,"line":1561},[599,4048,4049],{"class":666},"    mod ",[599,4051,1060],{"class":605},[599,4053,2677],{"class":949},[599,4055,4056],{"class":605},"**",[599,4058,4059],{"class":666},"digits\n",[599,4061,4062,4064,4067,4069],{"class":601,"line":1567},[599,4063,3551],{"class":605},[599,4065,4066],{"class":666}," binv ",[599,4068,2692],{"class":605},[599,4070,4071],{"class":666}," mod\n",[599,4073,4074],{"class":601,"line":1577},[599,4075,651],{"emptyLinePlaceholder":650},[599,4077,4078,4081,4083,4086,4089],{"class":601,"line":1582},[599,4079,4080],{"class":666},"seed ",[599,4082,1060],{"class":605},[599,4084,4085],{"class":605}," b",[599,4087,4088],{"class":619},"\"12345678901234567890\"",[599,4090,4091],{"class":772},"  # RFC 6238 appendix B (SHA1)\n",[599,4093,4094,4097,4099,4102,4105,4107,4110,4112,4115,4117,4120,4122,4125,4127,4130],{"class":601,"line":1587},[599,4095,4096],{"class":666},"vectors ",[599,4098,1060],{"class":605},[599,4100,4101],{"class":666}," {",[599,4103,4104],{"class":949},"59",[599,4106,590],{"class":666},[599,4108,4109],{"class":949},"94287082",[599,4111,212],{"class":666},[599,4113,4114],{"class":949},"1111111109",[599,4116,590],{"class":666},[599,4118,4119],{"class":949},"7081804",[599,4121,212],{"class":666},[599,4123,4124],{"class":949},"1111111111",[599,4126,590],{"class":666},[599,4128,4129],{"class":949},"14050471",[599,4131,813],{"class":666},[599,4133,4134,4137,4139,4142,4144,4147,4149,4152,4154,4157,4159,4162],{"class":601,"line":1616},[599,4135,4136],{"class":949},"           1234567890",[599,4138,590],{"class":666},[599,4140,4141],{"class":949},"89005924",[599,4143,212],{"class":666},[599,4145,4146],{"class":949},"2000000000",[599,4148,590],{"class":666},[599,4150,4151],{"class":949},"69279037",[599,4153,212],{"class":666},[599,4155,4156],{"class":949},"20000000000",[599,4158,590],{"class":666},[599,4160,4161],{"class":949},"65353130",[599,4163,981],{"class":666},[599,4165,4166],{"class":601,"line":1621},[599,4167,651],{"emptyLinePlaceholder":650},[599,4169,4170,4173,4175,4178],{"class":601,"line":1634},[599,4171,4172],{"class":949},"print",[599,4174,679],{"class":666},[599,4176,4177],{"class":619},"\"== RFC 6238 (8-digit) ==\"",[599,4179,1029],{"class":666},[599,4181,4182,4185,4187],{"class":601,"line":1647},[599,4183,4184],{"class":666},"ok_all",[599,4186,1060],{"class":605},[599,4188,4189],{"class":949},"True\n",[599,4191,4192,4195,4198,4200],{"class":601,"line":1660},[599,4193,4194],{"class":605},"for",[599,4196,4197],{"class":666}," t,exp ",[599,4199,3413],{"class":605},[599,4201,4202],{"class":666}," vectors.items():\n",[599,4204,4205,4208,4210,4213,4216,4218,4220],{"class":601,"line":1665},[599,4206,4207],{"class":666},"    got8 ",[599,4209,1060],{"class":605},[599,4211,4212],{"class":666}," totp_at(seed, t, ",[599,4214,4215],{"class":697},"digits",[599,4217,1060],{"class":605},[599,4219,2326],{"class":949},[599,4221,1029],{"class":666},[599,4223,4224,4227,4229,4231,4233,4235,4237],{"class":601,"line":1695},[599,4225,4226],{"class":666},"    got6 ",[599,4228,1060],{"class":605},[599,4230,4212],{"class":666},[599,4232,4215],{"class":697},[599,4234,1060],{"class":605},[599,4236,3886],{"class":949},[599,4238,1029],{"class":666},[599,4240,4241,4244,4246,4249,4251],{"class":601,"line":1700},[599,4242,4243],{"class":666},"    ok ",[599,4245,1060],{"class":605},[599,4247,4248],{"class":666}," (got8",[599,4250,1349],{"class":605},[599,4252,4253],{"class":666},"exp)\n",[599,4255,4256,4259,4261],{"class":601,"line":1720},[599,4257,4258],{"class":666},"    ok_all ",[599,4260,1529],{"class":605},[599,4262,4263],{"class":666}," ok\n",[599,4265,4266,4269,4271,4274,4277,4280,4283,4286,4289,4292,4294,4297,4300,4302,4305,4307,4310,4312,4314,4316,4319,4322,4324,4327,4330,4332,4335,4337,4340,4343,4345,4348],{"class":601,"line":1731},[599,4267,4268],{"class":949},"    print",[599,4270,679],{"class":666},[599,4272,4273],{"class":605},"f",[599,4275,4276],{"class":619},"\"T=",[599,4278,4279],{"class":949},"{",[599,4281,4282],{"class":666},"t",[599,4284,4285],{"class":605},":\u003C12",[599,4287,4288],{"class":949},"}",[599,4290,4291],{"class":619}," got8=",[599,4293,4279],{"class":949},[599,4295,4296],{"class":666},"got8",[599,4298,4299],{"class":605},":08d",[599,4301,4288],{"class":949},[599,4303,4304],{"class":619}," exp=",[599,4306,4279],{"class":949},[599,4308,4309],{"class":666},"exp",[599,4311,4299],{"class":605},[599,4313,4288],{"class":949},[599,4315,4101],{"class":949},[599,4317,4318],{"class":619},"'OK'",[599,4320,4321],{"class":605}," if",[599,4323,1988],{"class":666},[599,4325,4326],{"class":605},"else",[599,4328,4329],{"class":619}," 'FAIL'",[599,4331,4288],{"class":949},[599,4333,4334],{"class":619},"   (6-digit=",[599,4336,4279],{"class":949},[599,4338,4339],{"class":666},"got6",[599,4341,4342],{"class":605},":06d",[599,4344,4288],{"class":949},[599,4346,4347],{"class":619},")\"",[599,4349,1029],{"class":666},[599,4351,4352],{"class":601,"line":1745},[599,4353,651],{"emptyLinePlaceholder":650},[599,4355,4356,4358,4360,4363,4366,4369],{"class":601,"line":1750},[599,4357,4172],{"class":949},[599,4359,679],{"class":666},[599,4361,4362],{"class":619},"\"",[599,4364,4365],{"class":949},"\\n",[599,4367,4368],{"class":619},"== Base32 round-trip ==\"",[599,4370,1029],{"class":666},[599,4372,4373,4376,4378],{"class":601,"line":1761},[599,4374,4375],{"class":666},"enc",[599,4377,1060],{"class":605},[599,4379,4380],{"class":666},"b32enc(seed)\n",[599,4382,4383,4386,4388],{"class":601,"line":1787},[599,4384,4385],{"class":666},"dec",[599,4387,1060],{"class":605},[599,4389,4390],{"class":666},"b32dec(enc)\n",[599,4392,4393,4395,4397,4400],{"class":601,"line":1792},[599,4394,4172],{"class":949},[599,4396,679],{"class":666},[599,4398,4399],{"class":619},"\"encode(seed)=\"",[599,4401,4402],{"class":666},",enc)\n",[599,4404,4405,4407,4409,4412,4415,4417],{"class":601,"line":1815},[599,4406,4172],{"class":949},[599,4408,679],{"class":666},[599,4410,4411],{"class":619},"\"decode==seed:\"",[599,4413,4414],{"class":666},", dec",[599,4416,1349],{"class":605},[599,4418,4419],{"class":666},"seed)\n",[599,4421,4422],{"class":601,"line":1820},[599,4423,651],{"emptyLinePlaceholder":650},[599,4425,4426],{"class":601,"line":1833},[599,4427,4428],{"class":772},"# Known: base32 of ASCII \"12345678901234567890\" is GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\n",[599,4430,4431,4433,4435,4438,4441,4443,4446],{"class":601,"line":1863},[599,4432,4172],{"class":949},[599,4434,679],{"class":666},[599,4436,4437],{"class":619},"\"matches known GEZD... :\"",[599,4439,4440],{"class":666},", enc",[599,4442,1349],{"class":605},[599,4444,4445],{"class":619},"\"GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\"",[599,4447,1029],{"class":666},[599,4449,4450],{"class":601,"line":1870},[599,4451,651],{"emptyLinePlaceholder":650},[599,4453,4454],{"class":601,"line":1875},[599,4455,4456],{"class":772},"# --- faithful port of my C++ ValidateTotp (with replay protection) ---\n",[599,4458,4459,4461,4464,4467,4469,4471,4473,4475,4477,4480,4482,4484],{"class":601,"line":1880},[599,4460,3371],{"class":605},[599,4462,4463],{"class":609}," validate",[599,4465,4466],{"class":666},"(key, code, now, last_step, step",[599,4468,1060],{"class":605},[599,4470,3878],{"class":949},[599,4472,3881],{"class":666},[599,4474,1060],{"class":605},[599,4476,3886],{"class":949},[599,4478,4479],{"class":666},", window",[599,4481,1060],{"class":605},[599,4483,1217],{"class":949},[599,4485,3889],{"class":666},[599,4487,4488,4490,4492,4495,4497,4500,4503,4506,4509,4511,4514,4516,4518,4520,4523,4526,4528,4530,4533,4535],{"class":601,"line":1946},[599,4489,3514],{"class":605},[599,4491,759],{"class":949},[599,4493,4494],{"class":666},"(code)",[599,4496,2030],{"class":605},[599,4498,4499],{"class":666},"digits ",[599,4501,4502],{"class":605},"or",[599,4504,4505],{"class":605}," not",[599,4507,4508],{"class":949}," all",[599,4510,679],{"class":666},[599,4512,4513],{"class":619},"'0'",[599,4515,1118],{"class":605},[599,4517,3595],{"class":666},[599,4519,1118],{"class":605},[599,4521,4522],{"class":619},"'9'",[599,4524,4525],{"class":605}," for",[599,4527,1115],{"class":666},[599,4529,3413],{"class":605},[599,4531,4532],{"class":666}," code): ",[599,4534,1127],{"class":605},[599,4536,3772],{"class":949},[599,4538,4539,4542,4544,4546,4548],{"class":601,"line":1951},[599,4540,4541],{"class":666},"    current ",[599,4543,1060],{"class":605},[599,4545,918],{"class":666},[599,4547,3902],{"class":605},[599,4549,3905],{"class":666},[599,4551,4552,4554,4556,4558,4561,4563,4565,4568,4570,4572],{"class":601,"line":1967},[599,4553,3407],{"class":605},[599,4555,2991],{"class":666},[599,4557,3413],{"class":605},[599,4559,4560],{"class":949}," range",[599,4562,679],{"class":666},[599,4564,1132],{"class":605},[599,4566,4567],{"class":666},"window, window",[599,4569,2543],{"class":605},[599,4571,1217],{"class":949},[599,4573,3889],{"class":666},[599,4575,4576,4578,4581,4583,4585,4588,4590,4592,4594,4597],{"class":601,"line":1982},[599,4577,1100],{"class":605},[599,4579,4580],{"class":666}," w",[599,4582,711],{"class":605},[599,4584,2074],{"class":949},[599,4586,4587],{"class":605}," and",[599,4589,2970],{"class":666},[599,4591,711],{"class":605},[599,4593,1214],{"class":605},[599,4595,4596],{"class":666},"w: ",[599,4598,3744],{"class":605},[599,4600,4601,4604,4606,4608,4610],{"class":601,"line":1997},[599,4602,4603],{"class":666},"        counter ",[599,4605,1060],{"class":605},[599,4607,2970],{"class":666},[599,4609,2543],{"class":605},[599,4611,4612],{"class":666}," w\n",[599,4614,4615,4617,4619,4621,4624,4627],{"class":601,"line":2002},[599,4616,1100],{"class":605},[599,4618,2303],{"class":666},[599,4620,1118],{"class":605},[599,4622,4623],{"class":666}," last_step: ",[599,4625,4626],{"class":605},"continue",[599,4628,4629],{"class":772},"          # \"\u003C=\", not \"==\"\n",[599,4631,4632,4634,4637,4639,4642,4644,4646,4649,4651],{"class":601,"line":2024},[599,4633,1100],{"class":605},[599,4635,4636],{"class":666}," totp_at(key, counter",[599,4638,748],{"class":605},[599,4640,4641],{"class":666},"step, step, digits) ",[599,4643,1349],{"class":605},[599,4645,1077],{"class":949},[599,4647,4648],{"class":666},"(code): ",[599,4650,1127],{"class":605},[599,4652,4653],{"class":666}," counter\n",[599,4655,4656,4658],{"class":601,"line":2037},[599,4657,3551],{"class":605},[599,4659,3772],{"class":949},[599,4661,4662],{"class":601,"line":2047},[599,4663,651],{"emptyLinePlaceholder":650},[599,4665,4666,4668,4670,4672,4674,4677],{"class":601,"line":2052},[599,4667,4172],{"class":949},[599,4669,679],{"class":666},[599,4671,4362],{"class":619},[599,4673,4365],{"class":949},[599,4675,4676],{"class":619},"== Replay protection ==\"",[599,4678,1029],{"class":666},[599,4680,4681,4684,4686],{"class":601,"line":2096},[599,4682,4683],{"class":666},"T",[599,4685,1060],{"class":605},[599,4687,4688],{"class":949},"1800000000\n",[599,4690,4691,4693,4695,4697,4699,4701,4704,4706,4708],{"class":601,"line":2124},[599,4692,3595],{"class":666},[599,4694,1060],{"class":605},[599,4696,4273],{"class":605},[599,4698,4362],{"class":619},[599,4700,4279],{"class":949},[599,4702,4703],{"class":666},"totp_at(seed,T)",[599,4705,4342],{"class":605},[599,4707,4288],{"class":949},[599,4709,4710],{"class":619},"\"\n",[599,4712,4713,4716,4718,4721,4723],{"class":601,"line":2129},[599,4714,4715],{"class":666},"s1",[599,4717,1060],{"class":605},[599,4719,4720],{"class":666},"validate(seed,c,T,",[599,4722,2074],{"class":949},[599,4724,1029],{"class":666},[599,4726,4727,4730,4732],{"class":601,"line":2163},[599,4728,4729],{"class":666},"checks ",[599,4731,1060],{"class":605},[599,4733,4734],{"class":666}," {\n",[599,4736,4737,4740,4743,4745,4747,4749,4751],{"class":601,"line":2186},[599,4738,4739],{"class":619},"    \"fresh code accepted\"",[599,4741,4742],{"class":666},":             s1",[599,4744,1349],{"class":605},[599,4746,4683],{"class":666},[599,4748,3902],{"class":605},[599,4750,3878],{"class":949},[599,4752,813],{"class":666},[599,4754,4755,4758,4761,4763,4765,4768,4770,4773],{"class":601,"line":2195},[599,4756,4757],{"class":619},"    \"same code rejected\"",[599,4759,4760],{"class":666},":              validate(seed,c,T",[599,4762,2543],{"class":605},[599,4764,1847],{"class":949},[599,4766,4767],{"class":666},",s1) ",[599,4769,3292],{"class":605},[599,4771,4772],{"class":949}," None",[599,4774,813],{"class":666},[599,4776,4777,4780,4783,4785,4787,4789,4792,4794,4796,4798,4800,4802,4804,4807,4809,4811],{"class":601,"line":2200},[599,4778,4779],{"class":619},"    \"previous step rejected\"",[599,4781,4782],{"class":666},":          validate(seed,",[599,4784,4273],{"class":605},[599,4786,4362],{"class":619},[599,4788,4279],{"class":949},[599,4790,4791],{"class":666},"totp_at(seed,T",[599,4793,1132],{"class":605},[599,4795,3878],{"class":949},[599,4797,487],{"class":666},[599,4799,4342],{"class":605},[599,4801,4288],{"class":949},[599,4803,4362],{"class":619},[599,4805,4806],{"class":666},",T,s1) ",[599,4808,3292],{"class":605},[599,4810,4772],{"class":949},[599,4812,813],{"class":666},[599,4814,4815,4818,4821,4823,4825,4827,4829,4831,4833,4835,4837,4839,4841,4844,4846,4848,4850,4852,4854,4856],{"class":601,"line":2212},[599,4816,4817],{"class":619},"    \"next step accepted\"",[599,4819,4820],{"class":666},":              validate(seed,",[599,4822,4273],{"class":605},[599,4824,4362],{"class":619},[599,4826,4279],{"class":949},[599,4828,4791],{"class":666},[599,4830,2543],{"class":605},[599,4832,3878],{"class":949},[599,4834,487],{"class":666},[599,4836,4342],{"class":605},[599,4838,4288],{"class":949},[599,4840,4362],{"class":619},[599,4842,4843],{"class":666},",T,s1)",[599,4845,1349],{"class":605},[599,4847,4683],{"class":666},[599,4849,3902],{"class":605},[599,4851,3878],{"class":949},[599,4853,2543],{"class":605},[599,4855,1217],{"class":949},[599,4857,813],{"class":666},[599,4859,4860,4863,4866,4868,4870,4872,4874,4876,4879,4881,4883,4885,4887,4890,4892,4894,4896,4898,4900],{"class":601,"line":2220},[599,4861,4862],{"class":619},"    \"old code after clock turned back\"",[599,4864,4865],{"class":666},":validate(seed,",[599,4867,4273],{"class":605},[599,4869,4362],{"class":619},[599,4871,4279],{"class":949},[599,4873,4791],{"class":666},[599,4875,1132],{"class":605},[599,4877,4878],{"class":949},"3600",[599,4880,487],{"class":666},[599,4882,4342],{"class":605},[599,4884,4288],{"class":949},[599,4886,4362],{"class":619},[599,4888,4889],{"class":666},",T",[599,4891,1132],{"class":605},[599,4893,4878],{"class":949},[599,4895,4767],{"class":666},[599,4897,3292],{"class":605},[599,4899,4772],{"class":949},[599,4901,813],{"class":666},[599,4903,4904,4907,4910,4912,4915,4917,4919,4921,4923],{"class":601,"line":2225},[599,4905,4906],{"class":619},"    \"'12abc' rejected\"",[599,4908,4909],{"class":666},":                validate(seed,",[599,4911,3233],{"class":619},[599,4913,4914],{"class":666},",T,",[599,4916,2074],{"class":949},[599,4918,1124],{"class":666},[599,4920,3292],{"class":605},[599,4922,4772],{"class":949},[599,4924,813],{"class":666},[599,4926,4927],{"class":601,"line":2230},[599,4928,981],{"class":666},[599,4930,4931,4933,4936,4938,4941,4943,4945,4947,4949,4951,4954,4957,4959,4961,4963,4965,4967,4969,4971,4973,4975],{"class":601,"line":2265},[599,4932,4194],{"class":605},[599,4934,4935],{"class":666}," k,v ",[599,4937,3413],{"class":605},[599,4939,4940],{"class":666}," checks.items(): ",[599,4942,4172],{"class":949},[599,4944,679],{"class":666},[599,4946,4273],{"class":605},[599,4948,4362],{"class":619},[599,4950,4279],{"class":949},[599,4952,4953],{"class":666},"k",[599,4955,4956],{"class":605},":\u003C34",[599,4958,4288],{"class":949},[599,4960,4101],{"class":949},[599,4962,4318],{"class":619},[599,4964,4321],{"class":605},[599,4966,1381],{"class":666},[599,4968,4326],{"class":605},[599,4970,4329],{"class":619},[599,4972,4288],{"class":949},[599,4974,4362],{"class":619},[599,4976,1029],{"class":666},[599,4978,4979,4982,4984,4986],{"class":601,"line":2286},[599,4980,4981],{"class":666},"ok_all ",[599,4983,1529],{"class":605},[599,4985,4508],{"class":949},[599,4987,4988],{"class":666},"(checks.values())\n",[599,4990,4991],{"class":601,"line":2291},[599,4992,651],{"emptyLinePlaceholder":650},[599,4994,4995,4997,4999,5001,5003,5006],{"class":601,"line":2297},[599,4996,4172],{"class":949},[599,4998,679],{"class":666},[599,5000,4362],{"class":619},[599,5002,4365],{"class":949},[599,5004,5005],{"class":619},"ALL CHECKS PASS:\"",[599,5007,5008],{"class":666},", ok_all)\n",[15,5010,5011,5012,212,5014,212,5017,212,5019,212,5021,212,5023,5025,5026,3242],{},"All six values have to be correct (",[69,5013,4109],{},[69,5015,5016],{},"07081804",[69,5018,4129],{},[69,5020,4141],{},[69,5022,4151],{},[69,5024,4161],{},"). The Base32 value of the test seed has to be ",[69,5027,5028],{},"GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",[15,5030,5031,5032,5034,5035,3242],{},"The second part checks the replay protection with a port of ",[69,5033,3225],{},": a fresh code works, the same code a second time doesn't, the step before doesn't, the step after does, and an old code after turning the clock back doesn't. At the end it has to say ",[69,5036,5037],{},"ALL CHECKS PASS: True",[10,5039,5041],{"id":5040},"secret-store","Secret store",[15,5043,5044,590],{},[69,5045,5046],{},"store.h",[148,5048,5050],{"className":593,"code":5049,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccstdint>\n#include \u003Cstring>\n#include \u003Cvector>\n\nnamespace tac\n{\n    \u002F\u002F \"PC\\Alice\", \".\\alice\" and \"alice\" all become \"alice\".\n    std::wstring NormalizeUser(const std::wstring& user);\n\n    \u002F\u002F Looks up COMPUTERNAME\\name and returns the SID string (\"S-1-5-21-...\")\n    \u002F\u002F if it is a local user account. Everything else returns false.\n    bool ResolveLocalUserSid(const std::wstring& user, std::wstring& sid);\n\n    \u002F\u002F The secret is stored per SID, not per name. A renamed or re-created\n    \u002F\u002F account is a different account.\n    bool StoreSecret(const std::wstring& sid, const std::string& base32Secret);\n    bool LoadSecretKey(const std::wstring& sid, std::vector\u003CBYTE>& key);\n\n    \u002F\u002F Per-account state for replay protection and rate limiting.\n    struct UserState\n    {\n        uint64_t lastStep;      \u002F\u002F last accepted TOTP time step, 0 = none yet\n        uint32_t failures;      \u002F\u002F wrong codes in a row\n        uint32_t reserved;\n        uint64_t lockedUntil;   \u002F\u002F unix time, 0 = not locked\n    };\n    static_assert(sizeof(UserState) == 24, \"UserState is stored as-is in the registry\");\n\n    \u002F\u002F A missing value is a fresh state (all zero). A broken value is an error.\n    bool LoadState(const std::wstring& sid, UserState& state);\n    bool SaveState(const std::wstring& sid, const UserState& state);\n    bool DeleteState(const std::wstring& sid);\n}\n",[69,5051,5052,5058,5064,5070,5076,5082,5086,5092,5096,5101,5129,5133,5138,5143,5179,5183,5188,5193,5231,5272,5276,5281,5289,5293,5303,5313,5320,5330,5335,5358,5362,5367,5400,5434,5457],{"__ignoreMap":154},[599,5053,5054,5056],{"class":601,"line":602},[599,5055,606],{"class":605},[599,5057,610],{"class":609},[599,5059,5060,5062],{"class":601,"line":613},[599,5061,616],{"class":605},[599,5063,620],{"class":619},[599,5065,5066,5068],{"class":601,"line":623},[599,5067,616],{"class":605},[599,5069,628],{"class":619},[599,5071,5072,5074],{"class":601,"line":631},[599,5073,616],{"class":605},[599,5075,636],{"class":619},[599,5077,5078,5080],{"class":601,"line":639},[599,5079,616],{"class":605},[599,5081,644],{"class":619},[599,5083,5084],{"class":601,"line":647},[599,5085,651],{"emptyLinePlaceholder":650},[599,5087,5088,5090],{"class":601,"line":654},[599,5089,657],{"class":605},[599,5091,660],{"class":609},[599,5093,5094],{"class":601,"line":663},[599,5095,667],{"class":666},[599,5097,5098],{"class":601,"line":670},[599,5099,5100],{"class":772},"    \u002F\u002F \"PC\\Alice\", \".\\alice\" and \"alice\" all become \"alice\".\n",[599,5102,5103,5105,5107,5109,5112,5114,5116,5118,5120,5122,5124,5127],{"class":601,"line":728},[599,5104,731],{"class":609},[599,5106,688],{"class":666},[599,5108,902],{"class":609},[599,5110,5111],{"class":609}," NormalizeUser",[599,5113,679],{"class":666},[599,5115,682],{"class":605},[599,5117,685],{"class":609},[599,5119,688],{"class":666},[599,5121,902],{"class":609},[599,5123,694],{"class":605},[599,5125,5126],{"class":697}," user",[599,5128,725],{"class":666},[599,5130,5131],{"class":601,"line":764},[599,5132,651],{"emptyLinePlaceholder":650},[599,5134,5135],{"class":601,"line":769},[599,5136,5137],{"class":772},"    \u002F\u002F Looks up COMPUTERNAME\\name and returns the SID string (\"S-1-5-21-...\")\n",[599,5139,5140],{"class":601,"line":776},[599,5141,5142],{"class":772},"    \u002F\u002F if it is a local user account. Everything else returns false.\n",[599,5144,5145,5147,5150,5152,5154,5156,5158,5160,5162,5164,5166,5168,5170,5172,5174,5177],{"class":601,"line":816},[599,5146,673],{"class":605},[599,5148,5149],{"class":609}," ResolveLocalUserSid",[599,5151,679],{"class":666},[599,5153,682],{"class":605},[599,5155,685],{"class":609},[599,5157,688],{"class":666},[599,5159,902],{"class":609},[599,5161,694],{"class":605},[599,5163,5126],{"class":697},[599,5165,212],{"class":666},[599,5167,703],{"class":609},[599,5169,688],{"class":666},[599,5171,902],{"class":609},[599,5173,694],{"class":605},[599,5175,5176],{"class":697}," sid",[599,5178,725],{"class":666},[599,5180,5181],{"class":601,"line":843},[599,5182,651],{"emptyLinePlaceholder":650},[599,5184,5185],{"class":601,"line":848},[599,5186,5187],{"class":772},"    \u002F\u002F The secret is stored per SID, not per name. A renamed or re-created\n",[599,5189,5190],{"class":601,"line":854},[599,5191,5192],{"class":772},"    \u002F\u002F account is a different account.\n",[599,5194,5195,5197,5200,5202,5204,5206,5208,5210,5212,5214,5216,5218,5220,5222,5224,5226,5229],{"class":601,"line":860},[599,5196,673],{"class":605},[599,5198,5199],{"class":609}," StoreSecret",[599,5201,679],{"class":666},[599,5203,682],{"class":605},[599,5205,685],{"class":609},[599,5207,688],{"class":666},[599,5209,902],{"class":609},[599,5211,694],{"class":605},[599,5213,5176],{"class":697},[599,5215,212],{"class":666},[599,5217,682],{"class":605},[599,5219,685],{"class":609},[599,5221,688],{"class":666},[599,5223,691],{"class":609},[599,5225,694],{"class":605},[599,5227,5228],{"class":697}," base32Secret",[599,5230,725],{"class":666},[599,5232,5233,5235,5238,5240,5242,5244,5246,5248,5250,5252,5254,5256,5258,5260,5262,5264,5266,5268,5270],{"class":601,"line":866},[599,5234,673],{"class":605},[599,5236,5237],{"class":609}," LoadSecretKey",[599,5239,679],{"class":666},[599,5241,682],{"class":605},[599,5243,685],{"class":609},[599,5245,688],{"class":666},[599,5247,902],{"class":609},[599,5249,694],{"class":605},[599,5251,5176],{"class":697},[599,5253,212],{"class":666},[599,5255,703],{"class":609},[599,5257,688],{"class":666},[599,5259,708],{"class":609},[599,5261,711],{"class":666},[599,5263,714],{"class":609},[599,5265,717],{"class":666},[599,5267,694],{"class":605},[599,5269,802],{"class":697},[599,5271,725],{"class":666},[599,5273,5274],{"class":601,"line":912},[599,5275,651],{"emptyLinePlaceholder":650},[599,5277,5278],{"class":601,"line":938},[599,5279,5280],{"class":772},"    \u002F\u002F Per-account state for replay protection and rate limiting.\n",[599,5282,5283,5286],{"class":601,"line":978},[599,5284,5285],{"class":605},"    struct",[599,5287,5288],{"class":609}," UserState\n",[599,5290,5291],{"class":601,"line":1316},[599,5292,1095],{"class":666},[599,5294,5295,5297,5300],{"class":601,"line":1321},[599,5296,2300],{"class":605},[599,5298,5299],{"class":666}," lastStep;",[599,5301,5302],{"class":772},"      \u002F\u002F last accepted TOTP time step, 0 = none yet\n",[599,5304,5305,5307,5310],{"class":601,"line":1335},[599,5306,1278],{"class":605},[599,5308,5309],{"class":666}," failures;",[599,5311,5312],{"class":772},"      \u002F\u002F wrong codes in a row\n",[599,5314,5315,5317],{"class":601,"line":1341},[599,5316,1278],{"class":605},[599,5318,5319],{"class":666}," reserved;\n",[599,5321,5322,5324,5327],{"class":601,"line":1367},[599,5323,2300],{"class":605},[599,5325,5326],{"class":666}," lockedUntil;",[599,5328,5329],{"class":772},"   \u002F\u002F unix time, 0 = not locked\n",[599,5331,5332],{"class":601,"line":1375},[599,5333,5334],{"class":666},"    };\n",[599,5336,5337,5340,5342,5344,5347,5349,5351,5353,5356],{"class":601,"line":1391},[599,5338,5339],{"class":605},"    static_assert",[599,5341,679],{"class":666},[599,5343,2444],{"class":605},[599,5345,5346],{"class":666},"(UserState) ",[599,5348,1349],{"class":605},[599,5350,2529],{"class":949},[599,5352,212],{"class":666},[599,5354,5355],{"class":619},"\"UserState is stored as-is in the registry\"",[599,5357,725],{"class":666},[599,5359,5360],{"class":601,"line":1405},[599,5361,651],{"emptyLinePlaceholder":650},[599,5363,5364],{"class":601,"line":1416},[599,5365,5366],{"class":772},"    \u002F\u002F A missing value is a fresh state (all zero). A broken value is an error.\n",[599,5368,5369,5371,5374,5376,5378,5380,5382,5384,5386,5388,5390,5393,5395,5398],{"class":601,"line":1421},[599,5370,673],{"class":605},[599,5372,5373],{"class":609}," LoadState",[599,5375,679],{"class":666},[599,5377,682],{"class":605},[599,5379,685],{"class":609},[599,5381,688],{"class":666},[599,5383,902],{"class":609},[599,5385,694],{"class":605},[599,5387,5176],{"class":697},[599,5389,212],{"class":666},[599,5391,5392],{"class":609},"UserState",[599,5394,694],{"class":605},[599,5396,5397],{"class":697}," state",[599,5399,725],{"class":666},[599,5401,5402,5404,5407,5409,5411,5413,5415,5417,5419,5421,5423,5425,5428,5430,5432],{"class":601,"line":1449},[599,5403,673],{"class":605},[599,5405,5406],{"class":609}," SaveState",[599,5408,679],{"class":666},[599,5410,682],{"class":605},[599,5412,685],{"class":609},[599,5414,688],{"class":666},[599,5416,902],{"class":609},[599,5418,694],{"class":605},[599,5420,5176],{"class":697},[599,5422,212],{"class":666},[599,5424,682],{"class":605},[599,5426,5427],{"class":609}," UserState",[599,5429,694],{"class":605},[599,5431,5397],{"class":697},[599,5433,725],{"class":666},[599,5435,5436,5438,5441,5443,5445,5447,5449,5451,5453,5455],{"class":601,"line":1462},[599,5437,673],{"class":605},[599,5439,5440],{"class":609}," DeleteState",[599,5442,679],{"class":666},[599,5444,682],{"class":605},[599,5446,685],{"class":609},[599,5448,688],{"class":666},[599,5450,902],{"class":609},[599,5452,694],{"class":605},[599,5454,5176],{"class":697},[599,5456,725],{"class":666},[599,5458,5459],{"class":601,"line":1477},[599,5460,981],{"class":666},[15,5462,5463,590],{},[69,5464,5465],{},"store.cpp",[148,5467,5469],{"className":593,"code":5468,"language":595,"meta":154,"style":154},"#include \"store.h\"\n#include \"totp.h\"\n#include \u003Cwincrypt.h>\n#include \u003Csddl.h>\n#include \u003Ccwctype>\n\n#pragma comment(lib, \"crypt32.lib\")\n#pragma comment(lib, \"advapi32.lib\")\n\nnamespace tac\n{\n    static const wchar_t kKeyPath[]   = L\"SOFTWARE\\\\TheAdminCafe\\\\2FA\";\n    static const wchar_t kStatePath[] = L\"SOFTWARE\\\\TheAdminCafe\\\\2FA\\\\State\";\n\n    \u002F\u002F SYSTEM and Administrators only. \"P\" blocks the inherited ACL of\n    \u002F\u002F HKLM\\SOFTWARE, which would let every user read the key.\n    static const wchar_t kKeySddl[] = L\"D:P(A;OICI;KA;;;SY)(A;OICI;KA;;;BA)\";\n\n    std::wstring NormalizeUser(const std::wstring& user)\n    {\n        std::wstring name = user;\n        size_t pos = name.find_last_of(L'\\\\');\n        if (pos != std::wstring::npos)\n            name = name.substr(pos + 1);\n        for (wchar_t& c : name)\n            c = static_cast\u003Cwchar_t>(towlower(c));\n        return name;\n    }\n\n    static bool Protect(const std::string& plain, std::vector\u003CBYTE>& blob)\n    {\n        DATA_BLOB in  = { static_cast\u003CDWORD>(plain.size()),\n                          reinterpret_cast\u003CBYTE*>(const_cast\u003Cchar*>(plain.data())) };\n        DATA_BLOB out = {};\n\n        \u002F\u002F Machine scope, so LogonUI (SYSTEM) can decrypt what an admin encrypted.\n        \u002F\u002F No UI may ever appear on the secure desktop.\n        if (!CryptProtectData(&in, L\"tac-2fa\", nullptr, nullptr, nullptr,\n                              CRYPTPROTECT_LOCAL_MACHINE | CRYPTPROTECT_UI_FORBIDDEN, &out))\n            return false;\n\n        blob.assign(out.pbData, out.pbData + out.cbData);\n        LocalFree(out.pbData);\n        return true;\n    }\n\n    static bool Unprotect(const std::vector\u003CBYTE>& blob, std::string& plain)\n    {\n        DATA_BLOB in  = { static_cast\u003CDWORD>(blob.size()), const_cast\u003CBYTE*>(blob.data()) };\n        DATA_BLOB out = {};\n\n        \u002F\u002F The scope is stored in the blob, so no LOCAL_MACHINE flag here.\n        if (!CryptUnprotectData(&in, nullptr, nullptr, nullptr, nullptr,\n                                CRYPTPROTECT_UI_FORBIDDEN, &out))\n            return false;\n\n        plain.assign(reinterpret_cast\u003Cchar*>(out.pbData), out.cbData);\n        SecureZeroMemory(out.pbData, out.cbData);\n        LocalFree(out.pbData);\n        return true;\n    }\n\n    \u002F\u002F Resolves the name the same way LSA will: as COMPUTERNAME\\name against the\n    \u002F\u002F local SAM. Only a real user account counts, not a group or an alias.\n    bool ResolveLocalUserSid(const std::wstring& user, std::wstring& sid)\n    {\n        sid.clear();\n        std::wstring name = NormalizeUser(user);\n        if (name.empty())\n            return false;\n\n        WCHAR computer[MAX_COMPUTERNAME_LENGTH + 1] = {};\n        DWORD cchComputer = ARRAYSIZE(computer);\n        if (!GetComputerNameW(computer, &cchComputer))\n            return false;\n\n        std::wstring qualified = std::wstring(computer) + L\"\\\\\" + name;\n        BYTE sidBuf[SECURITY_MAX_SID_SIZE];\n        DWORD cbSid = sizeof(sidBuf);\n        WCHAR domain[256] = {};\n        DWORD cchDomain = ARRAYSIZE(domain);\n        SID_NAME_USE use;\n        if (!LookupAccountNameW(nullptr, qualified.c_str(), sidBuf, &cbSid,\n                                domain, &cchDomain, &use))\n            return false;\n\n        \u002F\u002F The account has to live in this computer's SAM, not in a domain.\n        if (use != SidTypeUser || _wcsicmp(domain, computer) != 0)\n            return false;\n\n        PWSTR pszSid = nullptr;\n        if (!ConvertSidToStringSidW(sidBuf, &pszSid))\n            return false;\n        sid = pszSid;\n        LocalFree(pszSid);\n        return true;\n    }\n\n    \u002F\u002F Only SIDs are used as value names. This keeps odd input out of the registry.\n    static bool IsSidString(const std::wstring& sid)\n    {\n        return sid.size() > 4 && sid.compare(0, 4, L\"S-1-\") == 0;\n    }\n\n    \u002F\u002F Creates or opens a key below HKLM with our ACL. The security attributes\n    \u002F\u002F only apply when the key is created. An existing key might still carry a\n    \u002F\u002F weaker ACL, so it is set again.\n    static LSTATUS OpenProtectedKey(const wchar_t* path, HKEY* phKey)\n    {\n        PSECURITY_DESCRIPTOR psd = nullptr;\n        if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(kKeySddl, SDDL_REVISION_1,\n                                                                  &psd, nullptr))\n            return static_cast\u003CLSTATUS>(GetLastError());\n\n        SECURITY_ATTRIBUTES sa = { sizeof(sa), psd, FALSE };\n        DWORD disposition = 0;\n        LSTATUS status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, path, 0, nullptr, 0,\n                                         KEY_SET_VALUE | KEY_QUERY_VALUE | WRITE_DAC,\n                                         &sa, phKey, &disposition);\n        if (status == ERROR_SUCCESS && disposition == REG_OPENED_EXISTING_KEY)\n        {\n            status = RegSetKeySecurity(*phKey, DACL_SECURITY_INFORMATION, psd);\n            if (status != ERROR_SUCCESS)\n            {\n                RegCloseKey(*phKey);\n                *phKey = nullptr;\n            }\n        }\n\n        LocalFree(psd);\n        return status;\n    }\n\n    bool StoreSecret(const std::wstring& sid, const std::string& base32Secret)\n    {\n        if (!IsSidString(sid))\n            return false;\n\n        std::vector\u003CBYTE> blob;\n        if (!Protect(base32Secret, blob))\n            return false;\n\n        HKEY hKey = nullptr;\n        LSTATUS status = OpenProtectedKey(kKeyPath, &hKey);\n        if (status == ERROR_SUCCESS)\n        {\n            status = RegSetValueExW(hKey, sid.c_str(), 0, REG_BINARY,\n                                    blob.data(), static_cast\u003CDWORD>(blob.size()));\n            RegCloseKey(hKey);\n        }\n        return status == ERROR_SUCCESS;\n    }\n\n    bool LoadSecretKey(const std::wstring& sid, std::vector\u003CBYTE>& key)\n    {\n        key.clear();\n        if (!IsSidString(sid))\n            return false;\n\n        HKEY hKey = nullptr;\n        if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, kKeyPath, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)\n            return false;\n\n        DWORD type = 0;\n        DWORD cb = 0;\n        std::vector\u003CBYTE> blob;\n        LSTATUS status = RegQueryValueExW(hKey, sid.c_str(), nullptr, &type, nullptr, &cb);\n        if (status == ERROR_SUCCESS && type == REG_BINARY && cb > 0)\n        {\n            blob.resize(cb);\n            status = RegQueryValueExW(hKey, sid.c_str(), nullptr, &type, blob.data(), &cb);\n        }\n        RegCloseKey(hKey);\n        if (status != ERROR_SUCCESS || blob.empty())\n            return false;\n\n        std::string base32;\n        if (!Unprotect(blob, base32))\n            return false;\n\n        bool ok = Base32Decode(base32, key);\n        SecureZeroMemory(&base32[0], base32.size());\n\n        \u002F\u002F An empty or very short key would make the code predictable. Our\n        \u002F\u002F secrets have 20 bytes; anything under 16 counts as broken.\n        if (!ok || key.size() \u003C 16)\n        {\n            if (!key.empty())\n                SecureZeroMemory(key.data(), key.size());\n            key.clear();\n            return false;\n        }\n        return true;\n    }\n\n    bool LoadState(const std::wstring& sid, UserState& state)\n    {\n        ZeroMemory(&state, sizeof(state));\n        if (!IsSidString(sid))\n            return false;\n\n        HKEY hKey = nullptr;\n        LSTATUS status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, kStatePath, 0, KEY_QUERY_VALUE, &hKey);\n        if (status == ERROR_FILE_NOT_FOUND)\n            return true;                      \u002F\u002F nobody has logged on yet\n        if (status != ERROR_SUCCESS)\n            return false;\n\n        DWORD type = 0;\n        DWORD cb = sizeof(state);\n        status = RegQueryValueExW(hKey, sid.c_str(), nullptr, &type,\n                                  reinterpret_cast\u003CBYTE*>(&state), &cb);\n        RegCloseKey(hKey);\n\n        if (status == ERROR_FILE_NOT_FOUND)\n        {\n            ZeroMemory(&state, sizeof(state));\n            return true;                      \u002F\u002F this user has not logged on yet\n        }\n        \u002F\u002F Anything else that is not exactly our structure is an error. The\n        \u002F\u002F caller fails closed, so a broken value cannot reset the counters.\n        return status == ERROR_SUCCESS && type == REG_BINARY && cb == sizeof(state);\n    }\n\n    bool SaveState(const std::wstring& sid, const UserState& state)\n    {\n        if (!IsSidString(sid))\n            return false;\n\n        HKEY hKey = nullptr;\n        LSTATUS status = OpenProtectedKey(kStatePath, &hKey);\n        if (status == ERROR_SUCCESS)\n        {\n            status = RegSetValueExW(hKey, sid.c_str(), 0, REG_BINARY,\n                                    reinterpret_cast\u003Cconst BYTE*>(&state), sizeof(state));\n            RegFlushKey(hKey);   \u002F\u002F survive a hard reset right after the logon\n            RegCloseKey(hKey);\n        }\n        return status == ERROR_SUCCESS;\n    }\n\n    bool DeleteState(const std::wstring& sid)\n    {\n        if (!IsSidString(sid))\n            return false;\n\n        HKEY hKey = nullptr;\n        LSTATUS status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, kStatePath, 0, KEY_SET_VALUE, &hKey);\n        if (status == ERROR_FILE_NOT_FOUND)\n            return true;\n        if (status != ERROR_SUCCESS)\n            return false;\n\n        status = RegDeleteValueW(hKey, sid.c_str());\n        RegCloseKey(hKey);\n        return status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND;\n    }\n}\n",[69,5470,5471,5478,5484,5491,5498,5505,5509,5526,5543,5547,5553,5557,5587,5618,5622,5627,5632,5650,5654,5680,5684,5700,5728,5746,5767,5779,5797,5804,5808,5812,5857,5861,5888,5910,5922,5926,5931,5936,5971,5986,5994,5998,6014,6022,6030,6034,6038,6081,6085,6121,6131,6135,6140,6173,6182,6190,6194,6209,6217,6223,6231,6235,6239,6244,6249,6283,6287,6296,6313,6326,6334,6338,6353,6369,6388,6396,6400,6435,6442,6457,6471,6485,6493,6522,6537,6545,6549,6554,6581,6589,6593,6607,6626,6634,6644,6651,6659,6663,6667,6672,6697,6701,6746,6750,6754,6759,6764,6769,6801,6805,6819,6833,6846,6865,6869,6886,6899,6927,6942,6955,6976,6980,6997,7008,7012,7024,7038,7042,7046,7050,7057,7064,7068,7072,7108,7112,7126,7134,7138,7153,7167,7175,7179,7193,7211,7221,7225,7247,7269,7277,7281,7292,7296,7300,7340,7344,7353,7365,7374,7379,7392,7419,7428,7433,7447,7461,7476,7512,7542,7547,7559,7591,7596,7604,7624,7633,7638,7650,7665,7674,7679,7693,7714,7719,7725,7731,7758,7763,7779,7796,7806,7815,7820,7829,7834,7839,7870,7875,7893,7906,7915,7920,7933,7956,7968,7980,7991,8000,8005,8018,8032,8057,8078,8085,8090,8101,8106,8122,8134,8139,8145,8151,8180,8185,8190,8223,8228,8241,8250,8255,8268,8286,8297,8302,8321,8341,8353,8360,8365,8376,8381,8386,8409,8414,8427,8436,8441,8454,8476,8487,8496,8507,8516,8521,8537,8544,8564,8569],{"__ignoreMap":154},[599,5472,5473,5475],{"class":601,"line":602},[599,5474,616],{"class":605},[599,5476,5477],{"class":619}," \"store.h\"\n",[599,5479,5480,5482],{"class":601,"line":613},[599,5481,616],{"class":605},[599,5483,998],{"class":619},[599,5485,5486,5488],{"class":601,"line":623},[599,5487,616],{"class":605},[599,5489,5490],{"class":619}," \u003Cwincrypt.h>\n",[599,5492,5493,5495],{"class":601,"line":631},[599,5494,616],{"class":605},[599,5496,5497],{"class":619}," \u003Csddl.h>\n",[599,5499,5500,5502],{"class":601,"line":639},[599,5501,616],{"class":605},[599,5503,5504],{"class":619}," \u003Ccwctype>\n",[599,5506,5507],{"class":601,"line":647},[599,5508,651],{"emptyLinePlaceholder":650},[599,5510,5511,5513,5515,5517,5519,5521,5524],{"class":601,"line":654},[599,5512,606],{"class":605},[599,5514,1016],{"class":609},[599,5516,679],{"class":666},[599,5518,1021],{"class":609},[599,5520,212],{"class":666},[599,5522,5523],{"class":619},"\"crypt32.lib\"",[599,5525,1029],{"class":666},[599,5527,5528,5530,5532,5534,5536,5538,5541],{"class":601,"line":663},[599,5529,606],{"class":605},[599,5531,1016],{"class":609},[599,5533,679],{"class":666},[599,5535,1021],{"class":609},[599,5537,212],{"class":666},[599,5539,5540],{"class":619},"\"advapi32.lib\"",[599,5542,1029],{"class":666},[599,5544,5545],{"class":601,"line":670},[599,5546,651],{"emptyLinePlaceholder":650},[599,5548,5549,5551],{"class":601,"line":728},[599,5550,657],{"class":605},[599,5552,660],{"class":609},[599,5554,5555],{"class":601,"line":764},[599,5556,667],{"class":666},[599,5558,5559,5561,5563,5566,5569,5571,5574,5577,5580,5582,5585],{"class":601,"line":769},[599,5560,1048],{"class":605},[599,5562,1051],{"class":605},[599,5564,5565],{"class":605}," wchar_t",[599,5567,5568],{"class":666}," kKeyPath[]   ",[599,5570,1060],{"class":605},[599,5572,5573],{"class":619}," L\"SOFTWARE",[599,5575,5576],{"class":949},"\\\\",[599,5578,5579],{"class":619},"TheAdminCafe",[599,5581,5576],{"class":949},[599,5583,5584],{"class":619},"2FA\"",[599,5586,1066],{"class":666},[599,5588,5589,5591,5593,5595,5598,5600,5602,5604,5606,5608,5611,5613,5616],{"class":601,"line":776},[599,5590,1048],{"class":605},[599,5592,1051],{"class":605},[599,5594,5565],{"class":605},[599,5596,5597],{"class":666}," kStatePath[] ",[599,5599,1060],{"class":605},[599,5601,5573],{"class":619},[599,5603,5576],{"class":949},[599,5605,5579],{"class":619},[599,5607,5576],{"class":949},[599,5609,5610],{"class":619},"2FA",[599,5612,5576],{"class":949},[599,5614,5615],{"class":619},"State\"",[599,5617,1066],{"class":666},[599,5619,5620],{"class":601,"line":816},[599,5621,651],{"emptyLinePlaceholder":650},[599,5623,5624],{"class":601,"line":843},[599,5625,5626],{"class":772},"    \u002F\u002F SYSTEM and Administrators only. \"P\" blocks the inherited ACL of\n",[599,5628,5629],{"class":601,"line":848},[599,5630,5631],{"class":772},"    \u002F\u002F HKLM\\SOFTWARE, which would let every user read the key.\n",[599,5633,5634,5636,5638,5640,5643,5645,5648],{"class":601,"line":854},[599,5635,1048],{"class":605},[599,5637,1051],{"class":605},[599,5639,5565],{"class":605},[599,5641,5642],{"class":666}," kKeySddl[] ",[599,5644,1060],{"class":605},[599,5646,5647],{"class":619}," L\"D:P(A;OICI;KA;;;SY)(A;OICI;KA;;;BA)\"",[599,5649,1066],{"class":666},[599,5651,5652],{"class":601,"line":860},[599,5653,651],{"emptyLinePlaceholder":650},[599,5655,5656,5658,5660,5662,5664,5666,5668,5670,5672,5674,5676,5678],{"class":601,"line":866},[599,5657,731],{"class":609},[599,5659,688],{"class":666},[599,5661,902],{"class":609},[599,5663,5111],{"class":609},[599,5665,679],{"class":666},[599,5667,682],{"class":605},[599,5669,685],{"class":609},[599,5671,688],{"class":666},[599,5673,902],{"class":609},[599,5675,694],{"class":605},[599,5677,5126],{"class":697},[599,5679,1029],{"class":666},[599,5681,5682],{"class":601,"line":912},[599,5683,1095],{"class":666},[599,5685,5686,5688,5690,5692,5695,5697],{"class":601,"line":938},[599,5687,1624],{"class":609},[599,5689,688],{"class":666},[599,5691,902],{"class":609},[599,5693,5694],{"class":666}," name ",[599,5696,1060],{"class":605},[599,5698,5699],{"class":666}," user;\n",[599,5701,5702,5705,5708,5710,5713,5716,5718,5721,5723,5726],{"class":601,"line":978},[599,5703,5704],{"class":605},"        size_t",[599,5706,5707],{"class":666}," pos ",[599,5709,1060],{"class":605},[599,5711,5712],{"class":666}," name.",[599,5714,5715],{"class":609},"find_last_of",[599,5717,679],{"class":666},[599,5719,5720],{"class":619},"L'",[599,5722,5576],{"class":949},[599,5724,5725],{"class":619},"'",[599,5727,725],{"class":666},[599,5729,5730,5732,5735,5737,5739,5741,5743],{"class":601,"line":1316},[599,5731,1100],{"class":605},[599,5733,5734],{"class":666}," (pos ",[599,5736,2030],{"class":605},[599,5738,685],{"class":609},[599,5740,688],{"class":666},[599,5742,902],{"class":609},[599,5744,5745],{"class":666},"::npos)\n",[599,5747,5748,5751,5753,5755,5758,5761,5763,5765],{"class":601,"line":1321},[599,5749,5750],{"class":666},"            name ",[599,5752,1060],{"class":605},[599,5754,5712],{"class":666},[599,5756,5757],{"class":609},"substr",[599,5759,5760],{"class":666},"(pos ",[599,5762,2543],{"class":605},[599,5764,973],{"class":949},[599,5766,725],{"class":666},[599,5768,5769,5771,5773,5776],{"class":601,"line":1335},[599,5770,1324],{"class":605},[599,5772,1327],{"class":666},[599,5774,5775],{"class":605},"wchar_t&",[599,5777,5778],{"class":666}," c : name)\n",[599,5780,5781,5784,5786,5789,5791,5794],{"class":601,"line":1341},[599,5782,5783],{"class":666},"            c ",[599,5785,1060],{"class":605},[599,5787,5788],{"class":605}," static_cast\u003Cwchar_t>",[599,5790,679],{"class":666},[599,5792,5793],{"class":609},"towlower",[599,5795,5796],{"class":666},"(c));\n",[599,5798,5799,5801],{"class":601,"line":1367},[599,5800,1211],{"class":605},[599,5802,5803],{"class":666}," name;\n",[599,5805,5806],{"class":601,"line":1375},[599,5807,1224],{"class":666},[599,5809,5810],{"class":601,"line":1391},[599,5811,651],{"emptyLinePlaceholder":650},[599,5813,5814,5816,5818,5821,5823,5825,5827,5829,5831,5833,5836,5838,5840,5842,5844,5846,5848,5850,5852,5855],{"class":601,"line":1405},[599,5815,1048],{"class":605},[599,5817,1885],{"class":605},[599,5819,5820],{"class":609}," Protect",[599,5822,679],{"class":666},[599,5824,682],{"class":605},[599,5826,685],{"class":609},[599,5828,688],{"class":666},[599,5830,691],{"class":609},[599,5832,694],{"class":605},[599,5834,5835],{"class":697}," plain",[599,5837,212],{"class":666},[599,5839,703],{"class":609},[599,5841,688],{"class":666},[599,5843,708],{"class":609},[599,5845,711],{"class":666},[599,5847,714],{"class":609},[599,5849,717],{"class":666},[599,5851,694],{"class":605},[599,5853,5854],{"class":697}," blob",[599,5856,1029],{"class":666},[599,5858,5859],{"class":601,"line":1416},[599,5860,1095],{"class":666},[599,5862,5863,5866,5869,5871,5874,5876,5879,5881,5884,5886],{"class":601,"line":1421},[599,5864,5865],{"class":609},"        DATA_BLOB",[599,5867,5868],{"class":666}," in  ",[599,5870,1060],{"class":605},[599,5872,5873],{"class":666}," { ",[599,5875,1507],{"class":605},[599,5877,5878],{"class":666},"DWORD",[599,5880,717],{"class":605},[599,5882,5883],{"class":666},"(plain.",[599,5885,2108],{"class":609},[599,5887,2093],{"class":666},[599,5889,5890,5893,5895,5898,5900,5903,5905,5907],{"class":601,"line":1449},[599,5891,5892],{"class":605},"                          reinterpret_cast\u003C",[599,5894,714],{"class":666},[599,5896,5897],{"class":605},"*>",[599,5899,679],{"class":666},[599,5901,5902],{"class":605},"const_cast\u003Cchar*>",[599,5904,5883],{"class":666},[599,5906,2090],{"class":609},[599,5908,5909],{"class":666},"())) };\n",[599,5911,5912,5914,5917,5919],{"class":601,"line":1462},[599,5913,5865],{"class":609},[599,5915,5916],{"class":666}," out ",[599,5918,1060],{"class":605},[599,5920,5921],{"class":666}," {};\n",[599,5923,5924],{"class":601,"line":1477},[599,5925,651],{"emptyLinePlaceholder":650},[599,5927,5928],{"class":601,"line":1483},[599,5929,5930],{"class":772},"        \u002F\u002F Machine scope, so LogonUI (SYSTEM) can decrypt what an admin encrypted.\n",[599,5932,5933],{"class":601,"line":1496},[599,5934,5935],{"class":772},"        \u002F\u002F No UI may ever appear on the secure desktop.\n",[599,5937,5938,5940,5942,5944,5947,5949,5951,5954,5957,5959,5961,5963,5965,5967,5969],{"class":601,"line":1523},[599,5939,1100],{"class":605},[599,5941,1327],{"class":666},[599,5943,2435],{"class":605},[599,5945,5946],{"class":609},"CryptProtectData",[599,5948,679],{"class":666},[599,5950,694],{"class":605},[599,5952,5953],{"class":666},"in, ",[599,5955,5956],{"class":619},"L\"tac-2fa\"",[599,5958,212],{"class":666},[599,5960,2019],{"class":949},[599,5962,212],{"class":666},[599,5964,2019],{"class":949},[599,5966,212],{"class":666},[599,5968,2019],{"class":949},[599,5970,813],{"class":666},[599,5972,5973,5976,5978,5981,5983],{"class":601,"line":1555},[599,5974,5975],{"class":666},"                              CRYPTPROTECT_LOCAL_MACHINE ",[599,5977,1440],{"class":605},[599,5979,5980],{"class":666}," CRYPTPROTECT_UI_FORBIDDEN, ",[599,5982,694],{"class":605},[599,5984,5985],{"class":666},"out))\n",[599,5987,5988,5990,5992],{"class":601,"line":1561},[599,5989,2040],{"class":605},[599,5991,1411],{"class":949},[599,5993,1066],{"class":666},[599,5995,5996],{"class":601,"line":1567},[599,5997,651],{"emptyLinePlaceholder":650},[599,5999,6000,6003,6006,6009,6011],{"class":601,"line":1577},[599,6001,6002],{"class":666},"        blob.",[599,6004,6005],{"class":609},"assign",[599,6007,6008],{"class":666},"(out.pbData, out.pbData ",[599,6010,2543],{"class":605},[599,6012,6013],{"class":666}," out.cbData);\n",[599,6015,6016,6019],{"class":601,"line":1582},[599,6017,6018],{"class":609},"        LocalFree",[599,6020,6021],{"class":666},"(out.pbData);\n",[599,6023,6024,6026,6028],{"class":601,"line":1587},[599,6025,1211],{"class":605},[599,6027,1572],{"class":949},[599,6029,1066],{"class":666},[599,6031,6032],{"class":601,"line":1616},[599,6033,1224],{"class":666},[599,6035,6036],{"class":601,"line":1621},[599,6037,651],{"emptyLinePlaceholder":650},[599,6039,6040,6042,6044,6047,6049,6051,6053,6055,6057,6059,6061,6063,6065,6067,6069,6071,6073,6075,6077,6079],{"class":601,"line":1634},[599,6041,1048],{"class":605},[599,6043,1885],{"class":605},[599,6045,6046],{"class":609}," Unprotect",[599,6048,679],{"class":666},[599,6050,682],{"class":605},[599,6052,685],{"class":609},[599,6054,688],{"class":666},[599,6056,708],{"class":609},[599,6058,711],{"class":666},[599,6060,714],{"class":609},[599,6062,717],{"class":666},[599,6064,694],{"class":605},[599,6066,5854],{"class":697},[599,6068,212],{"class":666},[599,6070,703],{"class":609},[599,6072,688],{"class":666},[599,6074,691],{"class":609},[599,6076,694],{"class":605},[599,6078,5835],{"class":697},[599,6080,1029],{"class":666},[599,6082,6083],{"class":601,"line":1647},[599,6084,1095],{"class":666},[599,6086,6087,6089,6091,6093,6095,6097,6099,6101,6104,6106,6108,6110,6112,6114,6116,6118],{"class":601,"line":1660},[599,6088,5865],{"class":609},[599,6090,5868],{"class":666},[599,6092,1060],{"class":605},[599,6094,5873],{"class":666},[599,6096,1507],{"class":605},[599,6098,5878],{"class":666},[599,6100,717],{"class":605},[599,6102,6103],{"class":666},"(blob.",[599,6105,2108],{"class":609},[599,6107,2111],{"class":666},[599,6109,2079],{"class":605},[599,6111,714],{"class":666},[599,6113,5897],{"class":605},[599,6115,6103],{"class":666},[599,6117,2090],{"class":609},[599,6119,6120],{"class":666},"()) };\n",[599,6122,6123,6125,6127,6129],{"class":601,"line":1665},[599,6124,5865],{"class":609},[599,6126,5916],{"class":666},[599,6128,1060],{"class":605},[599,6130,5921],{"class":666},[599,6132,6133],{"class":601,"line":1695},[599,6134,651],{"emptyLinePlaceholder":650},[599,6136,6137],{"class":601,"line":1700},[599,6138,6139],{"class":772},"        \u002F\u002F The scope is stored in the blob, so no LOCAL_MACHINE flag here.\n",[599,6141,6142,6144,6146,6148,6151,6153,6155,6157,6159,6161,6163,6165,6167,6169,6171],{"class":601,"line":1720},[599,6143,1100],{"class":605},[599,6145,1327],{"class":666},[599,6147,2435],{"class":605},[599,6149,6150],{"class":609},"CryptUnprotectData",[599,6152,679],{"class":666},[599,6154,694],{"class":605},[599,6156,5953],{"class":666},[599,6158,2019],{"class":949},[599,6160,212],{"class":666},[599,6162,2019],{"class":949},[599,6164,212],{"class":666},[599,6166,2019],{"class":949},[599,6168,212],{"class":666},[599,6170,2019],{"class":949},[599,6172,813],{"class":666},[599,6174,6175,6178,6180],{"class":601,"line":1731},[599,6176,6177],{"class":666},"                                CRYPTPROTECT_UI_FORBIDDEN, ",[599,6179,694],{"class":605},[599,6181,5985],{"class":666},[599,6183,6184,6186,6188],{"class":601,"line":1745},[599,6185,2040],{"class":605},[599,6187,1411],{"class":949},[599,6189,1066],{"class":666},[599,6191,6192],{"class":601,"line":1750},[599,6193,651],{"emptyLinePlaceholder":650},[599,6195,6196,6199,6201,6203,6206],{"class":601,"line":1761},[599,6197,6198],{"class":666},"        plain.",[599,6200,6005],{"class":609},[599,6202,679],{"class":666},[599,6204,6205],{"class":605},"reinterpret_cast\u003Cchar*>",[599,6207,6208],{"class":666},"(out.pbData), out.cbData);\n",[599,6210,6211,6214],{"class":601,"line":1787},[599,6212,6213],{"class":609},"        SecureZeroMemory",[599,6215,6216],{"class":666},"(out.pbData, out.cbData);\n",[599,6218,6219,6221],{"class":601,"line":1792},[599,6220,6018],{"class":609},[599,6222,6021],{"class":666},[599,6224,6225,6227,6229],{"class":601,"line":1815},[599,6226,1211],{"class":605},[599,6228,1572],{"class":949},[599,6230,1066],{"class":666},[599,6232,6233],{"class":601,"line":1820},[599,6234,1224],{"class":666},[599,6236,6237],{"class":601,"line":1833},[599,6238,651],{"emptyLinePlaceholder":650},[599,6240,6241],{"class":601,"line":1863},[599,6242,6243],{"class":772},"    \u002F\u002F Resolves the name the same way LSA will: as COMPUTERNAME\\name against the\n",[599,6245,6246],{"class":601,"line":1870},[599,6247,6248],{"class":772},"    \u002F\u002F local SAM. Only a real user account counts, not a group or an alias.\n",[599,6250,6251,6253,6255,6257,6259,6261,6263,6265,6267,6269,6271,6273,6275,6277,6279,6281],{"class":601,"line":1875},[599,6252,673],{"class":605},[599,6254,5149],{"class":609},[599,6256,679],{"class":666},[599,6258,682],{"class":605},[599,6260,685],{"class":609},[599,6262,688],{"class":666},[599,6264,902],{"class":609},[599,6266,694],{"class":605},[599,6268,5126],{"class":697},[599,6270,212],{"class":666},[599,6272,703],{"class":609},[599,6274,688],{"class":666},[599,6276,902],{"class":609},[599,6278,694],{"class":605},[599,6280,5176],{"class":697},[599,6282,1029],{"class":666},[599,6284,6285],{"class":601,"line":1880},[599,6286,1095],{"class":666},[599,6288,6289,6292,6294],{"class":601,"line":1946},[599,6290,6291],{"class":666},"        sid.",[599,6293,1310],{"class":609},[599,6295,1313],{"class":666},[599,6297,6298,6300,6302,6304,6306,6308,6310],{"class":601,"line":1951},[599,6299,1624],{"class":609},[599,6301,688],{"class":666},[599,6303,902],{"class":609},[599,6305,5694],{"class":666},[599,6307,1060],{"class":605},[599,6309,5111],{"class":609},[599,6311,6312],{"class":666},"(user);\n",[599,6314,6315,6317,6320,6323],{"class":601,"line":1967},[599,6316,1100],{"class":605},[599,6318,6319],{"class":666}," (name.",[599,6321,6322],{"class":609},"empty",[599,6324,6325],{"class":666},"())\n",[599,6327,6328,6330,6332],{"class":601,"line":1982},[599,6329,2040],{"class":605},[599,6331,1411],{"class":949},[599,6333,1066],{"class":666},[599,6335,6336],{"class":601,"line":1997},[599,6337,651],{"emptyLinePlaceholder":650},[599,6339,6340,6343,6345,6347,6349,6351],{"class":601,"line":2002},[599,6341,6342],{"class":666},"        WCHAR computer[MAX_COMPUTERNAME_LENGTH ",[599,6344,2543],{"class":605},[599,6346,973],{"class":949},[599,6348,2491],{"class":666},[599,6350,1060],{"class":605},[599,6352,5921],{"class":666},[599,6354,6355,6358,6361,6363,6366],{"class":601,"line":2024},[599,6356,6357],{"class":609},"        DWORD",[599,6359,6360],{"class":666}," cchComputer ",[599,6362,1060],{"class":605},[599,6364,6365],{"class":609}," ARRAYSIZE",[599,6367,6368],{"class":666},"(computer);\n",[599,6370,6371,6373,6375,6377,6380,6383,6385],{"class":601,"line":2037},[599,6372,1100],{"class":605},[599,6374,1327],{"class":666},[599,6376,2435],{"class":605},[599,6378,6379],{"class":609},"GetComputerNameW",[599,6381,6382],{"class":666},"(computer, ",[599,6384,694],{"class":605},[599,6386,6387],{"class":666},"cchComputer))\n",[599,6389,6390,6392,6394],{"class":601,"line":2047},[599,6391,2040],{"class":605},[599,6393,1411],{"class":949},[599,6395,1066],{"class":666},[599,6397,6398],{"class":601,"line":2052},[599,6399,651],{"emptyLinePlaceholder":650},[599,6401,6402,6404,6406,6408,6411,6413,6415,6417,6419,6422,6424,6427,6429,6431,6433],{"class":601,"line":2096},[599,6403,1624],{"class":609},[599,6405,688],{"class":666},[599,6407,902],{"class":609},[599,6409,6410],{"class":666}," qualified ",[599,6412,1060],{"class":605},[599,6414,685],{"class":609},[599,6416,688],{"class":666},[599,6418,902],{"class":609},[599,6420,6421],{"class":666},"(computer) ",[599,6423,2543],{"class":605},[599,6425,6426],{"class":619}," L\"",[599,6428,5576],{"class":949},[599,6430,4362],{"class":619},[599,6432,1201],{"class":605},[599,6434,5803],{"class":666},[599,6436,6437,6439],{"class":601,"line":2124},[599,6438,2320],{"class":609},[599,6440,6441],{"class":666}," sidBuf[SECURITY_MAX_SID_SIZE];\n",[599,6443,6444,6446,6449,6451,6454],{"class":601,"line":2129},[599,6445,6357],{"class":609},[599,6447,6448],{"class":666}," cbSid ",[599,6450,1060],{"class":605},[599,6452,6453],{"class":605}," sizeof",[599,6455,6456],{"class":666},"(sidBuf);\n",[599,6458,6459,6462,6465,6467,6469],{"class":601,"line":2163},[599,6460,6461],{"class":666},"        WCHAR domain[",[599,6463,6464],{"class":949},"256",[599,6466,2491],{"class":666},[599,6468,1060],{"class":605},[599,6470,5921],{"class":666},[599,6472,6473,6475,6478,6480,6482],{"class":601,"line":2186},[599,6474,6357],{"class":609},[599,6476,6477],{"class":666}," cchDomain ",[599,6479,1060],{"class":605},[599,6481,6365],{"class":609},[599,6483,6484],{"class":666},"(domain);\n",[599,6486,6487,6490],{"class":601,"line":2195},[599,6488,6489],{"class":609},"        SID_NAME_USE",[599,6491,6492],{"class":666}," use;\n",[599,6494,6495,6497,6499,6501,6504,6506,6508,6511,6514,6517,6519],{"class":601,"line":2200},[599,6496,1100],{"class":605},[599,6498,1327],{"class":666},[599,6500,2435],{"class":605},[599,6502,6503],{"class":609},"LookupAccountNameW",[599,6505,679],{"class":666},[599,6507,2019],{"class":949},[599,6509,6510],{"class":666},", qualified.",[599,6512,6513],{"class":609},"c_str",[599,6515,6516],{"class":666},"(), sidBuf, ",[599,6518,694],{"class":605},[599,6520,6521],{"class":666},"cbSid,\n",[599,6523,6524,6527,6529,6532,6534],{"class":601,"line":2212},[599,6525,6526],{"class":666},"                                domain, ",[599,6528,694],{"class":605},[599,6530,6531],{"class":666},"cchDomain, ",[599,6533,694],{"class":605},[599,6535,6536],{"class":666},"use))\n",[599,6538,6539,6541,6543],{"class":601,"line":2220},[599,6540,2040],{"class":605},[599,6542,1411],{"class":949},[599,6544,1066],{"class":666},[599,6546,6547],{"class":601,"line":2225},[599,6548,651],{"emptyLinePlaceholder":650},[599,6550,6551],{"class":601,"line":2230},[599,6552,6553],{"class":772},"        \u002F\u002F The account has to live in this computer's SAM, not in a domain.\n",[599,6555,6556,6558,6561,6563,6566,6569,6572,6575,6577,6579],{"class":601,"line":2265},[599,6557,1100],{"class":605},[599,6559,6560],{"class":666}," (use ",[599,6562,2030],{"class":605},[599,6564,6565],{"class":666}," SidTypeUser ",[599,6567,6568],{"class":605},"||",[599,6570,6571],{"class":609}," _wcsicmp",[599,6573,6574],{"class":666},"(domain, computer) ",[599,6576,2030],{"class":605},[599,6578,1286],{"class":949},[599,6580,1029],{"class":666},[599,6582,6583,6585,6587],{"class":601,"line":2286},[599,6584,2040],{"class":605},[599,6586,1411],{"class":949},[599,6588,1066],{"class":666},[599,6590,6591],{"class":601,"line":2291},[599,6592,651],{"emptyLinePlaceholder":650},[599,6594,6595,6598,6601,6603,6605],{"class":601,"line":2297},[599,6596,6597],{"class":609},"        PWSTR",[599,6599,6600],{"class":666}," pszSid ",[599,6602,1060],{"class":605},[599,6604,1962],{"class":949},[599,6606,1066],{"class":666},[599,6608,6609,6611,6613,6615,6618,6621,6623],{"class":601,"line":2317},[599,6610,1100],{"class":605},[599,6612,1327],{"class":666},[599,6614,2435],{"class":605},[599,6616,6617],{"class":609},"ConvertSidToStringSidW",[599,6619,6620],{"class":666},"(sidBuf, ",[599,6622,694],{"class":605},[599,6624,6625],{"class":666},"pszSid))\n",[599,6627,6628,6630,6632],{"class":601,"line":2331},[599,6629,2040],{"class":605},[599,6631,1411],{"class":949},[599,6633,1066],{"class":666},[599,6635,6636,6639,6641],{"class":601,"line":2361},[599,6637,6638],{"class":666},"        sid ",[599,6640,1060],{"class":605},[599,6642,6643],{"class":666}," pszSid;\n",[599,6645,6646,6648],{"class":601,"line":2366},[599,6647,6018],{"class":609},[599,6649,6650],{"class":666},"(pszSid);\n",[599,6652,6653,6655,6657],{"class":601,"line":2393},[599,6654,1211],{"class":605},[599,6656,1572],{"class":949},[599,6658,1066],{"class":666},[599,6660,6661],{"class":601,"line":2406},[599,6662,1224],{"class":666},[599,6664,6665],{"class":601,"line":2411},[599,6666,651],{"emptyLinePlaceholder":650},[599,6668,6669],{"class":601,"line":2416},[599,6670,6671],{"class":772},"    \u002F\u002F Only SIDs are used as value names. This keeps odd input out of the registry.\n",[599,6673,6674,6676,6678,6681,6683,6685,6687,6689,6691,6693,6695],{"class":601,"line":2428},[599,6675,1048],{"class":605},[599,6677,1885],{"class":605},[599,6679,6680],{"class":609}," IsSidString",[599,6682,679],{"class":666},[599,6684,682],{"class":605},[599,6686,685],{"class":609},[599,6688,688],{"class":666},[599,6690,902],{"class":609},[599,6692,694],{"class":605},[599,6694,5176],{"class":697},[599,6696,1029],{"class":666},[599,6698,6699],{"class":601,"line":2450},[599,6700,1095],{"class":666},[599,6702,6703,6705,6708,6710,6712,6714,6717,6719,6721,6724,6726,6728,6730,6733,6735,6738,6740,6742,6744],{"class":601,"line":2459},[599,6704,1211],{"class":605},[599,6706,6707],{"class":666}," sid.",[599,6709,2108],{"class":609},[599,6711,2840],{"class":666},[599,6713,717],{"class":605},[599,6715,6716],{"class":949}," 4",[599,6718,1112],{"class":605},[599,6720,6707],{"class":666},[599,6722,6723],{"class":609},"compare",[599,6725,679],{"class":666},[599,6727,2074],{"class":949},[599,6729,212],{"class":666},[599,6731,6732],{"class":949},"4",[599,6734,212],{"class":666},[599,6736,6737],{"class":619},"L\"S-1-\"",[599,6739,1124],{"class":666},[599,6741,1349],{"class":605},[599,6743,1286],{"class":949},[599,6745,1066],{"class":666},[599,6747,6748],{"class":601,"line":2464},[599,6749,1224],{"class":666},[599,6751,6752],{"class":601,"line":2470},[599,6753,651],{"emptyLinePlaceholder":650},[599,6755,6756],{"class":601,"line":2476},[599,6757,6758],{"class":772},"    \u002F\u002F Creates or opens a key below HKLM with our ACL. The security attributes\n",[599,6760,6761],{"class":601,"line":2503},[599,6762,6763],{"class":772},"    \u002F\u002F only apply when the key is created. An existing key might still carry a\n",[599,6765,6766],{"class":601,"line":2537},[599,6767,6768],{"class":772},"    \u002F\u002F weaker ACL, so it is set again.\n",[599,6770,6771,6773,6776,6779,6781,6783,6786,6789,6791,6794,6796,6799],{"class":601,"line":2569},[599,6772,1048],{"class":605},[599,6774,6775],{"class":609}," LSTATUS",[599,6777,6778],{"class":609}," OpenProtectedKey",[599,6780,679],{"class":666},[599,6782,682],{"class":605},[599,6784,6785],{"class":605}," wchar_t*",[599,6787,6788],{"class":697}," path",[599,6790,212],{"class":666},[599,6792,6793],{"class":609},"HKEY",[599,6795,748],{"class":605},[599,6797,6798],{"class":697}," phKey",[599,6800,1029],{"class":666},[599,6802,6803],{"class":601,"line":2600},[599,6804,1095],{"class":666},[599,6806,6807,6810,6813,6815,6817],{"class":601,"line":2623},[599,6808,6809],{"class":609},"        PSECURITY_DESCRIPTOR",[599,6811,6812],{"class":666}," psd ",[599,6814,1060],{"class":605},[599,6816,1962],{"class":949},[599,6818,1066],{"class":666},[599,6820,6821,6823,6825,6827,6830],{"class":601,"line":2628},[599,6822,1100],{"class":605},[599,6824,1327],{"class":666},[599,6826,2435],{"class":605},[599,6828,6829],{"class":609},"ConvertStringSecurityDescriptorToSecurityDescriptorW",[599,6831,6832],{"class":666},"(kKeySddl, SDDL_REVISION_1,\n",[599,6834,6835,6838,6841,6843],{"class":601,"line":2642},[599,6836,6837],{"class":605},"                                                                  &",[599,6839,6840],{"class":666},"psd, ",[599,6842,2019],{"class":949},[599,6844,6845],{"class":666},"))\n",[599,6847,6848,6850,6852,6855,6857,6859,6862],{"class":601,"line":2668},[599,6849,2040],{"class":605},[599,6851,2374],{"class":605},[599,6853,6854],{"class":666},"LSTATUS",[599,6856,717],{"class":605},[599,6858,679],{"class":666},[599,6860,6861],{"class":609},"GetLastError",[599,6863,6864],{"class":666},"());\n",[599,6866,6867],{"class":601,"line":2682},[599,6868,651],{"emptyLinePlaceholder":650},[599,6870,6871,6874,6877,6879,6881,6883],{"class":601,"line":2698},[599,6872,6873],{"class":609},"        SECURITY_ATTRIBUTES",[599,6875,6876],{"class":666}," sa ",[599,6878,1060],{"class":605},[599,6880,5873],{"class":666},[599,6882,2444],{"class":605},[599,6884,6885],{"class":666},"(sa), psd, FALSE };\n",[599,6887,6888,6890,6893,6895,6897],{"class":601,"line":2707},[599,6889,6357],{"class":609},[599,6891,6892],{"class":666}," disposition ",[599,6894,1060],{"class":605},[599,6896,1286],{"class":949},[599,6898,1066],{"class":666},[599,6900,6901,6904,6907,6909,6912,6915,6917,6919,6921,6923,6925],{"class":601,"line":2712},[599,6902,6903],{"class":609},"        LSTATUS",[599,6905,6906],{"class":666}," status ",[599,6908,1060],{"class":605},[599,6910,6911],{"class":609}," RegCreateKeyExW",[599,6913,6914],{"class":666},"(HKEY_LOCAL_MACHINE, path, ",[599,6916,2074],{"class":949},[599,6918,212],{"class":666},[599,6920,2019],{"class":949},[599,6922,212],{"class":666},[599,6924,2074],{"class":949},[599,6926,813],{"class":666},[599,6928,6929,6932,6934,6937,6939],{"class":601,"line":2717},[599,6930,6931],{"class":666},"                                         KEY_SET_VALUE ",[599,6933,1440],{"class":605},[599,6935,6936],{"class":666}," KEY_QUERY_VALUE ",[599,6938,1440],{"class":605},[599,6940,6941],{"class":666}," WRITE_DAC,\n",[599,6943,6944,6947,6950,6952],{"class":601,"line":2760},[599,6945,6946],{"class":605},"                                         &",[599,6948,6949],{"class":666},"sa, phKey, ",[599,6951,694],{"class":605},[599,6953,6954],{"class":666},"disposition);\n",[599,6956,6957,6959,6962,6964,6967,6969,6971,6973],{"class":601,"line":2781},[599,6958,1100],{"class":605},[599,6960,6961],{"class":666}," (status ",[599,6963,1349],{"class":605},[599,6965,6966],{"class":666}," ERROR_SUCCESS ",[599,6968,3154],{"class":605},[599,6970,6892],{"class":666},[599,6972,1349],{"class":605},[599,6974,6975],{"class":666}," REG_OPENED_EXISTING_KEY)\n",[599,6977,6978],{"class":601,"line":2802},[599,6979,1338],{"class":666},[599,6981,6982,6985,6987,6990,6992,6994],{"class":601,"line":2807},[599,6983,6984],{"class":666},"            status ",[599,6986,1060],{"class":605},[599,6988,6989],{"class":609}," RegSetKeySecurity",[599,6991,679],{"class":666},[599,6993,748],{"class":605},[599,6995,6996],{"class":666},"phKey, DACL_SECURITY_INFORMATION, psd);\n",[599,6998,6999,7001,7003,7005],{"class":601,"line":2819},[599,7000,1344],{"class":605},[599,7002,6961],{"class":666},[599,7004,2030],{"class":605},[599,7006,7007],{"class":666}," ERROR_SUCCESS)\n",[599,7009,7010],{"class":601,"line":2824},[599,7011,1480],{"class":666},[599,7013,7014,7017,7019,7021],{"class":601,"line":2830},[599,7015,7016],{"class":609},"                RegCloseKey",[599,7018,679],{"class":666},[599,7020,748],{"class":605},[599,7022,7023],{"class":666},"phKey);\n",[599,7025,7026,7029,7032,7034,7036],{"class":601,"line":2851},[599,7027,7028],{"class":605},"                *",[599,7030,7031],{"class":666},"phKey ",[599,7033,1060],{"class":605},[599,7035,1962],{"class":949},[599,7037,1066],{"class":666},[599,7039,7040],{"class":601,"line":2860},[599,7041,1558],{"class":666},[599,7043,7044],{"class":601,"line":2874},[599,7045,1564],{"class":666},[599,7047,7048],{"class":601,"line":2887},[599,7049,651],{"emptyLinePlaceholder":650},[599,7051,7052,7054],{"class":601,"line":2892},[599,7053,6018],{"class":609},[599,7055,7056],{"class":666},"(psd);\n",[599,7058,7059,7061],{"class":601,"line":2915},[599,7060,1211],{"class":605},[599,7062,7063],{"class":666}," status;\n",[599,7065,7066],{"class":601,"line":2924},[599,7067,1224],{"class":666},[599,7069,7070],{"class":601,"line":2951},[599,7071,651],{"emptyLinePlaceholder":650},[599,7073,7074,7076,7078,7080,7082,7084,7086,7088,7090,7092,7094,7096,7098,7100,7102,7104,7106],{"class":601,"line":2956},[599,7075,673],{"class":605},[599,7077,5199],{"class":609},[599,7079,679],{"class":666},[599,7081,682],{"class":605},[599,7083,685],{"class":609},[599,7085,688],{"class":666},[599,7087,902],{"class":609},[599,7089,694],{"class":605},[599,7091,5176],{"class":697},[599,7093,212],{"class":666},[599,7095,682],{"class":605},[599,7097,685],{"class":609},[599,7099,688],{"class":666},[599,7101,691],{"class":609},[599,7103,694],{"class":605},[599,7105,5228],{"class":697},[599,7107,1029],{"class":666},[599,7109,7110],{"class":601,"line":2961},[599,7111,1095],{"class":666},[599,7113,7114,7116,7118,7120,7123],{"class":601,"line":2982},[599,7115,1100],{"class":605},[599,7117,1327],{"class":666},[599,7119,2435],{"class":605},[599,7121,7122],{"class":609},"IsSidString",[599,7124,7125],{"class":666},"(sid))\n",[599,7127,7128,7130,7132],{"class":601,"line":3011},[599,7129,2040],{"class":605},[599,7131,1411],{"class":949},[599,7133,1066],{"class":666},[599,7135,7136],{"class":601,"line":3016},[599,7137,651],{"emptyLinePlaceholder":650},[599,7139,7140,7142,7144,7146,7148,7150],{"class":601,"line":3044},[599,7141,1624],{"class":609},[599,7143,688],{"class":666},[599,7145,708],{"class":609},[599,7147,711],{"class":666},[599,7149,714],{"class":609},[599,7151,7152],{"class":666},"> blob;\n",[599,7154,7155,7157,7159,7161,7164],{"class":601,"line":3051},[599,7156,1100],{"class":605},[599,7158,1327],{"class":666},[599,7160,2435],{"class":605},[599,7162,7163],{"class":609},"Protect",[599,7165,7166],{"class":666},"(base32Secret, blob))\n",[599,7168,7169,7171,7173],{"class":601,"line":3073},[599,7170,2040],{"class":605},[599,7172,1411],{"class":949},[599,7174,1066],{"class":666},[599,7176,7177],{"class":601,"line":3078},[599,7178,651],{"emptyLinePlaceholder":650},[599,7180,7181,7184,7187,7189,7191],{"class":601,"line":3084},[599,7182,7183],{"class":609},"        HKEY",[599,7185,7186],{"class":666}," hKey ",[599,7188,1060],{"class":605},[599,7190,1962],{"class":949},[599,7192,1066],{"class":666},[599,7194,7195,7197,7199,7201,7203,7206,7208],{"class":601,"line":3090},[599,7196,6903],{"class":609},[599,7198,6906],{"class":666},[599,7200,1060],{"class":605},[599,7202,6778],{"class":609},[599,7204,7205],{"class":666},"(kKeyPath, ",[599,7207,694],{"class":605},[599,7209,7210],{"class":666},"hKey);\n",[599,7212,7213,7215,7217,7219],{"class":601,"line":3096},[599,7214,1100],{"class":605},[599,7216,6961],{"class":666},[599,7218,1349],{"class":605},[599,7220,7007],{"class":666},[599,7222,7223],{"class":601,"line":3109},[599,7224,1338],{"class":666},[599,7226,7227,7229,7231,7234,7237,7239,7242,7244],{"class":601,"line":3116},[599,7228,6984],{"class":666},[599,7230,1060],{"class":605},[599,7232,7233],{"class":609}," RegSetValueExW",[599,7235,7236],{"class":666},"(hKey, sid.",[599,7238,6513],{"class":609},[599,7240,7241],{"class":666},"(), ",[599,7243,2074],{"class":949},[599,7245,7246],{"class":666},", REG_BINARY,\n",[599,7248,7249,7252,7254,7256,7258,7260,7262,7264,7266],{"class":601,"line":3121},[599,7250,7251],{"class":666},"                                    blob.",[599,7253,2090],{"class":609},[599,7255,7241],{"class":666},[599,7257,1507],{"class":605},[599,7259,5878],{"class":666},[599,7261,717],{"class":605},[599,7263,6103],{"class":666},[599,7265,2108],{"class":609},[599,7267,7268],{"class":666},"()));\n",[599,7270,7271,7274],{"class":601,"line":3136},[599,7272,7273],{"class":609},"            RegCloseKey",[599,7275,7276],{"class":666},"(hKey);\n",[599,7278,7279],{"class":601,"line":3164},[599,7280,1564],{"class":666},[599,7282,7283,7285,7287,7289],{"class":601,"line":3169},[599,7284,1211],{"class":605},[599,7286,6906],{"class":666},[599,7288,1349],{"class":605},[599,7290,7291],{"class":666}," ERROR_SUCCESS;\n",[599,7293,7294],{"class":601,"line":3180},[599,7295,1224],{"class":666},[599,7297,7298],{"class":601,"line":3189},[599,7299,651],{"emptyLinePlaceholder":650},[599,7301,7302,7304,7306,7308,7310,7312,7314,7316,7318,7320,7322,7324,7326,7328,7330,7332,7334,7336,7338],{"class":601,"line":3194},[599,7303,673],{"class":605},[599,7305,5237],{"class":609},[599,7307,679],{"class":666},[599,7309,682],{"class":605},[599,7311,685],{"class":609},[599,7313,688],{"class":666},[599,7315,902],{"class":609},[599,7317,694],{"class":605},[599,7319,5176],{"class":697},[599,7321,212],{"class":666},[599,7323,703],{"class":609},[599,7325,688],{"class":666},[599,7327,708],{"class":609},[599,7329,711],{"class":666},[599,7331,714],{"class":609},[599,7333,717],{"class":666},[599,7335,694],{"class":605},[599,7337,802],{"class":697},[599,7339,1029],{"class":666},[599,7341,7342],{"class":601,"line":3199},[599,7343,1095],{"class":666},[599,7345,7346,7349,7351],{"class":601,"line":3208},[599,7347,7348],{"class":666},"        key.",[599,7350,1310],{"class":609},[599,7352,1313],{"class":666},[599,7354,7355,7357,7359,7361,7363],{"class":601,"line":3213},[599,7356,1100],{"class":605},[599,7358,1327],{"class":666},[599,7360,2435],{"class":605},[599,7362,7122],{"class":609},[599,7364,7125],{"class":666},[599,7366,7368,7370,7372],{"class":601,"line":7367},158,[599,7369,2040],{"class":605},[599,7371,1411],{"class":949},[599,7373,1066],{"class":666},[599,7375,7377],{"class":601,"line":7376},159,[599,7378,651],{"emptyLinePlaceholder":650},[599,7380,7382,7384,7386,7388,7390],{"class":601,"line":7381},160,[599,7383,7183],{"class":609},[599,7385,7186],{"class":666},[599,7387,1060],{"class":605},[599,7389,1962],{"class":949},[599,7391,1066],{"class":666},[599,7393,7395,7397,7399,7402,7405,7407,7410,7412,7415,7417],{"class":601,"line":7394},161,[599,7396,1100],{"class":605},[599,7398,1327],{"class":666},[599,7400,7401],{"class":609},"RegOpenKeyExW",[599,7403,7404],{"class":666},"(HKEY_LOCAL_MACHINE, kKeyPath, ",[599,7406,2074],{"class":949},[599,7408,7409],{"class":666},", KEY_QUERY_VALUE, ",[599,7411,694],{"class":605},[599,7413,7414],{"class":666},"hKey) ",[599,7416,2030],{"class":605},[599,7418,7007],{"class":666},[599,7420,7422,7424,7426],{"class":601,"line":7421},162,[599,7423,2040],{"class":605},[599,7425,1411],{"class":949},[599,7427,1066],{"class":666},[599,7429,7431],{"class":601,"line":7430},163,[599,7432,651],{"emptyLinePlaceholder":650},[599,7434,7436,7438,7441,7443,7445],{"class":601,"line":7435},164,[599,7437,6357],{"class":609},[599,7439,7440],{"class":666}," type ",[599,7442,1060],{"class":605},[599,7444,1286],{"class":949},[599,7446,1066],{"class":666},[599,7448,7450,7452,7455,7457,7459],{"class":601,"line":7449},165,[599,7451,6357],{"class":609},[599,7453,7454],{"class":666}," cb ",[599,7456,1060],{"class":605},[599,7458,1286],{"class":949},[599,7460,1066],{"class":666},[599,7462,7464,7466,7468,7470,7472,7474],{"class":601,"line":7463},166,[599,7465,1624],{"class":609},[599,7467,688],{"class":666},[599,7469,708],{"class":609},[599,7471,711],{"class":666},[599,7473,714],{"class":609},[599,7475,7152],{"class":666},[599,7477,7479,7481,7483,7485,7488,7490,7492,7494,7496,7498,7500,7503,7505,7507,7509],{"class":601,"line":7478},167,[599,7480,6903],{"class":609},[599,7482,6906],{"class":666},[599,7484,1060],{"class":605},[599,7486,7487],{"class":609}," RegQueryValueExW",[599,7489,7236],{"class":666},[599,7491,6513],{"class":609},[599,7493,7241],{"class":666},[599,7495,2019],{"class":949},[599,7497,212],{"class":666},[599,7499,694],{"class":605},[599,7501,7502],{"class":666},"type, ",[599,7504,2019],{"class":949},[599,7506,212],{"class":666},[599,7508,694],{"class":605},[599,7510,7511],{"class":666},"cb);\n",[599,7513,7515,7517,7519,7521,7523,7525,7527,7529,7532,7534,7536,7538,7540],{"class":601,"line":7514},168,[599,7516,1100],{"class":605},[599,7518,6961],{"class":666},[599,7520,1349],{"class":605},[599,7522,6966],{"class":666},[599,7524,3154],{"class":605},[599,7526,7440],{"class":666},[599,7528,1349],{"class":605},[599,7530,7531],{"class":666}," REG_BINARY ",[599,7533,3154],{"class":605},[599,7535,7454],{"class":666},[599,7537,717],{"class":605},[599,7539,1286],{"class":949},[599,7541,1029],{"class":666},[599,7543,7545],{"class":601,"line":7544},169,[599,7546,1338],{"class":666},[599,7548,7550,7553,7556],{"class":601,"line":7549},170,[599,7551,7552],{"class":666},"            blob.",[599,7554,7555],{"class":609},"resize",[599,7557,7558],{"class":666},"(cb);\n",[599,7560,7562,7564,7566,7568,7570,7572,7574,7576,7578,7580,7583,7585,7587,7589],{"class":601,"line":7561},171,[599,7563,6984],{"class":666},[599,7565,1060],{"class":605},[599,7567,7487],{"class":609},[599,7569,7236],{"class":666},[599,7571,6513],{"class":609},[599,7573,7241],{"class":666},[599,7575,2019],{"class":949},[599,7577,212],{"class":666},[599,7579,694],{"class":605},[599,7581,7582],{"class":666},"type, blob.",[599,7584,2090],{"class":609},[599,7586,7241],{"class":666},[599,7588,694],{"class":605},[599,7590,7511],{"class":666},[599,7592,7594],{"class":601,"line":7593},172,[599,7595,1564],{"class":666},[599,7597,7599,7602],{"class":601,"line":7598},173,[599,7600,7601],{"class":609},"        RegCloseKey",[599,7603,7276],{"class":666},[599,7605,7607,7609,7611,7613,7615,7617,7620,7622],{"class":601,"line":7606},174,[599,7608,1100],{"class":605},[599,7610,6961],{"class":666},[599,7612,2030],{"class":605},[599,7614,6966],{"class":666},[599,7616,6568],{"class":605},[599,7618,7619],{"class":666}," blob.",[599,7621,6322],{"class":609},[599,7623,6325],{"class":666},[599,7625,7627,7629,7631],{"class":601,"line":7626},175,[599,7628,2040],{"class":605},[599,7630,1411],{"class":949},[599,7632,1066],{"class":666},[599,7634,7636],{"class":601,"line":7635},176,[599,7637,651],{"emptyLinePlaceholder":650},[599,7639,7641,7643,7645,7647],{"class":601,"line":7640},177,[599,7642,1624],{"class":609},[599,7644,688],{"class":666},[599,7646,691],{"class":609},[599,7648,7649],{"class":666}," base32;\n",[599,7651,7653,7655,7657,7659,7662],{"class":601,"line":7652},178,[599,7654,1100],{"class":605},[599,7656,1327],{"class":666},[599,7658,2435],{"class":605},[599,7660,7661],{"class":609},"Unprotect",[599,7663,7664],{"class":666},"(blob, base32))\n",[599,7666,7668,7670,7672],{"class":601,"line":7667},179,[599,7669,2040],{"class":605},[599,7671,1411],{"class":949},[599,7673,1066],{"class":666},[599,7675,7677],{"class":601,"line":7676},180,[599,7678,651],{"emptyLinePlaceholder":650},[599,7680,7682,7684,7686,7688,7690],{"class":601,"line":7681},181,[599,7683,1985],{"class":605},[599,7685,1988],{"class":666},[599,7687,1060],{"class":605},[599,7689,1235],{"class":609},[599,7691,7692],{"class":666},"(base32, key);\n",[599,7694,7696,7698,7700,7702,7705,7707,7710,7712],{"class":601,"line":7695},182,[599,7697,6213],{"class":609},[599,7699,679],{"class":666},[599,7701,694],{"class":605},[599,7703,7704],{"class":666},"base32[",[599,7706,2074],{"class":949},[599,7708,7709],{"class":666},"], base32.",[599,7711,2108],{"class":609},[599,7713,6864],{"class":666},[599,7715,7717],{"class":601,"line":7716},183,[599,7718,651],{"emptyLinePlaceholder":650},[599,7720,7722],{"class":601,"line":7721},184,[599,7723,7724],{"class":772},"        \u002F\u002F An empty or very short key would make the code predictable. Our\n",[599,7726,7728],{"class":601,"line":7727},185,[599,7729,7730],{"class":772},"        \u002F\u002F secrets have 20 bytes; anything under 16 counts as broken.\n",[599,7732,7734,7736,7738,7740,7743,7745,7748,7750,7752,7754,7756],{"class":601,"line":7733},186,[599,7735,1100],{"class":605},[599,7737,1327],{"class":666},[599,7739,2435],{"class":605},[599,7741,7742],{"class":666},"ok ",[599,7744,6568],{"class":605},[599,7746,7747],{"class":666}," key.",[599,7749,2108],{"class":609},[599,7751,2840],{"class":666},[599,7753,711],{"class":605},[599,7755,2562],{"class":949},[599,7757,1029],{"class":666},[599,7759,7761],{"class":601,"line":7760},187,[599,7762,1338],{"class":666},[599,7764,7766,7768,7770,7772,7775,7777],{"class":601,"line":7765},188,[599,7767,1344],{"class":605},[599,7769,1327],{"class":666},[599,7771,2435],{"class":605},[599,7773,7774],{"class":666},"key.",[599,7776,6322],{"class":609},[599,7778,6325],{"class":666},[599,7780,7782,7785,7787,7789,7792,7794],{"class":601,"line":7781},189,[599,7783,7784],{"class":609},"                SecureZeroMemory",[599,7786,2087],{"class":666},[599,7788,2090],{"class":609},[599,7790,7791],{"class":666},"(), key.",[599,7793,2108],{"class":609},[599,7795,6864],{"class":666},[599,7797,7799,7802,7804],{"class":601,"line":7798},190,[599,7800,7801],{"class":666},"            key.",[599,7803,1310],{"class":609},[599,7805,1313],{"class":666},[599,7807,7809,7811,7813],{"class":601,"line":7808},191,[599,7810,2040],{"class":605},[599,7812,1411],{"class":949},[599,7814,1066],{"class":666},[599,7816,7818],{"class":601,"line":7817},192,[599,7819,1564],{"class":666},[599,7821,7823,7825,7827],{"class":601,"line":7822},193,[599,7824,1211],{"class":605},[599,7826,1572],{"class":949},[599,7828,1066],{"class":666},[599,7830,7832],{"class":601,"line":7831},194,[599,7833,1224],{"class":666},[599,7835,7837],{"class":601,"line":7836},195,[599,7838,651],{"emptyLinePlaceholder":650},[599,7840,7842,7844,7846,7848,7850,7852,7854,7856,7858,7860,7862,7864,7866,7868],{"class":601,"line":7841},196,[599,7843,673],{"class":605},[599,7845,5373],{"class":609},[599,7847,679],{"class":666},[599,7849,682],{"class":605},[599,7851,685],{"class":609},[599,7853,688],{"class":666},[599,7855,902],{"class":609},[599,7857,694],{"class":605},[599,7859,5176],{"class":697},[599,7861,212],{"class":666},[599,7863,5392],{"class":609},[599,7865,694],{"class":605},[599,7867,5397],{"class":697},[599,7869,1029],{"class":666},[599,7871,7873],{"class":601,"line":7872},197,[599,7874,1095],{"class":666},[599,7876,7878,7881,7883,7885,7888,7890],{"class":601,"line":7877},198,[599,7879,7880],{"class":609},"        ZeroMemory",[599,7882,679],{"class":666},[599,7884,694],{"class":605},[599,7886,7887],{"class":666},"state, ",[599,7889,2444],{"class":605},[599,7891,7892],{"class":666},"(state));\n",[599,7894,7896,7898,7900,7902,7904],{"class":601,"line":7895},199,[599,7897,1100],{"class":605},[599,7899,1327],{"class":666},[599,7901,2435],{"class":605},[599,7903,7122],{"class":609},[599,7905,7125],{"class":666},[599,7907,7909,7911,7913],{"class":601,"line":7908},200,[599,7910,2040],{"class":605},[599,7912,1411],{"class":949},[599,7914,1066],{"class":666},[599,7916,7918],{"class":601,"line":7917},201,[599,7919,651],{"emptyLinePlaceholder":650},[599,7921,7923,7925,7927,7929,7931],{"class":601,"line":7922},202,[599,7924,7183],{"class":609},[599,7926,7186],{"class":666},[599,7928,1060],{"class":605},[599,7930,1962],{"class":949},[599,7932,1066],{"class":666},[599,7934,7936,7938,7940,7942,7945,7948,7950,7952,7954],{"class":601,"line":7935},203,[599,7937,6903],{"class":609},[599,7939,6906],{"class":666},[599,7941,1060],{"class":605},[599,7943,7944],{"class":609}," RegOpenKeyExW",[599,7946,7947],{"class":666},"(HKEY_LOCAL_MACHINE, kStatePath, ",[599,7949,2074],{"class":949},[599,7951,7409],{"class":666},[599,7953,694],{"class":605},[599,7955,7210],{"class":666},[599,7957,7959,7961,7963,7965],{"class":601,"line":7958},204,[599,7960,1100],{"class":605},[599,7962,6961],{"class":666},[599,7964,1349],{"class":605},[599,7966,7967],{"class":666}," ERROR_FILE_NOT_FOUND)\n",[599,7969,7971,7973,7975,7977],{"class":601,"line":7970},205,[599,7972,2040],{"class":605},[599,7974,1572],{"class":949},[599,7976,1549],{"class":666},[599,7978,7979],{"class":772},"                      \u002F\u002F nobody has logged on yet\n",[599,7981,7983,7985,7987,7989],{"class":601,"line":7982},206,[599,7984,1100],{"class":605},[599,7986,6961],{"class":666},[599,7988,2030],{"class":605},[599,7990,7007],{"class":666},[599,7992,7994,7996,7998],{"class":601,"line":7993},207,[599,7995,2040],{"class":605},[599,7997,1411],{"class":949},[599,7999,1066],{"class":666},[599,8001,8003],{"class":601,"line":8002},208,[599,8004,651],{"emptyLinePlaceholder":650},[599,8006,8008,8010,8012,8014,8016],{"class":601,"line":8007},209,[599,8009,6357],{"class":609},[599,8011,7440],{"class":666},[599,8013,1060],{"class":605},[599,8015,1286],{"class":949},[599,8017,1066],{"class":666},[599,8019,8021,8023,8025,8027,8029],{"class":601,"line":8020},210,[599,8022,6357],{"class":609},[599,8024,7454],{"class":666},[599,8026,1060],{"class":605},[599,8028,6453],{"class":605},[599,8030,8031],{"class":666},"(state);\n",[599,8033,8035,8038,8040,8042,8044,8046,8048,8050,8052,8054],{"class":601,"line":8034},211,[599,8036,8037],{"class":666},"        status ",[599,8039,1060],{"class":605},[599,8041,7487],{"class":609},[599,8043,7236],{"class":666},[599,8045,6513],{"class":609},[599,8047,7241],{"class":666},[599,8049,2019],{"class":949},[599,8051,212],{"class":666},[599,8053,694],{"class":605},[599,8055,8056],{"class":666},"type,\n",[599,8058,8060,8063,8065,8067,8069,8071,8074,8076],{"class":601,"line":8059},212,[599,8061,8062],{"class":605},"                                  reinterpret_cast\u003C",[599,8064,714],{"class":666},[599,8066,5897],{"class":605},[599,8068,679],{"class":666},[599,8070,694],{"class":605},[599,8072,8073],{"class":666},"state), ",[599,8075,694],{"class":605},[599,8077,7511],{"class":666},[599,8079,8081,8083],{"class":601,"line":8080},213,[599,8082,7601],{"class":609},[599,8084,7276],{"class":666},[599,8086,8088],{"class":601,"line":8087},214,[599,8089,651],{"emptyLinePlaceholder":650},[599,8091,8093,8095,8097,8099],{"class":601,"line":8092},215,[599,8094,1100],{"class":605},[599,8096,6961],{"class":666},[599,8098,1349],{"class":605},[599,8100,7967],{"class":666},[599,8102,8104],{"class":601,"line":8103},216,[599,8105,1338],{"class":666},[599,8107,8109,8112,8114,8116,8118,8120],{"class":601,"line":8108},217,[599,8110,8111],{"class":609},"            ZeroMemory",[599,8113,679],{"class":666},[599,8115,694],{"class":605},[599,8117,7887],{"class":666},[599,8119,2444],{"class":605},[599,8121,7892],{"class":666},[599,8123,8125,8127,8129,8131],{"class":601,"line":8124},218,[599,8126,2040],{"class":605},[599,8128,1572],{"class":949},[599,8130,1549],{"class":666},[599,8132,8133],{"class":772},"                      \u002F\u002F this user has not logged on yet\n",[599,8135,8137],{"class":601,"line":8136},219,[599,8138,1564],{"class":666},[599,8140,8142],{"class":601,"line":8141},220,[599,8143,8144],{"class":772},"        \u002F\u002F Anything else that is not exactly our structure is an error. The\n",[599,8146,8148],{"class":601,"line":8147},221,[599,8149,8150],{"class":772},"        \u002F\u002F caller fails closed, so a broken value cannot reset the counters.\n",[599,8152,8154,8156,8158,8160,8162,8164,8166,8168,8170,8172,8174,8176,8178],{"class":601,"line":8153},222,[599,8155,1211],{"class":605},[599,8157,6906],{"class":666},[599,8159,1349],{"class":605},[599,8161,6966],{"class":666},[599,8163,3154],{"class":605},[599,8165,7440],{"class":666},[599,8167,1349],{"class":605},[599,8169,7531],{"class":666},[599,8171,3154],{"class":605},[599,8173,7454],{"class":666},[599,8175,1349],{"class":605},[599,8177,6453],{"class":605},[599,8179,8031],{"class":666},[599,8181,8183],{"class":601,"line":8182},223,[599,8184,1224],{"class":666},[599,8186,8188],{"class":601,"line":8187},224,[599,8189,651],{"emptyLinePlaceholder":650},[599,8191,8193,8195,8197,8199,8201,8203,8205,8207,8209,8211,8213,8215,8217,8219,8221],{"class":601,"line":8192},225,[599,8194,673],{"class":605},[599,8196,5406],{"class":609},[599,8198,679],{"class":666},[599,8200,682],{"class":605},[599,8202,685],{"class":609},[599,8204,688],{"class":666},[599,8206,902],{"class":609},[599,8208,694],{"class":605},[599,8210,5176],{"class":697},[599,8212,212],{"class":666},[599,8214,682],{"class":605},[599,8216,5427],{"class":609},[599,8218,694],{"class":605},[599,8220,5397],{"class":697},[599,8222,1029],{"class":666},[599,8224,8226],{"class":601,"line":8225},226,[599,8227,1095],{"class":666},[599,8229,8231,8233,8235,8237,8239],{"class":601,"line":8230},227,[599,8232,1100],{"class":605},[599,8234,1327],{"class":666},[599,8236,2435],{"class":605},[599,8238,7122],{"class":609},[599,8240,7125],{"class":666},[599,8242,8244,8246,8248],{"class":601,"line":8243},228,[599,8245,2040],{"class":605},[599,8247,1411],{"class":949},[599,8249,1066],{"class":666},[599,8251,8253],{"class":601,"line":8252},229,[599,8254,651],{"emptyLinePlaceholder":650},[599,8256,8258,8260,8262,8264,8266],{"class":601,"line":8257},230,[599,8259,7183],{"class":609},[599,8261,7186],{"class":666},[599,8263,1060],{"class":605},[599,8265,1962],{"class":949},[599,8267,1066],{"class":666},[599,8269,8271,8273,8275,8277,8279,8282,8284],{"class":601,"line":8270},231,[599,8272,6903],{"class":609},[599,8274,6906],{"class":666},[599,8276,1060],{"class":605},[599,8278,6778],{"class":609},[599,8280,8281],{"class":666},"(kStatePath, ",[599,8283,694],{"class":605},[599,8285,7210],{"class":666},[599,8287,8289,8291,8293,8295],{"class":601,"line":8288},232,[599,8290,1100],{"class":605},[599,8292,6961],{"class":666},[599,8294,1349],{"class":605},[599,8296,7007],{"class":666},[599,8298,8300],{"class":601,"line":8299},233,[599,8301,1338],{"class":666},[599,8303,8305,8307,8309,8311,8313,8315,8317,8319],{"class":601,"line":8304},234,[599,8306,6984],{"class":666},[599,8308,1060],{"class":605},[599,8310,7233],{"class":609},[599,8312,7236],{"class":666},[599,8314,6513],{"class":609},[599,8316,7241],{"class":666},[599,8318,2074],{"class":949},[599,8320,7246],{"class":666},[599,8322,8324,8327,8329,8331,8333,8335,8337,8339],{"class":601,"line":8323},235,[599,8325,8326],{"class":605},"                                    reinterpret_cast\u003Cconst",[599,8328,745],{"class":666},[599,8330,5897],{"class":605},[599,8332,679],{"class":666},[599,8334,694],{"class":605},[599,8336,8073],{"class":666},[599,8338,2444],{"class":605},[599,8340,7892],{"class":666},[599,8342,8344,8347,8350],{"class":601,"line":8343},236,[599,8345,8346],{"class":609},"            RegFlushKey",[599,8348,8349],{"class":666},"(hKey);",[599,8351,8352],{"class":772},"   \u002F\u002F survive a hard reset right after the logon\n",[599,8354,8356,8358],{"class":601,"line":8355},237,[599,8357,7273],{"class":609},[599,8359,7276],{"class":666},[599,8361,8363],{"class":601,"line":8362},238,[599,8364,1564],{"class":666},[599,8366,8368,8370,8372,8374],{"class":601,"line":8367},239,[599,8369,1211],{"class":605},[599,8371,6906],{"class":666},[599,8373,1349],{"class":605},[599,8375,7291],{"class":666},[599,8377,8379],{"class":601,"line":8378},240,[599,8380,1224],{"class":666},[599,8382,8384],{"class":601,"line":8383},241,[599,8385,651],{"emptyLinePlaceholder":650},[599,8387,8389,8391,8393,8395,8397,8399,8401,8403,8405,8407],{"class":601,"line":8388},242,[599,8390,673],{"class":605},[599,8392,5440],{"class":609},[599,8394,679],{"class":666},[599,8396,682],{"class":605},[599,8398,685],{"class":609},[599,8400,688],{"class":666},[599,8402,902],{"class":609},[599,8404,694],{"class":605},[599,8406,5176],{"class":697},[599,8408,1029],{"class":666},[599,8410,8412],{"class":601,"line":8411},243,[599,8413,1095],{"class":666},[599,8415,8417,8419,8421,8423,8425],{"class":601,"line":8416},244,[599,8418,1100],{"class":605},[599,8420,1327],{"class":666},[599,8422,2435],{"class":605},[599,8424,7122],{"class":609},[599,8426,7125],{"class":666},[599,8428,8430,8432,8434],{"class":601,"line":8429},245,[599,8431,2040],{"class":605},[599,8433,1411],{"class":949},[599,8435,1066],{"class":666},[599,8437,8439],{"class":601,"line":8438},246,[599,8440,651],{"emptyLinePlaceholder":650},[599,8442,8444,8446,8448,8450,8452],{"class":601,"line":8443},247,[599,8445,7183],{"class":609},[599,8447,7186],{"class":666},[599,8449,1060],{"class":605},[599,8451,1962],{"class":949},[599,8453,1066],{"class":666},[599,8455,8457,8459,8461,8463,8465,8467,8469,8472,8474],{"class":601,"line":8456},248,[599,8458,6903],{"class":609},[599,8460,6906],{"class":666},[599,8462,1060],{"class":605},[599,8464,7944],{"class":609},[599,8466,7947],{"class":666},[599,8468,2074],{"class":949},[599,8470,8471],{"class":666},", KEY_SET_VALUE, ",[599,8473,694],{"class":605},[599,8475,7210],{"class":666},[599,8477,8479,8481,8483,8485],{"class":601,"line":8478},249,[599,8480,1100],{"class":605},[599,8482,6961],{"class":666},[599,8484,1349],{"class":605},[599,8486,7967],{"class":666},[599,8488,8490,8492,8494],{"class":601,"line":8489},250,[599,8491,2040],{"class":605},[599,8493,1572],{"class":949},[599,8495,1066],{"class":666},[599,8497,8499,8501,8503,8505],{"class":601,"line":8498},251,[599,8500,1100],{"class":605},[599,8502,6961],{"class":666},[599,8504,2030],{"class":605},[599,8506,7007],{"class":666},[599,8508,8510,8512,8514],{"class":601,"line":8509},252,[599,8511,2040],{"class":605},[599,8513,1411],{"class":949},[599,8515,1066],{"class":666},[599,8517,8519],{"class":601,"line":8518},253,[599,8520,651],{"emptyLinePlaceholder":650},[599,8522,8524,8526,8528,8531,8533,8535],{"class":601,"line":8523},254,[599,8525,8037],{"class":666},[599,8527,1060],{"class":605},[599,8529,8530],{"class":609}," RegDeleteValueW",[599,8532,7236],{"class":666},[599,8534,6513],{"class":609},[599,8536,6864],{"class":666},[599,8538,8540,8542],{"class":601,"line":8539},255,[599,8541,7601],{"class":609},[599,8543,7276],{"class":666},[599,8545,8547,8549,8551,8553,8555,8557,8559,8561],{"class":601,"line":8546},256,[599,8548,1211],{"class":605},[599,8550,6906],{"class":666},[599,8552,1349],{"class":605},[599,8554,6966],{"class":666},[599,8556,6568],{"class":605},[599,8558,6906],{"class":666},[599,8560,1349],{"class":605},[599,8562,8563],{"class":666}," ERROR_FILE_NOT_FOUND;\n",[599,8565,8567],{"class":601,"line":8566},257,[599,8568,1224],{"class":666},[599,8570,8572],{"class":601,"line":8571},258,[599,8573,981],{"class":666},[15,8575,8576],{},"The protection of the secret is a bit tricky, so I want to explain it.",[15,8578,8579,8580,8583],{},"The secret is encrypted with DPAPI and ",[69,8581,8582],{},"CRYPTPROTECT_LOCAL_MACHINE",". I need this flag, because at logon the code runs in LogonUI as SYSTEM. SYSTEM can only decrypt it, if it was encrypted for the whole machine. But this also means: every process on the machine can decrypt it, also a normal user. DPAPI is no access control here. It only makes sure the secret is not stored in plain text.",[15,8585,8586,8587,8590,8591,8594],{},"Think this through for a second. The secret is exactly as safe as every copy of the ",[69,8588,8589],{},"SOFTWARE"," hive. The live hive is protected, but there are registry backups, VSS shadow copies and bugs like HiveNightmare (CVE-2021-36934), where normal users could read the hives from the shadow copies. Whoever has a copy of the blob can decrypt it with any process on ",[3290,8592,8593],{},"this"," machine.",[15,8596,8597,8598,8601,8602,8605,8606,8609],{},"The real protection is the ACL on the registry key. The SDDL ",[69,8599,8600],{},"D:P(A;OICI;KA;;;SY)(A;OICI;KA;;;BA)"," gives full access to SYSTEM and administrators, nobody else. The ",[69,8603,8604],{},"P"," blocks the inheritance from ",[69,8607,8608],{},"HKLM\\SOFTWARE",". Without it every user could read the key. So a normal user can't even read the encrypted value. An admin can, but an admin can do much worse things anyway. For a demo this is okay. In production you would store the secret in the TPM.",[15,8611,8612],{},"Some more details:",[56,8614,8615,8628,8638,8644,8654,8660],{},[59,8616,8617,8620,8621,8624,8625,3242],{},[69,8618,8619],{},"RegCreateKeyEx"," only applies the security attributes when it ",[3290,8622,8623],{},"creates"," the key. If the key already exists, maybe with a weaker ACL, I set the ACL again explicitly with ",[69,8626,8627],{},"RegSetKeySecurity",[59,8629,8630,8631,8633,8634,8637],{},"On decrypt there is no ",[69,8632,8582],{}," flag. The scope is stored inside the blob, so DPAPI already knows. But ",[69,8635,8636],{},"CRYPTPROTECT_UI_FORBIDDEN"," is mandatory on both sides, because no window may ever pop up on the secure desktop.",[59,8639,8640,8643],{},[69,8641,8642],{},"OpenProtectedKey"," is used for the secret and for the state. So both keys always get the same ACL, also when they already existed.",[59,8645,8646,8647,8650,8651,8653],{},"The value name is the SID of the account (",[69,8648,8649],{},"S-1-5-21-...-1001","), not the username. More about this below. ",[69,8652,7122],{}," makes sure that only SIDs end up as value names.",[59,8655,8656,8659],{},[69,8657,8658],{},"LoadState"," is strict. A missing value is a user who has never logged on, that's fine. A value that exists but has the wrong size or type is an error, and the logon is refused. The other way around a broken value would reset the counters to zero.",[59,8661,8662,8665,8666,8669],{},[69,8663,8664],{},"SaveState"," calls ",[69,8667,8668],{},"RegFlushKey",". The registry is written to disk lazily. If someone pulls the power right after a logon, the used time step must not get lost. Otherwise the same code would work again after the reboot.",[126,8671,8673],{"id":8672},"why-the-sid-and-not-the-name","Why the SID and not the name",[15,8675,8676],{},"My first version stored the secret under the lowercased username. That works until you change something in the user management:",[56,8678,8679,8689],{},[59,8680,8681,8682,8685,8686,8688],{},"You delete ",[69,8683,8684],{},"alice"," and later create a new ",[69,8687,8684],{}," for somebody else. The new account gets the old secret, and the old phone logs into it.",[59,8690,8691,8692,8694,8695,8698,8699,8701,8702,8704,8705,3242],{},"You rename ",[69,8693,8684],{}," to ",[69,8696,8697],{},"bob",". Now ",[69,8700,8697],{}," has no secret and is locked out. If you create a new ",[69,8703,8684],{},", she gets the secret of ",[69,8706,8697],{},[15,8708,8709,8710,8712],{},"Windows itself doesn't care about names. An account ",[3290,8711,3292],{}," its SID. A new account with the same name gets a new SID, a renamed account keeps its SID. So the secret belongs to the SID.",[15,8714,8715,8718,8719,8721,8722,8725,8726,8729],{},[69,8716,8717],{},"ResolveLocalUserSid"," does the lookup with ",[69,8720,6503],{}," and ",[69,8723,8724],{},"COMPUTERNAME\\name",". This is exactly the name that goes to LSA later. And it checks two things: the result must be a user (",[69,8727,8728],{},"SidTypeUser","), not a group or an alias. And the domain in the answer must be this computer. So the lookup can never end up in a domain.",[15,8731,8732],{},"If you used an older version of this demo: the old entries are stored under the name and are simply not found anymore. Enroll the users again and delete the old values.",[10,8734,8736],{"id":8735},"enrollment-tool","Enrollment tool",[15,8738,8739],{},"Before a user can log in, they need a secret. For this I wrote a small console tool that has to be run as admin.",[15,8741,8742,590],{},[69,8743,441],{},[148,8745,8747],{"className":593,"code":8746,"language":595,"meta":154,"style":154},"#include \"totp.h\"\n#include \"store.h\"\n#include \u003Cbcrypt.h>\n#include \u003Cconio.h>\n#include \u003Ccctype>\n#include \u003Ccstdio>\n#include \u003Cctime>\n#include \u003Cstring>\n#include \u003Cvector>\n\n#pragma comment(lib, \"bcrypt.lib\")\n#pragma comment(lib, \"advapi32.lib\")\n\n\u002F\u002F The otpauth label is UTF-8 and percent-encoded, so names like \"jürg\" survive.\nstatic std::string UrlEncode(const std::wstring& text)\n{\n    int cb = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, nullptr, 0, nullptr, nullptr);\n    std::string utf8(cb > 1 ? cb - 1 : 0, '\\0');\n    if (cb > 1)\n        WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, &utf8[0], cb, nullptr, nullptr);\n\n    static const char hex[] = \"0123456789ABCDEF\";\n    std::string out;\n    for (unsigned char c : utf8)\n    {\n        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')\n            out += static_cast\u003Cchar>(c);\n        else\n        {\n            out += '%';\n            out += hex[c >> 4];\n            out += hex[c & 0x0F];\n        }\n    }\n    return out;\n}\n\n\u002F\u002F Resets the lock of an enrolled user. The last used time step stays, so an\n\u002F\u002F unlock never makes an old code valid again.\nstatic int Unlock(const std::wstring& user, const std::wstring& sid)\n{\n    tac::UserState state;\n    if (!tac::LoadState(sid, state))\n    {\n        wprintf(L\"Could not read the state of '%s'. Run this from an elevated prompt.\\n\", user.c_str());\n        return 1;\n    }\n\n    uint64_t now = static_cast\u003Cuint64_t>(time(nullptr));\n    wprintf(L\"'%s': %u wrong code(s) in a row, %s.\\n\", user.c_str(), state.failures,\n            state.lockedUntil > now ? L\"locked\" : L\"not locked\");\n\n    state.failures    = 0;\n    state.lockedUntil = 0;\n    if (!tac::SaveState(sid, state))\n    {\n        wprintf(L\"Could not reset the state. Run this from an elevated prompt.\\n\");\n        return 1;\n    }\n    wprintf(L\"Unlocked.\\n\");\n    return 0;\n}\n\nint wmain(int argc, wchar_t** argv)\n{\n    bool unlock = argc == 3 && _wcsicmp(argv[1], L\"\u002Funlock\") == 0;\n    if (argc != 2 && !unlock)\n    {\n        wprintf(L\"Usage: enroll \u003Clocal username>\\n\");\n        wprintf(L\"       enroll \u002Funlock \u003Clocal username>\\n\");\n        return 1;\n    }\n\n    \u002F\u002F Only names that exist as a local user account on this machine. The\n    \u002F\u002F secret is stored under the SID of that account.\n    std::wstring user = tac::NormalizeUser(argv[unlock ? 2 : 1]);\n    std::wstring sid;\n    if (!tac::ResolveLocalUserSid(user, sid))\n    {\n        wprintf(L\"'%s' is not a local user account on this machine.\\n\", user.c_str());\n        return 1;\n    }\n\n    if (unlock)\n        return Unlock(user, sid);\n\n    std::vector\u003CBYTE> existing;\n    if (tac::LoadSecretKey(sid, existing))\n    {\n        SecureZeroMemory(existing.data(), existing.size());\n        wprintf(L\"'%s' is already enrolled. Replace the secret? [y\u002FN] \", user.c_str());\n        int answer = _getwch();\n        wprintf(L\"\\n\");\n        if (answer != L'y' && answer != L'Y')\n        {\n            wprintf(L\"Aborted.\\n\");\n            return 0;\n        }\n    }\n\n    \u002F\u002F 160 bits, the key size RFC 4226 recommends for HMAC-SHA1.\n    BYTE raw[20];\n    if (BCryptGenRandom(nullptr, raw, sizeof(raw), BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0)\n    {\n        wprintf(L\"Could not generate a random secret.\\n\");\n        return 1;\n    }\n    std::string secret = tac::Base32Encode(raw, sizeof(raw));\n    SecureZeroMemory(raw, sizeof(raw));\n\n    \u002F\u002F A new secret starts with a clean state: no lock, no used time step.\n    if (!tac::StoreSecret(sid, secret) || !tac::DeleteState(sid))\n    {\n        wprintf(L\"Could not store the secret. Run this from an elevated prompt.\\n\");\n        SecureZeroMemory(&secret[0], secret.size());\n        return 1;\n    }\n\n    std::string uri = \"otpauth:\u002F\u002Ftotp\u002FTheAdminCafe:\" + UrlEncode(user) +\n                      \"?secret=\" + secret +\n                      \"&issuer=TheAdminCafe&algorithm=SHA1&digits=6&period=30\";\n\n    wprintf(L\"\\nEnrolled '%s' (%s).\\n\\n\", user.c_str(), sid.c_str());\n    wprintf(L\"  Secret : %S\\n\", secret.c_str());\n    wprintf(L\"  URI    : %S\\n\\n\", uri.c_str());\n    wprintf(L\"Add the secret to your authenticator app, then test the logon.\\n\");\n    wprintf(L\"Don't paste it into an online QR code generator. Clear this window\\n\");\n    wprintf(L\"afterwards (cls), the secret is still in the scrollback.\\n\");\n\n    SecureZeroMemory(&secret[0], secret.size());\n    SecureZeroMemory(&uri[0], uri.size());\n    return 0;\n}\n",[69,8748,8749,8755,8761,8767,8774,8781,8788,8795,8801,8807,8811,8827,8843,8847,8852,8883,8887,8933,8976,8989,9028,9032,9050,9060,9074,9078,9128,9139,9144,9148,9159,9174,9190,9194,9198,9204,9208,9212,9217,9222,9261,9265,9277,9295,9299,9326,9334,9338,9342,9365,9401,9423,9427,9438,9449,9465,9469,9484,9492,9496,9511,9519,9523,9527,9551,9555,9594,9613,9617,9632,9647,9655,9659,9663,9668,9673,9708,9719,9736,9740,9763,9771,9775,9779,9786,9795,9799,9814,9830,9834,9850,9869,9883,9898,9921,9925,9941,9949,9953,9957,9961,9966,9978,10005,10009,10024,10032,10036,10064,10075,10079,10084,10115,10119,10134,10154,10162,10166,10170,10196,10207,10214,10218,10257,10278,10299,10314,10329,10344,10348,10366,10386,10394],{"__ignoreMap":154},[599,8750,8751,8753],{"class":601,"line":602},[599,8752,616],{"class":605},[599,8754,998],{"class":619},[599,8756,8757,8759],{"class":601,"line":613},[599,8758,616],{"class":605},[599,8760,5477],{"class":619},[599,8762,8763,8765],{"class":601,"line":623},[599,8764,616],{"class":605},[599,8766,1005],{"class":619},[599,8768,8769,8771],{"class":601,"line":631},[599,8770,616],{"class":605},[599,8772,8773],{"class":619}," \u003Cconio.h>\n",[599,8775,8776,8778],{"class":601,"line":639},[599,8777,616],{"class":605},[599,8779,8780],{"class":619}," \u003Ccctype>\n",[599,8782,8783,8785],{"class":601,"line":647},[599,8784,616],{"class":605},[599,8786,8787],{"class":619}," \u003Ccstdio>\n",[599,8789,8790,8792],{"class":601,"line":654},[599,8791,616],{"class":605},[599,8793,8794],{"class":619}," \u003Cctime>\n",[599,8796,8797,8799],{"class":601,"line":663},[599,8798,616],{"class":605},[599,8800,636],{"class":619},[599,8802,8803,8805],{"class":601,"line":670},[599,8804,616],{"class":605},[599,8806,644],{"class":619},[599,8808,8809],{"class":601,"line":728},[599,8810,651],{"emptyLinePlaceholder":650},[599,8812,8813,8815,8817,8819,8821,8823,8825],{"class":601,"line":764},[599,8814,606],{"class":605},[599,8816,1016],{"class":609},[599,8818,679],{"class":666},[599,8820,1021],{"class":609},[599,8822,212],{"class":666},[599,8824,1026],{"class":619},[599,8826,1029],{"class":666},[599,8828,8829,8831,8833,8835,8837,8839,8841],{"class":601,"line":769},[599,8830,606],{"class":605},[599,8832,1016],{"class":609},[599,8834,679],{"class":666},[599,8836,1021],{"class":609},[599,8838,212],{"class":666},[599,8840,5540],{"class":619},[599,8842,1029],{"class":666},[599,8844,8845],{"class":601,"line":776},[599,8846,651],{"emptyLinePlaceholder":650},[599,8848,8849],{"class":601,"line":816},[599,8850,8851],{"class":772},"\u002F\u002F The otpauth label is UTF-8 and percent-encoded, so names like \"jürg\" survive.\n",[599,8853,8854,8857,8859,8861,8863,8866,8868,8870,8872,8874,8876,8878,8881],{"class":601,"line":843},[599,8855,8856],{"class":605},"static",[599,8858,685],{"class":609},[599,8860,688],{"class":666},[599,8862,691],{"class":609},[599,8864,8865],{"class":609}," UrlEncode",[599,8867,679],{"class":666},[599,8869,682],{"class":605},[599,8871,685],{"class":609},[599,8873,688],{"class":666},[599,8875,902],{"class":609},[599,8877,694],{"class":605},[599,8879,8880],{"class":697}," text",[599,8882,1029],{"class":666},[599,8884,8885],{"class":601,"line":848},[599,8886,667],{"class":666},[599,8888,8889,8892,8894,8896,8899,8902,8904,8907,8909,8911,8913,8915,8917,8919,8921,8923,8925,8927,8929,8931],{"class":601,"line":854},[599,8890,8891],{"class":605},"    int",[599,8893,7454],{"class":666},[599,8895,1060],{"class":605},[599,8897,8898],{"class":609}," WideCharToMultiByte",[599,8900,8901],{"class":666},"(CP_UTF8, ",[599,8903,2074],{"class":949},[599,8905,8906],{"class":666},", text.",[599,8908,6513],{"class":609},[599,8910,7241],{"class":666},[599,8912,1132],{"class":605},[599,8914,1217],{"class":949},[599,8916,212],{"class":666},[599,8918,2019],{"class":949},[599,8920,212],{"class":666},[599,8922,2074],{"class":949},[599,8924,212],{"class":666},[599,8926,2019],{"class":949},[599,8928,212],{"class":666},[599,8930,2019],{"class":949},[599,8932,725],{"class":666},[599,8934,8935,8937,8939,8941,8944,8947,8949,8951,8954,8956,8958,8960,8963,8965,8967,8969,8972,8974],{"class":601,"line":860},[599,8936,731],{"class":609},[599,8938,688],{"class":666},[599,8940,691],{"class":609},[599,8942,8943],{"class":609}," utf8",[599,8945,8946],{"class":666},"(cb ",[599,8948,717],{"class":605},[599,8950,973],{"class":949},[599,8952,8953],{"class":605}," ?",[599,8955,7454],{"class":666},[599,8957,1132],{"class":605},[599,8959,973],{"class":949},[599,8961,8962],{"class":605}," :",[599,8964,1286],{"class":949},[599,8966,212],{"class":666},[599,8968,5725],{"class":619},[599,8970,8971],{"class":949},"\\0",[599,8973,5725],{"class":619},[599,8975,725],{"class":666},[599,8977,8978,8980,8983,8985,8987],{"class":601,"line":866},[599,8979,3514],{"class":605},[599,8981,8982],{"class":666}," (cb ",[599,8984,717],{"class":605},[599,8986,973],{"class":949},[599,8988,1029],{"class":666},[599,8990,8991,8994,8996,8998,9000,9002,9004,9006,9008,9010,9012,9015,9017,9020,9022,9024,9026],{"class":601,"line":912},[599,8992,8993],{"class":609},"        WideCharToMultiByte",[599,8995,8901],{"class":666},[599,8997,2074],{"class":949},[599,8999,8906],{"class":666},[599,9001,6513],{"class":609},[599,9003,7241],{"class":666},[599,9005,1132],{"class":605},[599,9007,1217],{"class":949},[599,9009,212],{"class":666},[599,9011,694],{"class":605},[599,9013,9014],{"class":666},"utf8[",[599,9016,2074],{"class":949},[599,9018,9019],{"class":666},"], cb, ",[599,9021,2019],{"class":949},[599,9023,212],{"class":666},[599,9025,2019],{"class":949},[599,9027,725],{"class":666},[599,9029,9030],{"class":601,"line":938},[599,9031,651],{"emptyLinePlaceholder":650},[599,9033,9034,9036,9038,9040,9043,9045,9048],{"class":601,"line":978},[599,9035,1048],{"class":605},[599,9037,1051],{"class":605},[599,9039,1054],{"class":605},[599,9041,9042],{"class":666}," hex[] ",[599,9044,1060],{"class":605},[599,9046,9047],{"class":619}," \"0123456789ABCDEF\"",[599,9049,1066],{"class":666},[599,9051,9052,9054,9056,9058],{"class":601,"line":1316},[599,9053,731],{"class":609},[599,9055,688],{"class":666},[599,9057,691],{"class":609},[599,9059,1631],{"class":666},[599,9061,9062,9064,9066,9069,9071],{"class":601,"line":1321},[599,9063,3407],{"class":605},[599,9065,1327],{"class":666},[599,9067,9068],{"class":605},"unsigned",[599,9070,1054],{"class":605},[599,9072,9073],{"class":666}," c : utf8)\n",[599,9075,9076],{"class":601,"line":1335},[599,9077,1095],{"class":666},[599,9079,9080,9082,9084,9087,9090,9092,9094,9096,9099,9101,9103,9105,9108,9110,9112,9114,9117,9119,9121,9123,9126],{"class":601,"line":1341},[599,9081,1100],{"class":605},[599,9083,1327],{"class":666},[599,9085,9086],{"class":609},"isalnum",[599,9088,9089],{"class":666},"(c) ",[599,9091,6568],{"class":605},[599,9093,1115],{"class":666},[599,9095,1349],{"class":605},[599,9097,9098],{"class":619}," '-'",[599,9100,1355],{"class":605},[599,9102,1115],{"class":666},[599,9104,1349],{"class":605},[599,9106,9107],{"class":619}," '_'",[599,9109,1355],{"class":605},[599,9111,1115],{"class":666},[599,9113,1349],{"class":605},[599,9115,9116],{"class":619}," '.'",[599,9118,1355],{"class":605},[599,9120,1115],{"class":666},[599,9122,1349],{"class":605},[599,9124,9125],{"class":619}," '~'",[599,9127,1029],{"class":666},[599,9129,9130,9132,9134,9137],{"class":601,"line":1367},[599,9131,1836],{"class":666},[599,9133,1455],{"class":605},[599,9135,9136],{"class":605}," static_cast\u003Cchar>",[599,9138,1388],{"class":666},[599,9140,9141],{"class":601,"line":1375},[599,9142,9143],{"class":605},"        else\n",[599,9145,9146],{"class":601,"line":1391},[599,9147,1338],{"class":666},[599,9149,9150,9152,9154,9157],{"class":601,"line":1405},[599,9151,1836],{"class":666},[599,9153,1455],{"class":605},[599,9155,9156],{"class":619}," '%'",[599,9158,1066],{"class":666},[599,9160,9161,9163,9165,9168,9170,9172],{"class":601,"line":1416},[599,9162,1836],{"class":666},[599,9164,1455],{"class":605},[599,9166,9167],{"class":666}," hex[c ",[599,9169,1517],{"class":605},[599,9171,6716],{"class":949},[599,9173,1784],{"class":666},[599,9175,9176,9178,9180,9182,9184,9186,9188],{"class":601,"line":1421},[599,9177,1836],{"class":666},[599,9179,1455],{"class":605},[599,9181,9167],{"class":666},[599,9183,694],{"class":605},[599,9185,1778],{"class":605},[599,9187,2498],{"class":949},[599,9189,1784],{"class":666},[599,9191,9192],{"class":601,"line":1449},[599,9193,1564],{"class":666},[599,9195,9196],{"class":601,"line":1462},[599,9197,1224],{"class":666},[599,9199,9200,9202],{"class":601,"line":1477},[599,9201,3551],{"class":605},[599,9203,1631],{"class":666},[599,9205,9206],{"class":601,"line":1483},[599,9207,981],{"class":666},[599,9209,9210],{"class":601,"line":1496},[599,9211,651],{"emptyLinePlaceholder":650},[599,9213,9214],{"class":601,"line":1523},[599,9215,9216],{"class":772},"\u002F\u002F Resets the lock of an enrolled user. The last used time step stays, so an\n",[599,9218,9219],{"class":601,"line":1555},[599,9220,9221],{"class":772},"\u002F\u002F unlock never makes an old code valid again.\n",[599,9223,9224,9226,9228,9231,9233,9235,9237,9239,9241,9243,9245,9247,9249,9251,9253,9255,9257,9259],{"class":601,"line":1561},[599,9225,8856],{"class":605},[599,9227,1077],{"class":605},[599,9229,9230],{"class":609}," Unlock",[599,9232,679],{"class":666},[599,9234,682],{"class":605},[599,9236,685],{"class":609},[599,9238,688],{"class":666},[599,9240,902],{"class":609},[599,9242,694],{"class":605},[599,9244,5126],{"class":697},[599,9246,212],{"class":666},[599,9248,682],{"class":605},[599,9250,685],{"class":609},[599,9252,688],{"class":666},[599,9254,902],{"class":609},[599,9256,694],{"class":605},[599,9258,5176],{"class":697},[599,9260,1029],{"class":666},[599,9262,9263],{"class":601,"line":1567},[599,9264,667],{"class":666},[599,9266,9267,9270,9272,9274],{"class":601,"line":1577},[599,9268,9269],{"class":609},"    tac",[599,9271,688],{"class":666},[599,9273,5392],{"class":609},[599,9275,9276],{"class":666}," state;\n",[599,9278,9279,9281,9283,9285,9288,9290,9292],{"class":601,"line":1582},[599,9280,3514],{"class":605},[599,9282,1327],{"class":666},[599,9284,2435],{"class":605},[599,9286,9287],{"class":609},"tac",[599,9289,688],{"class":666},[599,9291,8658],{"class":609},[599,9293,9294],{"class":666},"(sid, state))\n",[599,9296,9297],{"class":601,"line":1587},[599,9298,1095],{"class":666},[599,9300,9301,9304,9306,9309,9312,9315,9317,9319,9322,9324],{"class":601,"line":1616},[599,9302,9303],{"class":609},"        wprintf",[599,9305,679],{"class":666},[599,9307,9308],{"class":619},"L\"Could not read the state of '",[599,9310,9311],{"class":949},"%s",[599,9313,9314],{"class":619},"'. Run this from an elevated prompt.",[599,9316,4365],{"class":949},[599,9318,4362],{"class":619},[599,9320,9321],{"class":666},", user.",[599,9323,6513],{"class":609},[599,9325,6864],{"class":666},[599,9327,9328,9330,9332],{"class":601,"line":1621},[599,9329,1211],{"class":605},[599,9331,973],{"class":949},[599,9333,1066],{"class":666},[599,9335,9336],{"class":601,"line":1634},[599,9337,1224],{"class":666},[599,9339,9340],{"class":601,"line":1647},[599,9341,651],{"emptyLinePlaceholder":650},[599,9343,9344,9347,9349,9351,9353,9355,9358,9360,9362],{"class":601,"line":1660},[599,9345,9346],{"class":605},"    uint64_t",[599,9348,2975],{"class":666},[599,9350,1060],{"class":605},[599,9352,3034],{"class":605},[599,9354,679],{"class":666},[599,9356,9357],{"class":609},"time",[599,9359,679],{"class":666},[599,9361,2019],{"class":949},[599,9363,9364],{"class":666},"));\n",[599,9366,9367,9370,9372,9375,9377,9380,9383,9386,9388,9390,9392,9394,9396,9398],{"class":601,"line":1665},[599,9368,9369],{"class":609},"    wprintf",[599,9371,679],{"class":666},[599,9373,9374],{"class":619},"L\"'",[599,9376,9311],{"class":949},[599,9378,9379],{"class":619},"': ",[599,9381,9382],{"class":949},"%u",[599,9384,9385],{"class":619}," wrong code(s) in a row, ",[599,9387,9311],{"class":949},[599,9389,3242],{"class":619},[599,9391,4365],{"class":949},[599,9393,4362],{"class":619},[599,9395,9321],{"class":666},[599,9397,6513],{"class":609},[599,9399,9400],{"class":666},"(), state.failures,\n",[599,9402,9403,9406,9408,9410,9413,9416,9418,9421],{"class":601,"line":1695},[599,9404,9405],{"class":666},"            state.lockedUntil ",[599,9407,717],{"class":605},[599,9409,2975],{"class":666},[599,9411,9412],{"class":605},"?",[599,9414,9415],{"class":619}," L\"locked\"",[599,9417,8962],{"class":605},[599,9419,9420],{"class":619}," L\"not locked\"",[599,9422,725],{"class":666},[599,9424,9425],{"class":601,"line":1700},[599,9426,651],{"emptyLinePlaceholder":650},[599,9428,9429,9432,9434,9436],{"class":601,"line":1720},[599,9430,9431],{"class":666},"    state.failures    ",[599,9433,1060],{"class":605},[599,9435,1286],{"class":949},[599,9437,1066],{"class":666},[599,9439,9440,9443,9445,9447],{"class":601,"line":1731},[599,9441,9442],{"class":666},"    state.lockedUntil ",[599,9444,1060],{"class":605},[599,9446,1286],{"class":949},[599,9448,1066],{"class":666},[599,9450,9451,9453,9455,9457,9459,9461,9463],{"class":601,"line":1745},[599,9452,3514],{"class":605},[599,9454,1327],{"class":666},[599,9456,2435],{"class":605},[599,9458,9287],{"class":609},[599,9460,688],{"class":666},[599,9462,8664],{"class":609},[599,9464,9294],{"class":666},[599,9466,9467],{"class":601,"line":1750},[599,9468,1095],{"class":666},[599,9470,9471,9473,9475,9478,9480,9482],{"class":601,"line":1761},[599,9472,9303],{"class":609},[599,9474,679],{"class":666},[599,9476,9477],{"class":619},"L\"Could not reset the state. Run this from an elevated prompt.",[599,9479,4365],{"class":949},[599,9481,4362],{"class":619},[599,9483,725],{"class":666},[599,9485,9486,9488,9490],{"class":601,"line":1787},[599,9487,1211],{"class":605},[599,9489,973],{"class":949},[599,9491,1066],{"class":666},[599,9493,9494],{"class":601,"line":1792},[599,9495,1224],{"class":666},[599,9497,9498,9500,9502,9505,9507,9509],{"class":601,"line":1815},[599,9499,9369],{"class":609},[599,9501,679],{"class":666},[599,9503,9504],{"class":619},"L\"Unlocked.",[599,9506,4365],{"class":949},[599,9508,4362],{"class":619},[599,9510,725],{"class":666},[599,9512,9513,9515,9517],{"class":601,"line":1820},[599,9514,3551],{"class":605},[599,9516,1286],{"class":949},[599,9518,1066],{"class":666},[599,9520,9521],{"class":601,"line":1833},[599,9522,981],{"class":666},[599,9524,9525],{"class":601,"line":1863},[599,9526,651],{"emptyLinePlaceholder":650},[599,9528,9529,9531,9534,9536,9538,9541,9543,9546,9549],{"class":601,"line":1870},[599,9530,827],{"class":605},[599,9532,9533],{"class":609}," wmain",[599,9535,679],{"class":666},[599,9537,827],{"class":605},[599,9539,9540],{"class":697}," argc",[599,9542,212],{"class":666},[599,9544,9545],{"class":605},"wchar_t**",[599,9547,9548],{"class":697}," argv",[599,9550,1029],{"class":666},[599,9552,9553],{"class":601,"line":1875},[599,9554,667],{"class":666},[599,9556,9557,9559,9562,9564,9567,9569,9571,9573,9575,9578,9580,9583,9586,9588,9590,9592],{"class":601,"line":1880},[599,9558,673],{"class":605},[599,9560,9561],{"class":666}," unlock ",[599,9563,1060],{"class":605},[599,9565,9566],{"class":666}," argc ",[599,9568,1349],{"class":605},[599,9570,2608],{"class":949},[599,9572,1112],{"class":605},[599,9574,6571],{"class":609},[599,9576,9577],{"class":666},"(argv[",[599,9579,1217],{"class":949},[599,9581,9582],{"class":666},"], ",[599,9584,9585],{"class":619},"L\"\u002Funlock\"",[599,9587,1124],{"class":666},[599,9589,1349],{"class":605},[599,9591,1286],{"class":949},[599,9593,1066],{"class":666},[599,9595,9596,9598,9601,9603,9605,9607,9610],{"class":601,"line":1946},[599,9597,3514],{"class":605},[599,9599,9600],{"class":666}," (argc ",[599,9602,2030],{"class":605},[599,9604,2576],{"class":949},[599,9606,1112],{"class":605},[599,9608,9609],{"class":605}," !",[599,9611,9612],{"class":666},"unlock)\n",[599,9614,9615],{"class":601,"line":1951},[599,9616,1095],{"class":666},[599,9618,9619,9621,9623,9626,9628,9630],{"class":601,"line":1967},[599,9620,9303],{"class":609},[599,9622,679],{"class":666},[599,9624,9625],{"class":619},"L\"Usage: enroll \u003Clocal username>",[599,9627,4365],{"class":949},[599,9629,4362],{"class":619},[599,9631,725],{"class":666},[599,9633,9634,9636,9638,9641,9643,9645],{"class":601,"line":1982},[599,9635,9303],{"class":609},[599,9637,679],{"class":666},[599,9639,9640],{"class":619},"L\"       enroll \u002Funlock \u003Clocal username>",[599,9642,4365],{"class":949},[599,9644,4362],{"class":619},[599,9646,725],{"class":666},[599,9648,9649,9651,9653],{"class":601,"line":1997},[599,9650,1211],{"class":605},[599,9652,973],{"class":949},[599,9654,1066],{"class":666},[599,9656,9657],{"class":601,"line":2002},[599,9658,1224],{"class":666},[599,9660,9661],{"class":601,"line":2024},[599,9662,651],{"emptyLinePlaceholder":650},[599,9664,9665],{"class":601,"line":2037},[599,9666,9667],{"class":772},"    \u002F\u002F Only names that exist as a local user account on this machine. The\n",[599,9669,9670],{"class":601,"line":2047},[599,9671,9672],{"class":772},"    \u002F\u002F secret is stored under the SID of that account.\n",[599,9674,9675,9677,9679,9681,9684,9686,9689,9691,9694,9697,9699,9701,9703,9705],{"class":601,"line":2052},[599,9676,731],{"class":609},[599,9678,688],{"class":666},[599,9680,902],{"class":609},[599,9682,9683],{"class":666}," user ",[599,9685,1060],{"class":605},[599,9687,9688],{"class":609}," tac",[599,9690,688],{"class":666},[599,9692,9693],{"class":609},"NormalizeUser",[599,9695,9696],{"class":666},"(argv[unlock ",[599,9698,9412],{"class":605},[599,9700,2576],{"class":949},[599,9702,8962],{"class":605},[599,9704,973],{"class":949},[599,9706,9707],{"class":666},"]);\n",[599,9709,9710,9712,9714,9716],{"class":601,"line":2096},[599,9711,731],{"class":609},[599,9713,688],{"class":666},[599,9715,902],{"class":609},[599,9717,9718],{"class":666}," sid;\n",[599,9720,9721,9723,9725,9727,9729,9731,9733],{"class":601,"line":2124},[599,9722,3514],{"class":605},[599,9724,1327],{"class":666},[599,9726,2435],{"class":605},[599,9728,9287],{"class":609},[599,9730,688],{"class":666},[599,9732,8717],{"class":609},[599,9734,9735],{"class":666},"(user, sid))\n",[599,9737,9738],{"class":601,"line":2129},[599,9739,1095],{"class":666},[599,9741,9742,9744,9746,9748,9750,9753,9755,9757,9759,9761],{"class":601,"line":2163},[599,9743,9303],{"class":609},[599,9745,679],{"class":666},[599,9747,9374],{"class":619},[599,9749,9311],{"class":949},[599,9751,9752],{"class":619},"' is not a local user account on this machine.",[599,9754,4365],{"class":949},[599,9756,4362],{"class":619},[599,9758,9321],{"class":666},[599,9760,6513],{"class":609},[599,9762,6864],{"class":666},[599,9764,9765,9767,9769],{"class":601,"line":2186},[599,9766,1211],{"class":605},[599,9768,973],{"class":949},[599,9770,1066],{"class":666},[599,9772,9773],{"class":601,"line":2195},[599,9774,1224],{"class":666},[599,9776,9777],{"class":601,"line":2200},[599,9778,651],{"emptyLinePlaceholder":650},[599,9780,9781,9783],{"class":601,"line":2212},[599,9782,3514],{"class":605},[599,9784,9785],{"class":666}," (unlock)\n",[599,9787,9788,9790,9792],{"class":601,"line":2220},[599,9789,1211],{"class":605},[599,9791,9230],{"class":609},[599,9793,9794],{"class":666},"(user, sid);\n",[599,9796,9797],{"class":601,"line":2225},[599,9798,651],{"emptyLinePlaceholder":650},[599,9800,9801,9803,9805,9807,9809,9811],{"class":601,"line":2230},[599,9802,731],{"class":609},[599,9804,688],{"class":666},[599,9806,708],{"class":609},[599,9808,711],{"class":666},[599,9810,714],{"class":609},[599,9812,9813],{"class":666},"> existing;\n",[599,9815,9816,9818,9820,9822,9824,9827],{"class":601,"line":2265},[599,9817,3514],{"class":605},[599,9819,1327],{"class":666},[599,9821,9287],{"class":609},[599,9823,688],{"class":666},[599,9825,9826],{"class":609},"LoadSecretKey",[599,9828,9829],{"class":666},"(sid, existing))\n",[599,9831,9832],{"class":601,"line":2286},[599,9833,1095],{"class":666},[599,9835,9836,9838,9841,9843,9846,9848],{"class":601,"line":2291},[599,9837,6213],{"class":609},[599,9839,9840],{"class":666},"(existing.",[599,9842,2090],{"class":609},[599,9844,9845],{"class":666},"(), existing.",[599,9847,2108],{"class":609},[599,9849,6864],{"class":666},[599,9851,9852,9854,9856,9858,9860,9863,9865,9867],{"class":601,"line":2297},[599,9853,9303],{"class":609},[599,9855,679],{"class":666},[599,9857,9374],{"class":619},[599,9859,9311],{"class":949},[599,9861,9862],{"class":619},"' is already enrolled. Replace the secret? [y\u002FN] \"",[599,9864,9321],{"class":666},[599,9866,6513],{"class":609},[599,9868,6864],{"class":666},[599,9870,9871,9873,9876,9878,9881],{"class":601,"line":2317},[599,9872,1293],{"class":605},[599,9874,9875],{"class":666}," answer ",[599,9877,1060],{"class":605},[599,9879,9880],{"class":609}," _getwch",[599,9882,1313],{"class":666},[599,9884,9885,9887,9889,9892,9894,9896],{"class":601,"line":2331},[599,9886,9303],{"class":609},[599,9888,679],{"class":666},[599,9890,9891],{"class":619},"L\"",[599,9893,4365],{"class":949},[599,9895,4362],{"class":619},[599,9897,725],{"class":666},[599,9899,9900,9902,9905,9907,9910,9912,9914,9916,9919],{"class":601,"line":2361},[599,9901,1100],{"class":605},[599,9903,9904],{"class":666}," (answer ",[599,9906,2030],{"class":605},[599,9908,9909],{"class":619}," L'y'",[599,9911,1112],{"class":605},[599,9913,9875],{"class":666},[599,9915,2030],{"class":605},[599,9917,9918],{"class":619}," L'Y'",[599,9920,1029],{"class":666},[599,9922,9923],{"class":601,"line":2366},[599,9924,1338],{"class":666},[599,9926,9927,9930,9932,9935,9937,9939],{"class":601,"line":2393},[599,9928,9929],{"class":609},"            wprintf",[599,9931,679],{"class":666},[599,9933,9934],{"class":619},"L\"Aborted.",[599,9936,4365],{"class":949},[599,9938,4362],{"class":619},[599,9940,725],{"class":666},[599,9942,9943,9945,9947],{"class":601,"line":2406},[599,9944,2040],{"class":605},[599,9946,1286],{"class":949},[599,9948,1066],{"class":666},[599,9950,9951],{"class":601,"line":2411},[599,9952,1564],{"class":666},[599,9954,9955],{"class":601,"line":2416},[599,9956,1224],{"class":666},[599,9958,9959],{"class":601,"line":2428},[599,9960,651],{"emptyLinePlaceholder":650},[599,9962,9963],{"class":601,"line":2450},[599,9964,9965],{"class":772},"    \u002F\u002F 160 bits, the key size RFC 4226 recommends for HMAC-SHA1.\n",[599,9967,9968,9971,9974,9976],{"class":601,"line":2459},[599,9969,9970],{"class":609},"    BYTE",[599,9972,9973],{"class":666}," raw[",[599,9975,1940],{"class":949},[599,9977,1784],{"class":666},[599,9979,9980,9982,9984,9987,9989,9991,9994,9996,9999,10001,10003],{"class":601,"line":2464},[599,9981,3514],{"class":605},[599,9983,1327],{"class":666},[599,9985,9986],{"class":609},"BCryptGenRandom",[599,9988,679],{"class":666},[599,9990,2019],{"class":949},[599,9992,9993],{"class":666},", raw, ",[599,9995,2444],{"class":605},[599,9997,9998],{"class":666},"(raw), BCRYPT_USE_SYSTEM_PREFERRED_RNG) ",[599,10000,2030],{"class":605},[599,10002,1286],{"class":949},[599,10004,1029],{"class":666},[599,10006,10007],{"class":601,"line":2470},[599,10008,1095],{"class":666},[599,10010,10011,10013,10015,10018,10020,10022],{"class":601,"line":2476},[599,10012,9303],{"class":609},[599,10014,679],{"class":666},[599,10016,10017],{"class":619},"L\"Could not generate a random secret.",[599,10019,4365],{"class":949},[599,10021,4362],{"class":619},[599,10023,725],{"class":666},[599,10025,10026,10028,10030],{"class":601,"line":2503},[599,10027,1211],{"class":605},[599,10029,973],{"class":949},[599,10031,1066],{"class":666},[599,10033,10034],{"class":601,"line":2537},[599,10035,1224],{"class":666},[599,10037,10038,10040,10042,10044,10047,10049,10051,10053,10056,10059,10061],{"class":601,"line":2569},[599,10039,731],{"class":609},[599,10041,688],{"class":666},[599,10043,691],{"class":609},[599,10045,10046],{"class":666}," secret ",[599,10048,1060],{"class":605},[599,10050,9688],{"class":609},[599,10052,688],{"class":666},[599,10054,10055],{"class":609},"Base32Encode",[599,10057,10058],{"class":666},"(raw, ",[599,10060,2444],{"class":605},[599,10062,10063],{"class":666},"(raw));\n",[599,10065,10066,10069,10071,10073],{"class":601,"line":2600},[599,10067,10068],{"class":609},"    SecureZeroMemory",[599,10070,10058],{"class":666},[599,10072,2444],{"class":605},[599,10074,10063],{"class":666},[599,10076,10077],{"class":601,"line":2623},[599,10078,651],{"emptyLinePlaceholder":650},[599,10080,10081],{"class":601,"line":2628},[599,10082,10083],{"class":772},"    \u002F\u002F A new secret starts with a clean state: no lock, no used time step.\n",[599,10085,10086,10088,10090,10092,10094,10096,10099,10102,10104,10106,10108,10110,10113],{"class":601,"line":2642},[599,10087,3514],{"class":605},[599,10089,1327],{"class":666},[599,10091,2435],{"class":605},[599,10093,9287],{"class":609},[599,10095,688],{"class":666},[599,10097,10098],{"class":609},"StoreSecret",[599,10100,10101],{"class":666},"(sid, secret) ",[599,10103,6568],{"class":605},[599,10105,9609],{"class":605},[599,10107,9287],{"class":609},[599,10109,688],{"class":666},[599,10111,10112],{"class":609},"DeleteState",[599,10114,7125],{"class":666},[599,10116,10117],{"class":601,"line":2668},[599,10118,1095],{"class":666},[599,10120,10121,10123,10125,10128,10130,10132],{"class":601,"line":2682},[599,10122,9303],{"class":609},[599,10124,679],{"class":666},[599,10126,10127],{"class":619},"L\"Could not store the secret. Run this from an elevated prompt.",[599,10129,4365],{"class":949},[599,10131,4362],{"class":619},[599,10133,725],{"class":666},[599,10135,10136,10138,10140,10142,10145,10147,10150,10152],{"class":601,"line":2698},[599,10137,6213],{"class":609},[599,10139,679],{"class":666},[599,10141,694],{"class":605},[599,10143,10144],{"class":666},"secret[",[599,10146,2074],{"class":949},[599,10148,10149],{"class":666},"], secret.",[599,10151,2108],{"class":609},[599,10153,6864],{"class":666},[599,10155,10156,10158,10160],{"class":601,"line":2707},[599,10157,1211],{"class":605},[599,10159,973],{"class":949},[599,10161,1066],{"class":666},[599,10163,10164],{"class":601,"line":2712},[599,10165,1224],{"class":666},[599,10167,10168],{"class":601,"line":2717},[599,10169,651],{"emptyLinePlaceholder":650},[599,10171,10172,10174,10176,10178,10181,10183,10186,10188,10190,10193],{"class":601,"line":2760},[599,10173,731],{"class":609},[599,10175,688],{"class":666},[599,10177,691],{"class":609},[599,10179,10180],{"class":666}," uri ",[599,10182,1060],{"class":605},[599,10184,10185],{"class":619}," \"otpauth:\u002F\u002Ftotp\u002FTheAdminCafe:\"",[599,10187,1201],{"class":605},[599,10189,8865],{"class":609},[599,10191,10192],{"class":666},"(user) ",[599,10194,10195],{"class":605},"+\n",[599,10197,10198,10201,10203,10205],{"class":601,"line":2781},[599,10199,10200],{"class":619},"                      \"?secret=\"",[599,10202,1201],{"class":605},[599,10204,10046],{"class":666},[599,10206,10195],{"class":605},[599,10208,10209,10212],{"class":601,"line":2802},[599,10210,10211],{"class":619},"                      \"&issuer=TheAdminCafe&algorithm=SHA1&digits=6&period=30\"",[599,10213,1066],{"class":666},[599,10215,10216],{"class":601,"line":2807},[599,10217,651],{"emptyLinePlaceholder":650},[599,10219,10220,10222,10224,10226,10228,10231,10233,10236,10238,10241,10244,10246,10248,10250,10253,10255],{"class":601,"line":2819},[599,10221,9369],{"class":609},[599,10223,679],{"class":666},[599,10225,9891],{"class":619},[599,10227,4365],{"class":949},[599,10229,10230],{"class":619},"Enrolled '",[599,10232,9311],{"class":949},[599,10234,10235],{"class":619},"' (",[599,10237,9311],{"class":949},[599,10239,10240],{"class":619},").",[599,10242,10243],{"class":949},"\\n\\n",[599,10245,4362],{"class":619},[599,10247,9321],{"class":666},[599,10249,6513],{"class":609},[599,10251,10252],{"class":666},"(), sid.",[599,10254,6513],{"class":609},[599,10256,6864],{"class":666},[599,10258,10259,10261,10263,10266,10269,10271,10274,10276],{"class":601,"line":2824},[599,10260,9369],{"class":609},[599,10262,679],{"class":666},[599,10264,10265],{"class":619},"L\"  Secret : ",[599,10267,10268],{"class":949},"%S\\n",[599,10270,4362],{"class":619},[599,10272,10273],{"class":666},", secret.",[599,10275,6513],{"class":609},[599,10277,6864],{"class":666},[599,10279,10280,10282,10284,10287,10290,10292,10295,10297],{"class":601,"line":2830},[599,10281,9369],{"class":609},[599,10283,679],{"class":666},[599,10285,10286],{"class":619},"L\"  URI    : ",[599,10288,10289],{"class":949},"%S\\n\\n",[599,10291,4362],{"class":619},[599,10293,10294],{"class":666},", uri.",[599,10296,6513],{"class":609},[599,10298,6864],{"class":666},[599,10300,10301,10303,10305,10308,10310,10312],{"class":601,"line":2851},[599,10302,9369],{"class":609},[599,10304,679],{"class":666},[599,10306,10307],{"class":619},"L\"Add the secret to your authenticator app, then test the logon.",[599,10309,4365],{"class":949},[599,10311,4362],{"class":619},[599,10313,725],{"class":666},[599,10315,10316,10318,10320,10323,10325,10327],{"class":601,"line":2860},[599,10317,9369],{"class":609},[599,10319,679],{"class":666},[599,10321,10322],{"class":619},"L\"Don't paste it into an online QR code generator. Clear this window",[599,10324,4365],{"class":949},[599,10326,4362],{"class":619},[599,10328,725],{"class":666},[599,10330,10331,10333,10335,10338,10340,10342],{"class":601,"line":2874},[599,10332,9369],{"class":609},[599,10334,679],{"class":666},[599,10336,10337],{"class":619},"L\"afterwards (cls), the secret is still in the scrollback.",[599,10339,4365],{"class":949},[599,10341,4362],{"class":619},[599,10343,725],{"class":666},[599,10345,10346],{"class":601,"line":2887},[599,10347,651],{"emptyLinePlaceholder":650},[599,10349,10350,10352,10354,10356,10358,10360,10362,10364],{"class":601,"line":2892},[599,10351,10068],{"class":609},[599,10353,679],{"class":666},[599,10355,694],{"class":605},[599,10357,10144],{"class":666},[599,10359,2074],{"class":949},[599,10361,10149],{"class":666},[599,10363,2108],{"class":609},[599,10365,6864],{"class":666},[599,10367,10368,10370,10372,10374,10377,10379,10382,10384],{"class":601,"line":2915},[599,10369,10068],{"class":609},[599,10371,679],{"class":666},[599,10373,694],{"class":605},[599,10375,10376],{"class":666},"uri[",[599,10378,2074],{"class":949},[599,10380,10381],{"class":666},"], uri.",[599,10383,2108],{"class":609},[599,10385,6864],{"class":666},[599,10387,10388,10390,10392],{"class":601,"line":2924},[599,10389,3551],{"class":605},[599,10391,1286],{"class":949},[599,10393,1066],{"class":666},[599,10395,10396],{"class":601,"line":2951},[599,10397,981],{"class":666},[15,10399,10400],{},"Run it like this:",[148,10402,10405],{"className":10403,"code":10404,"language":153,"meta":154},[151],"enroll.exe alice\n",[69,10406,10404],{"__ignoreMap":154},[15,10408,10409,10410,10413,10414,10417,10418,10421],{},"The tool shows you the secret and an ",[69,10411,10412],{},"otpauth:\u002F\u002F"," URI. You can type the secret into your authenticator app or convert the URI into a QR code. Please use a generator that runs locally, for example ",[69,10415,10416],{},"qrencode -t ansiutf8 'otpauth:\u002F\u002F...'"," in WSL. An online QR code generator gets your secret, and then it's not a secret anymore. Also clear the console window afterwards (",[69,10419,10420],{},"cls","). The secret is still in the scrollback.",[15,10423,10424,10425,10427],{},"The tool first checks if the name is really a local user account on this machine (",[69,10426,8717],{},"). Without this check a typo would create a secret for an account that doesn't exist, and you would only notice it at the logon screen. The secret is stored under the SID of the account, and the old state of the user is deleted. A new secret starts clean: no lock, no used time step.",[15,10429,10430],{},"If the user is already enrolled, the tool asks before it overwrites the secret. Otherwise the code on the phone would suddenly stop working.",[15,10432,10433,10434,10437],{},"With ",[69,10435,10436],{},"\u002Funlock"," an admin can unlock a user who typed too many wrong codes:",[148,10439,10442],{"className":10440,"code":10441,"language":153,"meta":154},[151],"enroll.exe \u002Funlock alice\n",[69,10443,10441],{"__ignoreMap":154},[15,10445,10446],{},"This resets the counter and the lock, but not the last used time step. An unlock should never make an old code valid again.",[10,10448,10450],{"id":10449},"the-credential-provider","The Credential Provider",[126,10452,454],{"id":10453},"fields-of-the-tile",[15,10455,10456,10457,10459],{},"In ",[69,10458,451],{}," I define which fields the tile has:",[148,10461,10463],{"className":593,"code":10462,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccredentialprovider.h>\n#include \u003Cshlguid.h>\n\n\u002F\u002F On a user tile Windows draws the account name and the round account picture\n\u002F\u002F itself. TFI_TILEIMAGE and TFI_LABEL are only the small logo and the name of\n\u002F\u002F our provider under \"Sign-in options\" (that is what the CPFG_ GUIDs mean).\nenum TAC_FIELD_ID\n{\n    TFI_TILEIMAGE  = 0,\n    TFI_LABEL      = 1,\n    TFI_USERNAME   = 2,   \u002F\u002F only visible on the fallback tile\n    TFI_PASSWORD   = 3,\n    TFI_OTP        = 4,\n    TFI_SUBMIT     = 5,\n    TFI_NUM_FIELDS = 6,\n};\n\nstruct FIELD_STATE_PAIR\n{\n    CREDENTIAL_PROVIDER_FIELD_STATE             cpfs;\n    CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis;\n};\n\nstatic const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR s_rgFieldDescriptors[] =\n{\n    { TFI_TILEIMAGE, CPFT_TILE_IMAGE,    const_cast\u003CPWSTR>(L\"Image\"), CPFG_CREDENTIAL_PROVIDER_LOGO },\n    { TFI_LABEL,     CPFT_SMALL_TEXT,    const_cast\u003CPWSTR>(L\"TheAdminCafe 2FA\"), CPFG_CREDENTIAL_PROVIDER_LABEL },\n    { TFI_USERNAME,  CPFT_EDIT_TEXT,     const_cast\u003CPWSTR>(L\"Username\") },\n    { TFI_PASSWORD,  CPFT_PASSWORD_TEXT, const_cast\u003CPWSTR>(L\"Password\") },\n    { TFI_OTP,       CPFT_PASSWORD_TEXT, const_cast\u003CPWSTR>(L\"One-time code\") },\n    { TFI_SUBMIT,    CPFT_SUBMIT_BUTTON, const_cast\u003CPWSTR>(L\"Submit\") },\n};\n\n\u002F\u002F States for a user tile. CTacCredential::Initialize changes them for the\n\u002F\u002F fallback tile and the RDP tile.\nstatic const FIELD_STATE_PAIR s_rgFieldStatePairs[] =\n{\n    { CPFS_DISPLAY_IN_BOTH,          CPFIS_NONE    },   \u002F\u002F TFI_TILEIMAGE\n    { CPFS_HIDDEN,                   CPFIS_NONE    },   \u002F\u002F TFI_LABEL\n    { CPFS_HIDDEN,                   CPFIS_NONE    },   \u002F\u002F TFI_USERNAME\n    { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_FOCUSED },   \u002F\u002F TFI_PASSWORD\n    { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE    },   \u002F\u002F TFI_OTP\n    { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE    },   \u002F\u002F TFI_SUBMIT\n};\n",[69,10464,10465,10471,10477,10484,10491,10495,10500,10505,10510,10518,10522,10534,10546,10562,10573,10585,10597,10608,10613,10617,10625,10629,10637,10645,10649,10653,10668,10672,10692,10711,10730,10748,10766,10784,10788,10792,10797,10802,10816,10820,10828,10836,10843,10851,10859,10866],{"__ignoreMap":154},[599,10466,10467,10469],{"class":601,"line":602},[599,10468,606],{"class":605},[599,10470,610],{"class":609},[599,10472,10473,10475],{"class":601,"line":613},[599,10474,616],{"class":605},[599,10476,620],{"class":619},[599,10478,10479,10481],{"class":601,"line":623},[599,10480,616],{"class":605},[599,10482,10483],{"class":619}," \u003Ccredentialprovider.h>\n",[599,10485,10486,10488],{"class":601,"line":631},[599,10487,616],{"class":605},[599,10489,10490],{"class":619}," \u003Cshlguid.h>\n",[599,10492,10493],{"class":601,"line":639},[599,10494,651],{"emptyLinePlaceholder":650},[599,10496,10497],{"class":601,"line":647},[599,10498,10499],{"class":772},"\u002F\u002F On a user tile Windows draws the account name and the round account picture\n",[599,10501,10502],{"class":601,"line":654},[599,10503,10504],{"class":772},"\u002F\u002F itself. TFI_TILEIMAGE and TFI_LABEL are only the small logo and the name of\n",[599,10506,10507],{"class":601,"line":663},[599,10508,10509],{"class":772},"\u002F\u002F our provider under \"Sign-in options\" (that is what the CPFG_ GUIDs mean).\n",[599,10511,10512,10515],{"class":601,"line":670},[599,10513,10514],{"class":605},"enum",[599,10516,10517],{"class":609}," TAC_FIELD_ID\n",[599,10519,10520],{"class":601,"line":728},[599,10521,667],{"class":666},[599,10523,10524,10527,10530,10532],{"class":601,"line":764},[599,10525,10526],{"class":949},"    TFI_TILEIMAGE",[599,10528,10529],{"class":605},"  =",[599,10531,1286],{"class":949},[599,10533,813],{"class":666},[599,10535,10536,10539,10542,10544],{"class":601,"line":769},[599,10537,10538],{"class":949},"    TFI_LABEL",[599,10540,10541],{"class":605},"      =",[599,10543,973],{"class":949},[599,10545,813],{"class":666},[599,10547,10548,10551,10554,10556,10559],{"class":601,"line":776},[599,10549,10550],{"class":949},"    TFI_USERNAME",[599,10552,10553],{"class":605},"   =",[599,10555,2576],{"class":949},[599,10557,10558],{"class":666},",",[599,10560,10561],{"class":772},"   \u002F\u002F only visible on the fallback tile\n",[599,10563,10564,10567,10569,10571],{"class":601,"line":816},[599,10565,10566],{"class":949},"    TFI_PASSWORD",[599,10568,10553],{"class":605},[599,10570,2608],{"class":949},[599,10572,813],{"class":666},[599,10574,10575,10578,10581,10583],{"class":601,"line":843},[599,10576,10577],{"class":949},"    TFI_OTP",[599,10579,10580],{"class":605},"        =",[599,10582,6716],{"class":949},[599,10584,813],{"class":666},[599,10586,10587,10590,10593,10595],{"class":601,"line":848},[599,10588,10589],{"class":949},"    TFI_SUBMIT",[599,10591,10592],{"class":605},"     =",[599,10594,1435],{"class":949},[599,10596,813],{"class":666},[599,10598,10599,10602,10604,10606],{"class":601,"line":854},[599,10600,10601],{"class":949},"    TFI_NUM_FIELDS",[599,10603,946],{"class":605},[599,10605,961],{"class":949},[599,10607,813],{"class":666},[599,10609,10610],{"class":601,"line":860},[599,10611,10612],{"class":666},"};\n",[599,10614,10615],{"class":601,"line":866},[599,10616,651],{"emptyLinePlaceholder":650},[599,10618,10619,10622],{"class":601,"line":912},[599,10620,10621],{"class":605},"struct",[599,10623,10624],{"class":609}," FIELD_STATE_PAIR\n",[599,10626,10627],{"class":601,"line":938},[599,10628,667],{"class":666},[599,10630,10631,10634],{"class":601,"line":978},[599,10632,10633],{"class":609},"    CREDENTIAL_PROVIDER_FIELD_STATE",[599,10635,10636],{"class":666},"             cpfs;\n",[599,10638,10639,10642],{"class":601,"line":1316},[599,10640,10641],{"class":609},"    CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE",[599,10643,10644],{"class":666}," cpfis;\n",[599,10646,10647],{"class":601,"line":1321},[599,10648,10612],{"class":666},[599,10650,10651],{"class":601,"line":1335},[599,10652,651],{"emptyLinePlaceholder":650},[599,10654,10655,10657,10659,10662,10665],{"class":601,"line":1341},[599,10656,8856],{"class":605},[599,10658,1051],{"class":605},[599,10660,10661],{"class":609}," CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR",[599,10663,10664],{"class":666}," s_rgFieldDescriptors[] ",[599,10666,10667],{"class":605},"=\n",[599,10669,10670],{"class":601,"line":1367},[599,10671,667],{"class":666},[599,10673,10674,10677,10679,10682,10684,10686,10689],{"class":601,"line":1375},[599,10675,10676],{"class":666},"    { TFI_TILEIMAGE, CPFT_TILE_IMAGE,    ",[599,10678,2079],{"class":605},[599,10680,10681],{"class":666},"PWSTR",[599,10683,717],{"class":605},[599,10685,679],{"class":666},[599,10687,10688],{"class":619},"L\"Image\"",[599,10690,10691],{"class":666},"), CPFG_CREDENTIAL_PROVIDER_LOGO },\n",[599,10693,10694,10697,10699,10701,10703,10705,10708],{"class":601,"line":1391},[599,10695,10696],{"class":666},"    { TFI_LABEL,     CPFT_SMALL_TEXT,    ",[599,10698,2079],{"class":605},[599,10700,10681],{"class":666},[599,10702,717],{"class":605},[599,10704,679],{"class":666},[599,10706,10707],{"class":619},"L\"TheAdminCafe 2FA\"",[599,10709,10710],{"class":666},"), CPFG_CREDENTIAL_PROVIDER_LABEL },\n",[599,10712,10713,10716,10718,10720,10722,10724,10727],{"class":601,"line":1405},[599,10714,10715],{"class":666},"    { TFI_USERNAME,  CPFT_EDIT_TEXT,     ",[599,10717,2079],{"class":605},[599,10719,10681],{"class":666},[599,10721,717],{"class":605},[599,10723,679],{"class":666},[599,10725,10726],{"class":619},"L\"Username\"",[599,10728,10729],{"class":666},") },\n",[599,10731,10732,10735,10737,10739,10741,10743,10746],{"class":601,"line":1416},[599,10733,10734],{"class":666},"    { TFI_PASSWORD,  CPFT_PASSWORD_TEXT, ",[599,10736,2079],{"class":605},[599,10738,10681],{"class":666},[599,10740,717],{"class":605},[599,10742,679],{"class":666},[599,10744,10745],{"class":619},"L\"Password\"",[599,10747,10729],{"class":666},[599,10749,10750,10753,10755,10757,10759,10761,10764],{"class":601,"line":1421},[599,10751,10752],{"class":666},"    { TFI_OTP,       CPFT_PASSWORD_TEXT, ",[599,10754,2079],{"class":605},[599,10756,10681],{"class":666},[599,10758,717],{"class":605},[599,10760,679],{"class":666},[599,10762,10763],{"class":619},"L\"One-time code\"",[599,10765,10729],{"class":666},[599,10767,10768,10771,10773,10775,10777,10779,10782],{"class":601,"line":1449},[599,10769,10770],{"class":666},"    { TFI_SUBMIT,    CPFT_SUBMIT_BUTTON, ",[599,10772,2079],{"class":605},[599,10774,10681],{"class":666},[599,10776,717],{"class":605},[599,10778,679],{"class":666},[599,10780,10781],{"class":619},"L\"Submit\"",[599,10783,10729],{"class":666},[599,10785,10786],{"class":601,"line":1462},[599,10787,10612],{"class":666},[599,10789,10790],{"class":601,"line":1477},[599,10791,651],{"emptyLinePlaceholder":650},[599,10793,10794],{"class":601,"line":1483},[599,10795,10796],{"class":772},"\u002F\u002F States for a user tile. CTacCredential::Initialize changes them for the\n",[599,10798,10799],{"class":601,"line":1496},[599,10800,10801],{"class":772},"\u002F\u002F fallback tile and the RDP tile.\n",[599,10803,10804,10806,10808,10811,10814],{"class":601,"line":1523},[599,10805,8856],{"class":605},[599,10807,1051],{"class":605},[599,10809,10810],{"class":609}," FIELD_STATE_PAIR",[599,10812,10813],{"class":666}," s_rgFieldStatePairs[] ",[599,10815,10667],{"class":605},[599,10817,10818],{"class":601,"line":1555},[599,10819,667],{"class":666},[599,10821,10822,10825],{"class":601,"line":1561},[599,10823,10824],{"class":666},"    { CPFS_DISPLAY_IN_BOTH,          CPFIS_NONE    },",[599,10826,10827],{"class":772},"   \u002F\u002F TFI_TILEIMAGE\n",[599,10829,10830,10833],{"class":601,"line":1567},[599,10831,10832],{"class":666},"    { CPFS_HIDDEN,                   CPFIS_NONE    },",[599,10834,10835],{"class":772},"   \u002F\u002F TFI_LABEL\n",[599,10837,10838,10840],{"class":601,"line":1577},[599,10839,10832],{"class":666},[599,10841,10842],{"class":772},"   \u002F\u002F TFI_USERNAME\n",[599,10844,10845,10848],{"class":601,"line":1582},[599,10846,10847],{"class":666},"    { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_FOCUSED },",[599,10849,10850],{"class":772},"   \u002F\u002F TFI_PASSWORD\n",[599,10852,10853,10856],{"class":601,"line":1587},[599,10854,10855],{"class":666},"    { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE    },",[599,10857,10858],{"class":772},"   \u002F\u002F TFI_OTP\n",[599,10860,10861,10863],{"class":601,"line":1616},[599,10862,10855],{"class":666},[599,10864,10865],{"class":772},"   \u002F\u002F TFI_SUBMIT\n",[599,10867,10868],{"class":601,"line":1621},[599,10869,10612],{"class":666},[15,10871,10872,10873,10876],{},"The type (",[69,10874,10875],{},"CPFT_*",") tells LogonUI how to show the field. The tile is bound to a user (see below), so Windows draws the account name and its round picture itself, exactly like the built-in tiles. The image field here is only the small logo of our provider under \"Sign-in options\", and the label is its name. The username field is hidden on normal user tiles. It is only visible on a fallback tile that I explain below.",[126,10878,10880],{"id":10879},"the-provider","The provider",[15,10882,10883,590],{},[69,10884,10885],{},"CTacProvider.h",[148,10887,10889],{"className":593,"code":10888,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccredentialprovider.h>\n#include \u003Cstring>\n#include \u003Cvector>\n#include \"CTacCredential.h\"\n\n\u002F\u002F Creates one tile per local user, like the built-in Windows tiles. Windows\n\u002F\u002F hands us the users through ICredentialProviderSetUserArray; because each tile\n\u002F\u002F is bound to a user (via GetUserSid), Windows draws the name and round picture.\nclass CTacProvider : public ICredentialProvider,\n                     public ICredentialProviderSetUserArray\n{\npublic:\n    CTacProvider();\n\n    \u002F\u002F IUnknown\n    IFACEMETHODIMP_(ULONG) AddRef();\n    IFACEMETHODIMP_(ULONG) Release();\n    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);\n\n    \u002F\u002F ICredentialProvider\n    IFACEMETHODIMP SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD dwFlags);\n    IFACEMETHODIMP SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs);\n    IFACEMETHODIMP Advise(ICredentialProviderEvents* pcpe, UINT_PTR upAdviseContext);\n    IFACEMETHODIMP UnAdvise();\n    IFACEMETHODIMP GetFieldDescriptorCount(DWORD* pdwCount);\n    IFACEMETHODIMP GetFieldDescriptorAt(DWORD dwIndex, CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd);\n    IFACEMETHODIMP GetCredentialCount(DWORD* pdwCount, DWORD* pdwDefault, BOOL* pbAutoLogonWithDefault);\n    IFACEMETHODIMP GetCredentialAt(DWORD dwIndex, ICredentialProviderCredential** ppcpc);\n\n    \u002F\u002F ICredentialProviderSetUserArray\n    IFACEMETHODIMP SetUserArray(ICredentialProviderUserArray* users);\n\n    friend HRESULT CTacProvider_CreateInstance(REFIID riid, void** ppv);\n\nprivate:\n    virtual ~CTacProvider();\n\n    void    _ClearCredentials();\n    HRESULT _CreateCredentials();\n    HRESULT _AddCredential(PCWSTR pwzUser, PCWSTR pwzPassword, PCWSTR pwzSid);\n\n    LONG                               _cRef;\n    CREDENTIAL_PROVIDER_USAGE_SCENARIO _cpus;\n    ICredentialProviderUserArray*      _pUserArray;\n    std::vector\u003CCTacCredential*>       _credentials;\n    bool                               _built;\n    DWORD                              _defaultIndex;\n\n    \u002F\u002F Set by SetSerialization when RDP forwards a credential to us.\n    bool                               _haveRemote;\n    std::wstring                       _remoteUser;\n    std::wstring                       _remotePassword;\n};\n",[69,10890,10891,10897,10903,10909,10915,10921,10928,10932,10937,10942,10947,10966,10974,10978,10983,10990,10994,10999,11015,11030,11056,11060,11065,11089,11110,11137,11146,11164,11190,11226,11250,11254,11259,11278,11282,11307,11311,11316,11326,11330,11340,11350,11381,11385,11393,11401,11411,11429,11436,11444,11448,11453,11460,11471,11482],{"__ignoreMap":154},[599,10892,10893,10895],{"class":601,"line":602},[599,10894,606],{"class":605},[599,10896,610],{"class":609},[599,10898,10899,10901],{"class":601,"line":613},[599,10900,616],{"class":605},[599,10902,620],{"class":619},[599,10904,10905,10907],{"class":601,"line":623},[599,10906,616],{"class":605},[599,10908,10483],{"class":619},[599,10910,10911,10913],{"class":601,"line":631},[599,10912,616],{"class":605},[599,10914,636],{"class":619},[599,10916,10917,10919],{"class":601,"line":639},[599,10918,616],{"class":605},[599,10920,644],{"class":619},[599,10922,10923,10925],{"class":601,"line":647},[599,10924,616],{"class":605},[599,10926,10927],{"class":619}," \"CTacCredential.h\"\n",[599,10929,10930],{"class":601,"line":654},[599,10931,651],{"emptyLinePlaceholder":650},[599,10933,10934],{"class":601,"line":663},[599,10935,10936],{"class":772},"\u002F\u002F Creates one tile per local user, like the built-in Windows tiles. Windows\n",[599,10938,10939],{"class":601,"line":670},[599,10940,10941],{"class":772},"\u002F\u002F hands us the users through ICredentialProviderSetUserArray; because each tile\n",[599,10943,10944],{"class":601,"line":728},[599,10945,10946],{"class":772},"\u002F\u002F is bound to a user (via GetUserSid), Windows draws the name and round picture.\n",[599,10948,10949,10952,10955,10958,10961,10964],{"class":601,"line":764},[599,10950,10951],{"class":605},"class",[599,10953,10954],{"class":609}," CTacProvider",[599,10956,10957],{"class":666}," : ",[599,10959,10960],{"class":605},"public",[599,10962,10963],{"class":609}," ICredentialProvider",[599,10965,813],{"class":666},[599,10967,10968,10971],{"class":601,"line":769},[599,10969,10970],{"class":605},"                     public",[599,10972,10973],{"class":609}," ICredentialProviderSetUserArray\n",[599,10975,10976],{"class":601,"line":776},[599,10977,667],{"class":666},[599,10979,10980],{"class":601,"line":816},[599,10981,10982],{"class":605},"public:\n",[599,10984,10985,10988],{"class":601,"line":843},[599,10986,10987],{"class":609},"    CTacProvider",[599,10989,1313],{"class":666},[599,10991,10992],{"class":601,"line":848},[599,10993,651],{"emptyLinePlaceholder":650},[599,10995,10996],{"class":601,"line":854},[599,10997,10998],{"class":772},"    \u002F\u002F IUnknown\n",[599,11000,11001,11004,11006,11008,11010,11013],{"class":601,"line":860},[599,11002,11003],{"class":609},"    IFACEMETHODIMP_",[599,11005,679],{"class":666},[599,11007,1924],{"class":609},[599,11009,1124],{"class":666},[599,11011,11012],{"class":609},"AddRef",[599,11014,1313],{"class":666},[599,11016,11017,11019,11021,11023,11025,11028],{"class":601,"line":866},[599,11018,11003],{"class":609},[599,11020,679],{"class":666},[599,11022,1924],{"class":609},[599,11024,1124],{"class":666},[599,11026,11027],{"class":609},"Release",[599,11029,1313],{"class":666},[599,11031,11032,11035,11038,11040,11043,11046,11048,11051,11054],{"class":601,"line":912},[599,11033,11034],{"class":609},"    IFACEMETHODIMP",[599,11036,11037],{"class":609}," QueryInterface",[599,11039,679],{"class":666},[599,11041,11042],{"class":609},"REFIID",[599,11044,11045],{"class":697}," riid",[599,11047,212],{"class":666},[599,11049,11050],{"class":605},"void**",[599,11052,11053],{"class":697}," ppv",[599,11055,725],{"class":666},[599,11057,11058],{"class":601,"line":938},[599,11059,651],{"emptyLinePlaceholder":650},[599,11061,11062],{"class":601,"line":978},[599,11063,11064],{"class":772},"    \u002F\u002F ICredentialProvider\n",[599,11066,11067,11069,11072,11074,11077,11080,11082,11084,11087],{"class":601,"line":1316},[599,11068,11034],{"class":609},[599,11070,11071],{"class":609}," SetUsageScenario",[599,11073,679],{"class":666},[599,11075,11076],{"class":609},"CREDENTIAL_PROVIDER_USAGE_SCENARIO",[599,11078,11079],{"class":697}," cpus",[599,11081,212],{"class":666},[599,11083,5878],{"class":609},[599,11085,11086],{"class":697}," dwFlags",[599,11088,725],{"class":666},[599,11090,11091,11093,11096,11098,11100,11103,11105,11108],{"class":601,"line":1321},[599,11092,11034],{"class":609},[599,11094,11095],{"class":609}," SetSerialization",[599,11097,679],{"class":666},[599,11099,682],{"class":605},[599,11101,11102],{"class":609}," CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION",[599,11104,748],{"class":605},[599,11106,11107],{"class":697}," pcpcs",[599,11109,725],{"class":666},[599,11111,11112,11114,11117,11119,11122,11124,11127,11129,11132,11135],{"class":601,"line":1335},[599,11113,11034],{"class":609},[599,11115,11116],{"class":609}," Advise",[599,11118,679],{"class":666},[599,11120,11121],{"class":609},"ICredentialProviderEvents",[599,11123,748],{"class":605},[599,11125,11126],{"class":697}," pcpe",[599,11128,212],{"class":666},[599,11130,11131],{"class":609},"UINT_PTR",[599,11133,11134],{"class":697}," upAdviseContext",[599,11136,725],{"class":666},[599,11138,11139,11141,11144],{"class":601,"line":1341},[599,11140,11034],{"class":609},[599,11142,11143],{"class":609}," UnAdvise",[599,11145,1313],{"class":666},[599,11147,11148,11150,11153,11155,11157,11159,11162],{"class":601,"line":1367},[599,11149,11034],{"class":609},[599,11151,11152],{"class":609}," GetFieldDescriptorCount",[599,11154,679],{"class":666},[599,11156,5878],{"class":609},[599,11158,748],{"class":605},[599,11160,11161],{"class":697}," pdwCount",[599,11163,725],{"class":666},[599,11165,11166,11168,11171,11173,11175,11178,11180,11183,11185,11188],{"class":601,"line":1375},[599,11167,11034],{"class":609},[599,11169,11170],{"class":609}," GetFieldDescriptorAt",[599,11172,679],{"class":666},[599,11174,5878],{"class":609},[599,11176,11177],{"class":697}," dwIndex",[599,11179,212],{"class":666},[599,11181,11182],{"class":609},"CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR",[599,11184,4056],{"class":605},[599,11186,11187],{"class":697}," ppcpfd",[599,11189,725],{"class":666},[599,11191,11192,11194,11197,11199,11201,11203,11205,11207,11209,11211,11214,11216,11219,11221,11224],{"class":601,"line":1391},[599,11193,11034],{"class":609},[599,11195,11196],{"class":609}," GetCredentialCount",[599,11198,679],{"class":666},[599,11200,5878],{"class":609},[599,11202,748],{"class":605},[599,11204,11161],{"class":697},[599,11206,212],{"class":666},[599,11208,5878],{"class":609},[599,11210,748],{"class":605},[599,11212,11213],{"class":697}," pdwDefault",[599,11215,212],{"class":666},[599,11217,11218],{"class":609},"BOOL",[599,11220,748],{"class":605},[599,11222,11223],{"class":697}," pbAutoLogonWithDefault",[599,11225,725],{"class":666},[599,11227,11228,11230,11233,11235,11237,11239,11241,11243,11245,11248],{"class":601,"line":1405},[599,11229,11034],{"class":609},[599,11231,11232],{"class":609}," GetCredentialAt",[599,11234,679],{"class":666},[599,11236,5878],{"class":609},[599,11238,11177],{"class":697},[599,11240,212],{"class":666},[599,11242,229],{"class":609},[599,11244,4056],{"class":605},[599,11246,11247],{"class":697}," ppcpc",[599,11249,725],{"class":666},[599,11251,11252],{"class":601,"line":1416},[599,11253,651],{"emptyLinePlaceholder":650},[599,11255,11256],{"class":601,"line":1421},[599,11257,11258],{"class":772},"    \u002F\u002F ICredentialProviderSetUserArray\n",[599,11260,11261,11263,11266,11268,11271,11273,11276],{"class":601,"line":1449},[599,11262,11034],{"class":609},[599,11264,11265],{"class":609}," SetUserArray",[599,11267,679],{"class":666},[599,11269,11270],{"class":609},"ICredentialProviderUserArray",[599,11272,748],{"class":605},[599,11274,11275],{"class":697}," users",[599,11277,725],{"class":666},[599,11279,11280],{"class":601,"line":1462},[599,11281,651],{"emptyLinePlaceholder":650},[599,11283,11284,11287,11290,11293,11295,11297,11299,11301,11303,11305],{"class":601,"line":1477},[599,11285,11286],{"class":605},"    friend",[599,11288,11289],{"class":609}," HRESULT",[599,11291,11292],{"class":609}," CTacProvider_CreateInstance",[599,11294,679],{"class":666},[599,11296,11042],{"class":609},[599,11298,11045],{"class":697},[599,11300,212],{"class":666},[599,11302,11050],{"class":605},[599,11304,11053],{"class":697},[599,11306,725],{"class":666},[599,11308,11309],{"class":601,"line":1483},[599,11310,651],{"emptyLinePlaceholder":650},[599,11312,11313],{"class":601,"line":1496},[599,11314,11315],{"class":605},"private:\n",[599,11317,11318,11321,11324],{"class":601,"line":1523},[599,11319,11320],{"class":605},"    virtual",[599,11322,11323],{"class":609}," ~CTacProvider",[599,11325,1313],{"class":666},[599,11327,11328],{"class":601,"line":1555},[599,11329,651],{"emptyLinePlaceholder":650},[599,11331,11332,11335,11338],{"class":601,"line":1561},[599,11333,11334],{"class":605},"    void",[599,11336,11337],{"class":609},"    _ClearCredentials",[599,11339,1313],{"class":666},[599,11341,11342,11345,11348],{"class":601,"line":1567},[599,11343,11344],{"class":609},"    HRESULT",[599,11346,11347],{"class":609}," _CreateCredentials",[599,11349,1313],{"class":666},[599,11351,11352,11354,11357,11359,11362,11365,11367,11369,11372,11374,11376,11379],{"class":601,"line":1577},[599,11353,11344],{"class":609},[599,11355,11356],{"class":609}," _AddCredential",[599,11358,679],{"class":666},[599,11360,11361],{"class":609},"PCWSTR",[599,11363,11364],{"class":697}," pwzUser",[599,11366,212],{"class":666},[599,11368,11361],{"class":609},[599,11370,11371],{"class":697}," pwzPassword",[599,11373,212],{"class":666},[599,11375,11361],{"class":609},[599,11377,11378],{"class":697}," pwzSid",[599,11380,725],{"class":666},[599,11382,11383],{"class":601,"line":1582},[599,11384,651],{"emptyLinePlaceholder":650},[599,11386,11387,11390],{"class":601,"line":1587},[599,11388,11389],{"class":609},"    LONG",[599,11391,11392],{"class":666},"                               _cRef;\n",[599,11394,11395,11398],{"class":601,"line":1616},[599,11396,11397],{"class":609},"    CREDENTIAL_PROVIDER_USAGE_SCENARIO",[599,11399,11400],{"class":666}," _cpus;\n",[599,11402,11403,11406,11408],{"class":601,"line":1621},[599,11404,11405],{"class":609},"    ICredentialProviderUserArray",[599,11407,748],{"class":605},[599,11409,11410],{"class":666},"      _pUserArray;\n",[599,11412,11413,11415,11417,11419,11421,11424,11426],{"class":601,"line":1634},[599,11414,731],{"class":609},[599,11416,688],{"class":666},[599,11418,708],{"class":609},[599,11420,711],{"class":666},[599,11422,11423],{"class":609},"CTacCredential",[599,11425,748],{"class":605},[599,11427,11428],{"class":666},">       _credentials;\n",[599,11430,11431,11433],{"class":601,"line":1647},[599,11432,673],{"class":605},[599,11434,11435],{"class":666},"                               _built;\n",[599,11437,11438,11441],{"class":601,"line":1660},[599,11439,11440],{"class":609},"    DWORD",[599,11442,11443],{"class":666},"                              _defaultIndex;\n",[599,11445,11446],{"class":601,"line":1665},[599,11447,651],{"emptyLinePlaceholder":650},[599,11449,11450],{"class":601,"line":1695},[599,11451,11452],{"class":772},"    \u002F\u002F Set by SetSerialization when RDP forwards a credential to us.\n",[599,11454,11455,11457],{"class":601,"line":1700},[599,11456,673],{"class":605},[599,11458,11459],{"class":666},"                               _haveRemote;\n",[599,11461,11462,11464,11466,11468],{"class":601,"line":1720},[599,11463,731],{"class":609},[599,11465,688],{"class":666},[599,11467,902],{"class":609},[599,11469,11470],{"class":666},"                       _remoteUser;\n",[599,11472,11473,11475,11477,11479],{"class":601,"line":1731},[599,11474,731],{"class":609},[599,11476,688],{"class":666},[599,11478,902],{"class":609},[599,11480,11481],{"class":666},"                       _remotePassword;\n",[599,11483,11484],{"class":601,"line":1745},[599,11485,10612],{"class":666},[15,11487,11488,590],{},[69,11489,11490],{},"CTacProvider.cpp",[148,11492,11494],{"className":593,"code":11493,"language":595,"meta":154,"style":154},"#include \"CTacProvider.h\"\n#include \"helpers.h\"\n#include \"common.h\"\n#include \"dll.h\"\n#include \"guid.h\"\n\n#include \u003Cntsecapi.h>\n#include \u003Cnew>\n\n\u002F\u002F System.Identity.QualifiedUserName. This is the \"DOMAIN\\user\" (or \"PC\\user\")\n\u002F\u002F form LSA needs. The key is defined by value here so we do not have to link\n\u002F\u002F propsys just for one property. See the Microsoft property documentation.\nstatic const PROPERTYKEY PKEY_QualifiedUserName =\n    { { 0xDA520E51, 0xF4E9, 0x4739, { 0xAC, 0x82, 0x02, 0xE0, 0xA9, 0x5C, 0x90, 0x30 } }, 100 };\n\nCTacProvider::CTacProvider()\n    : _cRef(1), _cpus(CPUS_INVALID), _pUserArray(nullptr), _built(false),\n      _defaultIndex(CREDENTIAL_PROVIDER_NO_DEFAULT), _haveRemote(false)\n{\n    DllAddRef();\n}\n\nCTacProvider::~CTacProvider()\n{\n    _ClearCredentials();\n    if (!_remotePassword.empty())\n        SecureZeroMemory(&_remotePassword[0], _remotePassword.size() * sizeof(WCHAR));\n    if (_pUserArray)\n        _pUserArray->Release();\n    DllRelease();\n}\n\nvoid CTacProvider::_ClearCredentials()\n{\n    for (CTacCredential* c : _credentials)\n        c->Release();\n    _credentials.clear();\n    _built = false;\n    _defaultIndex = CREDENTIAL_PROVIDER_NO_DEFAULT;\n}\n\n\u002F\u002F --- IUnknown ---------------------------------------------------------------\n\nIFACEMETHODIMP_(ULONG) CTacProvider::AddRef()\n{\n    return InterlockedIncrement(&_cRef);\n}\n\nIFACEMETHODIMP_(ULONG) CTacProvider::Release()\n{\n    LONG cRef = InterlockedDecrement(&_cRef);\n    if (cRef == 0)\n        delete this;\n    return cRef;\n}\n\nIFACEMETHODIMP CTacProvider::QueryInterface(REFIID riid, void** ppv)\n{\n    if (!ppv)\n        return E_POINTER;\n    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, __uuidof(ICredentialProvider)))\n    {\n        *ppv = static_cast\u003CICredentialProvider*>(this);\n        AddRef();\n        return S_OK;\n    }\n    if (IsEqualIID(riid, __uuidof(ICredentialProviderSetUserArray)))\n    {\n        *ppv = static_cast\u003CICredentialProviderSetUserArray*>(this);\n        AddRef();\n        return S_OK;\n    }\n    *ppv = nullptr;\n    return E_NOINTERFACE;\n}\n\n\u002F\u002F --- ICredentialProvider ----------------------------------------------------\n\nIFACEMETHODIMP CTacProvider::SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD)\n{\n    switch (cpus)\n    {\n    case CPUS_LOGON:\n    case CPUS_UNLOCK_WORKSTATION:\n        _cpus = cpus;\n        return S_OK;\n\n    \u002F\u002F We take part in logon and unlock only. Declining the rest cleanly is\n    \u002F\u002F important: misbehaving in CPUS_CREDUI would break UAC prompts.\n    case CPUS_CHANGE_PASSWORD:\n    case CPUS_CREDUI:\n    case CPUS_PLAP:\n        return E_NOTIMPL;\n\n    default:\n        return E_INVALIDARG;\n    }\n}\n\n\u002F\u002F A qualified name is local when the part before the backslash is this computer.\n\u002F\u002F \"CONTOSO\\alice\" or \"MicrosoftAccount\\...\" are not, and get no tile: the secret\n\u002F\u002F is stored per bare name and this demo authenticates only against the local SAM.\nstatic bool IsLocalAccount(PCWSTR qualified)\n{\n    const wchar_t* slash = qualified ? wcschr(qualified, L'\\\\') : nullptr;\n    if (!slash)\n        return false;\n\n    WCHAR computer[MAX_COMPUTERNAME_LENGTH + 1] = {};\n    DWORD cchComputer = ARRAYSIZE(computer);\n    if (!GetComputerNameW(computer, &cchComputer))\n        return false;\n\n    size_t domainLen = static_cast\u003Csize_t>(slash - qualified);\n    return domainLen == cchComputer && _wcsnicmp(qualified, computer, domainLen) == 0;\n}\n\nHRESULT CTacProvider::_AddCredential(PCWSTR pwzUser, PCWSTR pwzPassword, PCWSTR pwzSid)\n{\n    CTacCredential* cred = new (std::nothrow) CTacCredential();\n    if (!cred)\n        return E_OUTOFMEMORY;\n\n    HRESULT hr = cred->Initialize(_cpus, s_rgFieldDescriptors, s_rgFieldStatePairs,\n                                  pwzUser, pwzPassword, pwzSid);\n    if (FAILED(hr))\n    {\n        cred->Release();\n        return hr;\n    }\n\n    _credentials.push_back(cred);\n    return S_OK;\n}\n\nHRESULT CTacProvider::_CreateCredentials()\n{\n    if (_built)\n        return S_OK;\n    _ClearCredentials();\n\n    \u002F\u002F RDP path: one tile, pre-filled with the forwarded name and password.\n    if (_haveRemote)\n    {\n        if (SUCCEEDED(_AddCredential(_remoteUser.c_str(), _remotePassword.c_str(), nullptr)))\n            _defaultIndex = 0;\n\n        \u002F\u002F The tile has its own copy now, so drop ours.\n        if (!_remotePassword.empty())\n        {\n            SecureZeroMemory(&_remotePassword[0], _remotePassword.size() * sizeof(WCHAR));\n            _remotePassword.clear();\n        }\n        _built = true;\n        return S_OK;\n    }\n\n    DWORD count = 0;\n    if (_pUserArray)\n        _pUserArray->GetCount(&count);\n\n    for (DWORD i = 0; i \u003C count; ++i)\n    {\n        ICredentialProviderUser* user = nullptr;\n        if (FAILED(_pUserArray->GetAt(i, &user)) || !user)\n            continue;\n\n        PWSTR qualified = nullptr;\n        PWSTR sid       = nullptr;\n        user->GetStringValue(PKEY_QualifiedUserName, &qualified);\n        user->GetSid(&sid);\n\n        if (qualified && sid && IsLocalAccount(qualified))\n            _AddCredential(qualified, L\"\", sid);\n\n        CoTaskMemFree(qualified);\n        CoTaskMemFree(sid);\n        user->Release();\n    }\n\n    \u002F\u002F If no local user tile was created (for example when Windows does not list\n    \u002F\u002F local users), add one generic tile with a username field. Without it the\n    \u002F\u002F filter could leave nobody a way to log on.\n    if (_credentials.empty())\n        _AddCredential(L\"\", L\"\", nullptr);\n\n    _built = true;\n    return S_OK;\n}\n\n\u002F\u002F RDP with NLA forwards the credential over CredSSP before any tile is drawn.\n\u002F\u002F We unpack it and remember the name and password to pre-fill the tile.\nIFACEMETHODIMP CTacProvider::SetSerialization(\n    const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs)\n{\n    if (!pcpcs || !pcpcs->rgbSerialization ||\n        pcpcs->cbSerialization \u003C sizeof(KERB_INTERACTIVE_UNLOCK_LOGON))\n        return E_NOTIMPL;\n    if (!IsEqualCLSID(pcpcs->clsidCredentialProvider, CLSID_CTacProvider))\n        return E_NOTIMPL;   \u002F\u002F not addressed to us\n\n    \u002F\u002F Work on our own copy, because unpacking rewrites the offsets to pointers.\n    KERB_INTERACTIVE_UNLOCK_LOGON* pkiul =\n        static_cast\u003CKERB_INTERACTIVE_UNLOCK_LOGON*>(CoTaskMemAlloc(pcpcs->cbSerialization));\n    if (!pkiul)\n        return E_OUTOFMEMORY;\n    CopyMemory(pkiul, pcpcs->rgbSerialization, pcpcs->cbSerialization);\n\n    \u002F\u002F RDP can also forward other logon types, a smartcard logon for example.\n    \u002F\u002F Only a password logon has the layout we unpack below.\n    HRESULT hr = S_OK;\n    if (pkiul->Logon.MessageType != KerbInteractiveLogon &&\n        pkiul->Logon.MessageType != KerbWorkstationUnlockLogon)\n        hr = E_NOTIMPL;\n\n    if (SUCCEEDED(hr))\n        hr = KerbInteractiveUnlockLogonUnpackInPlace(pkiul, pcpcs->cbSerialization);\n    if (SUCCEEDED(hr))\n    {\n        const KERB_INTERACTIVE_LOGON& kil = pkiul->Logon;\n\n        \u002F\u002F A UNICODE_STRING is counted, not null-terminated, and Buffer can be\n        \u002F\u002F null (empty domain), which std::wstring must not be built from.\n        auto toString = [](const UNICODE_STRING& us) -> std::wstring {\n            if (!us.Buffer || us.Length == 0)\n                return std::wstring();\n            return std::wstring(us.Buffer, us.Length \u002F sizeof(WCHAR));\n        };\n\n        std::wstring domain = toString(kil.LogonDomainName);\n        std::wstring user   = toString(kil.UserName);\n        std::wstring pass   = toString(kil.Password);\n\n        if (!_remotePassword.empty())\n            SecureZeroMemory(&_remotePassword[0], _remotePassword.size() * sizeof(WCHAR));\n\n        _remoteUser     = domain.empty() ? user : (domain + L\"\\\\\" + user);\n        _remotePassword = pass;\n        _haveRemote     = true;\n        _built          = false;\n\n        if (!pass.empty())\n            SecureZeroMemory(&pass[0], pass.size() * sizeof(WCHAR));\n    }\n\n    SecureZeroMemory(pkiul, pcpcs->cbSerialization);\n    CoTaskMemFree(pkiul);\n    return hr;\n}\n\nIFACEMETHODIMP CTacProvider::Advise(ICredentialProviderEvents*, UINT_PTR) { return S_OK; }\nIFACEMETHODIMP CTacProvider::UnAdvise() { return S_OK; }\n\nIFACEMETHODIMP CTacProvider::GetFieldDescriptorCount(DWORD* pdwCount)\n{\n    *pdwCount = TFI_NUM_FIELDS;\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacProvider::GetFieldDescriptorAt(DWORD dwIndex,\n                                                  CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd)\n{\n    if (dwIndex >= TFI_NUM_FIELDS || !ppcpfd)\n        return E_INVALIDARG;\n    return FieldDescriptorCoAllocCopy(s_rgFieldDescriptors[dwIndex], ppcpfd);\n}\n\nIFACEMETHODIMP CTacProvider::GetCredentialCount(DWORD* pdwCount, DWORD* pdwDefault,\n                                                BOOL* pbAutoLogonWithDefault)\n{\n    _CreateCredentials();\n    *pdwCount = static_cast\u003CDWORD>(_credentials.size());\n    *pdwDefault = _defaultIndex;\n    *pbAutoLogonWithDefault = FALSE;\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacProvider::GetCredentialAt(DWORD dwIndex,\n                                             ICredentialProviderCredential** ppcpc)\n{\n    if (!ppcpc)\n        return E_INVALIDARG;\n    _CreateCredentials();\n    if (dwIndex >= _credentials.size())\n        return E_INVALIDARG;\n    return _credentials[dwIndex]->QueryInterface(IID_PPV_ARGS(ppcpc));\n}\n\n\u002F\u002F --- ICredentialProviderSetUserArray ----------------------------------------\n\nIFACEMETHODIMP CTacProvider::SetUserArray(ICredentialProviderUserArray* users)\n{\n    if (_pUserArray)\n        _pUserArray->Release();\n    _pUserArray = users;\n    if (_pUserArray)\n        _pUserArray->AddRef();\n    _built = false;\n    return S_OK;\n}\n\nHRESULT CTacProvider_CreateInstance(REFIID riid, void** ppv)\n{\n    CTacProvider* provider = new (std::nothrow) CTacProvider();\n    if (!provider)\n        return E_OUTOFMEMORY;\n    HRESULT hr = provider->QueryInterface(riid, ppv);\n    provider->Release();\n    return hr;\n}\n",[69,11495,11496,11503,11510,11517,11524,11531,11535,11542,11549,11553,11558,11563,11568,11579,11669,11673,11684,11724,11741,11745,11752,11756,11760,11773,11777,11783,11798,11825,11832,11841,11848,11852,11856,11870,11874,11887,11896,11905,11916,11926,11930,11934,11939,11943,11959,11963,11977,11981,11985,11999,12003,12021,12034,12044,12051,12055,12059,12085,12089,12100,12107,12133,12137,12159,12166,12173,12177,12192,12196,12216,12222,12228,12232,12245,12252,12256,12260,12265,12269,12291,12295,12303,12307,12315,12322,12332,12338,12342,12347,12352,12359,12366,12373,12380,12384,12391,12398,12402,12406,12410,12415,12420,12425,12443,12447,12483,12494,12502,12506,12521,12533,12549,12557,12561,12581,12605,12609,12613,12645,12649,12675,12686,12693,12697,12715,12720,12732,12736,12745,12752,12756,12760,12769,12775,12779,12783,12796,12800,12807,12813,12819,12823,12828,12835,12839,12869,12880,12884,12889,12903,12907,12932,12941,12945,12956,12962,12966,12970,12983,12989,13003,13007,13029,13033,13048,13077,13084,13088,13100,13113,13129,13143,13147,13166,13179,13183,13191,13198,13206,13210,13214,13219,13224,13229,13240,13259,13263,13273,13279,13283,13287,13292,13297,13311,13323,13327,13348,13360,13366,13380,13390,13394,13399,13411,13429,13440,13446,13454,13458,13463,13468,13478,13493,13503,13512,13516,13526,13538,13548,13552,13569,13573,13578,13583,13614,13636,13648,13667,13672,13676,13695,13713,13731,13735,13749,13773,13777,13813,13823,13834,13845,13849,13864,13890,13894,13898,13904,13912,13918,13922,13926,13955,13973,13977,13997,14001,14013,14019,14023,14028,14047,14059,14064,14084,14091,14102,14107,14112,14141,14153,14158,14166,14188,14201,14214,14221,14226,14231,14250,14262,14267,14279,14286,14293,14309,14316,14334,14339,14344,14350,14355,14376,14381,14388,14397,14408,14415,14424,14435,14442,14447,14452,14473,14478,14502,14514,14521,14538,14548,14555],{"__ignoreMap":154},[599,11497,11498,11500],{"class":601,"line":602},[599,11499,616],{"class":605},[599,11501,11502],{"class":619}," \"CTacProvider.h\"\n",[599,11504,11505,11507],{"class":601,"line":613},[599,11506,616],{"class":605},[599,11508,11509],{"class":619}," \"helpers.h\"\n",[599,11511,11512,11514],{"class":601,"line":623},[599,11513,616],{"class":605},[599,11515,11516],{"class":619}," \"common.h\"\n",[599,11518,11519,11521],{"class":601,"line":631},[599,11520,616],{"class":605},[599,11522,11523],{"class":619}," \"dll.h\"\n",[599,11525,11526,11528],{"class":601,"line":639},[599,11527,616],{"class":605},[599,11529,11530],{"class":619}," \"guid.h\"\n",[599,11532,11533],{"class":601,"line":647},[599,11534,651],{"emptyLinePlaceholder":650},[599,11536,11537,11539],{"class":601,"line":654},[599,11538,616],{"class":605},[599,11540,11541],{"class":619}," \u003Cntsecapi.h>\n",[599,11543,11544,11546],{"class":601,"line":663},[599,11545,616],{"class":605},[599,11547,11548],{"class":619}," \u003Cnew>\n",[599,11550,11551],{"class":601,"line":670},[599,11552,651],{"emptyLinePlaceholder":650},[599,11554,11555],{"class":601,"line":728},[599,11556,11557],{"class":772},"\u002F\u002F System.Identity.QualifiedUserName. This is the \"DOMAIN\\user\" (or \"PC\\user\")\n",[599,11559,11560],{"class":601,"line":764},[599,11561,11562],{"class":772},"\u002F\u002F form LSA needs. The key is defined by value here so we do not have to link\n",[599,11564,11565],{"class":601,"line":769},[599,11566,11567],{"class":772},"\u002F\u002F propsys just for one property. See the Microsoft property documentation.\n",[599,11569,11570,11572,11574,11577],{"class":601,"line":776},[599,11571,8856],{"class":605},[599,11573,1051],{"class":605},[599,11575,11576],{"class":666}," PROPERTYKEY PKEY_QualifiedUserName ",[599,11578,10667],{"class":605},[599,11580,11581,11584,11587,11590,11592,11594,11597,11599,11601,11604,11607,11609,11612,11614,11616,11619,11621,11623,11626,11628,11630,11633,11635,11637,11640,11642,11644,11647,11649,11651,11654,11656,11658,11660,11663,11666],{"class":601,"line":816},[599,11582,11583],{"class":666},"    { { ",[599,11585,11586],{"class":605},"0x",[599,11588,11589],{"class":949},"DA520E51",[599,11591,212],{"class":666},[599,11593,11586],{"class":605},[599,11595,11596],{"class":949},"F4E9",[599,11598,212],{"class":666},[599,11600,11586],{"class":605},[599,11602,11603],{"class":949},"4739",[599,11605,11606],{"class":666},", { ",[599,11608,11586],{"class":605},[599,11610,11611],{"class":949},"AC",[599,11613,212],{"class":666},[599,11615,11586],{"class":605},[599,11617,11618],{"class":949},"82",[599,11620,212],{"class":666},[599,11622,11586],{"class":605},[599,11624,11625],{"class":949},"02",[599,11627,212],{"class":666},[599,11629,11586],{"class":605},[599,11631,11632],{"class":949},"E0",[599,11634,212],{"class":666},[599,11636,11586],{"class":605},[599,11638,11639],{"class":949},"A9",[599,11641,212],{"class":666},[599,11643,11586],{"class":605},[599,11645,11646],{"class":949},"5C",[599,11648,212],{"class":666},[599,11650,11586],{"class":605},[599,11652,11653],{"class":949},"90",[599,11655,212],{"class":666},[599,11657,11586],{"class":605},[599,11659,3878],{"class":949},[599,11661,11662],{"class":666}," } }, ",[599,11664,11665],{"class":949},"100",[599,11667,11668],{"class":666}," };\n",[599,11670,11671],{"class":601,"line":843},[599,11672,651],{"emptyLinePlaceholder":650},[599,11674,11675,11678,11680,11682],{"class":601,"line":848},[599,11676,11677],{"class":609},"CTacProvider",[599,11679,688],{"class":666},[599,11681,11677],{"class":609},[599,11683,3717],{"class":666},[599,11685,11686,11689,11692,11694,11696,11698,11701,11704,11707,11709,11711,11713,11716,11718,11721],{"class":601,"line":854},[599,11687,11688],{"class":666},"    : ",[599,11690,11691],{"class":609},"_cRef",[599,11693,679],{"class":666},[599,11695,1217],{"class":949},[599,11697,101],{"class":666},[599,11699,11700],{"class":609},"_cpus",[599,11702,11703],{"class":666},"(CPUS_INVALID), ",[599,11705,11706],{"class":609},"_pUserArray",[599,11708,679],{"class":666},[599,11710,2019],{"class":949},[599,11712,101],{"class":666},[599,11714,11715],{"class":609},"_built",[599,11717,679],{"class":666},[599,11719,11720],{"class":949},"false",[599,11722,11723],{"class":666},"),\n",[599,11725,11726,11729,11732,11735,11737,11739],{"class":601,"line":860},[599,11727,11728],{"class":609},"      _defaultIndex",[599,11730,11731],{"class":666},"(CREDENTIAL_PROVIDER_NO_DEFAULT), ",[599,11733,11734],{"class":609},"_haveRemote",[599,11736,679],{"class":666},[599,11738,11720],{"class":949},[599,11740,1029],{"class":666},[599,11742,11743],{"class":601,"line":866},[599,11744,667],{"class":666},[599,11746,11747,11750],{"class":601,"line":912},[599,11748,11749],{"class":609},"    DllAddRef",[599,11751,1313],{"class":666},[599,11753,11754],{"class":601,"line":938},[599,11755,981],{"class":666},[599,11757,11758],{"class":601,"line":978},[599,11759,651],{"emptyLinePlaceholder":650},[599,11761,11762,11764,11766,11769,11771],{"class":601,"line":1316},[599,11763,11677],{"class":609},[599,11765,688],{"class":666},[599,11767,11768],{"class":605},"~",[599,11770,11677],{"class":609},[599,11772,3717],{"class":666},[599,11774,11775],{"class":601,"line":1321},[599,11776,667],{"class":666},[599,11778,11779,11781],{"class":601,"line":1335},[599,11780,11337],{"class":609},[599,11782,1313],{"class":666},[599,11784,11785,11787,11789,11791,11794,11796],{"class":601,"line":1341},[599,11786,3514],{"class":605},[599,11788,1327],{"class":666},[599,11790,2435],{"class":605},[599,11792,11793],{"class":666},"_remotePassword.",[599,11795,6322],{"class":609},[599,11797,6325],{"class":666},[599,11799,11800,11802,11804,11806,11809,11811,11814,11816,11818,11820,11822],{"class":601,"line":1367},[599,11801,6213],{"class":609},[599,11803,679],{"class":666},[599,11805,694],{"class":605},[599,11807,11808],{"class":666},"_remotePassword[",[599,11810,2074],{"class":949},[599,11812,11813],{"class":666},"], _remotePassword.",[599,11815,2108],{"class":609},[599,11817,2840],{"class":666},[599,11819,748],{"class":605},[599,11821,6453],{"class":605},[599,11823,11824],{"class":666},"(WCHAR));\n",[599,11826,11827,11829],{"class":601,"line":1375},[599,11828,3514],{"class":605},[599,11830,11831],{"class":666}," (_pUserArray)\n",[599,11833,11834,11837,11839],{"class":601,"line":1391},[599,11835,11836],{"class":666},"        _pUserArray->",[599,11838,11027],{"class":609},[599,11840,1313],{"class":666},[599,11842,11843,11846],{"class":601,"line":1405},[599,11844,11845],{"class":609},"    DllRelease",[599,11847,1313],{"class":666},[599,11849,11850],{"class":601,"line":1416},[599,11851,981],{"class":666},[599,11853,11854],{"class":601,"line":1421},[599,11855,651],{"emptyLinePlaceholder":650},[599,11857,11858,11861,11863,11865,11868],{"class":601,"line":1449},[599,11859,11860],{"class":605},"void",[599,11862,10954],{"class":609},[599,11864,688],{"class":666},[599,11866,11867],{"class":609},"_ClearCredentials",[599,11869,3717],{"class":666},[599,11871,11872],{"class":601,"line":1462},[599,11873,667],{"class":666},[599,11875,11876,11878,11880,11882,11884],{"class":601,"line":1477},[599,11877,3407],{"class":605},[599,11879,1327],{"class":666},[599,11881,11423],{"class":609},[599,11883,748],{"class":605},[599,11885,11886],{"class":666}," c : _credentials)\n",[599,11888,11889,11892,11894],{"class":601,"line":1483},[599,11890,11891],{"class":666},"        c->",[599,11893,11027],{"class":609},[599,11895,1313],{"class":666},[599,11897,11898,11901,11903],{"class":601,"line":1496},[599,11899,11900],{"class":666},"    _credentials.",[599,11902,1310],{"class":609},[599,11904,1313],{"class":666},[599,11906,11907,11910,11912,11914],{"class":601,"line":1523},[599,11908,11909],{"class":666},"    _built ",[599,11911,1060],{"class":605},[599,11913,1411],{"class":949},[599,11915,1066],{"class":666},[599,11917,11918,11921,11923],{"class":601,"line":1555},[599,11919,11920],{"class":666},"    _defaultIndex ",[599,11922,1060],{"class":605},[599,11924,11925],{"class":666}," CREDENTIAL_PROVIDER_NO_DEFAULT;\n",[599,11927,11928],{"class":601,"line":1561},[599,11929,981],{"class":666},[599,11931,11932],{"class":601,"line":1567},[599,11933,651],{"emptyLinePlaceholder":650},[599,11935,11936],{"class":601,"line":1577},[599,11937,11938],{"class":772},"\u002F\u002F --- IUnknown ---------------------------------------------------------------\n",[599,11940,11941],{"class":601,"line":1582},[599,11942,651],{"emptyLinePlaceholder":650},[599,11944,11945,11948,11951,11953,11955,11957],{"class":601,"line":1587},[599,11946,11947],{"class":609},"IFACEMETHODIMP_",[599,11949,11950],{"class":666},"(ULONG) ",[599,11952,11677],{"class":609},[599,11954,688],{"class":666},[599,11956,11012],{"class":609},[599,11958,3717],{"class":666},[599,11960,11961],{"class":601,"line":1616},[599,11962,667],{"class":666},[599,11964,11965,11967,11970,11972,11974],{"class":601,"line":1621},[599,11966,3551],{"class":605},[599,11968,11969],{"class":609}," InterlockedIncrement",[599,11971,679],{"class":666},[599,11973,694],{"class":605},[599,11975,11976],{"class":666},"_cRef);\n",[599,11978,11979],{"class":601,"line":1634},[599,11980,981],{"class":666},[599,11982,11983],{"class":601,"line":1647},[599,11984,651],{"emptyLinePlaceholder":650},[599,11986,11987,11989,11991,11993,11995,11997],{"class":601,"line":1660},[599,11988,11947],{"class":609},[599,11990,11950],{"class":666},[599,11992,11677],{"class":609},[599,11994,688],{"class":666},[599,11996,11027],{"class":609},[599,11998,3717],{"class":666},[599,12000,12001],{"class":601,"line":1665},[599,12002,667],{"class":666},[599,12004,12005,12007,12010,12012,12015,12017,12019],{"class":601,"line":1695},[599,12006,11389],{"class":609},[599,12008,12009],{"class":666}," cRef ",[599,12011,1060],{"class":605},[599,12013,12014],{"class":609}," InterlockedDecrement",[599,12016,679],{"class":666},[599,12018,694],{"class":605},[599,12020,11976],{"class":666},[599,12022,12023,12025,12028,12030,12032],{"class":601,"line":1700},[599,12024,3514],{"class":605},[599,12026,12027],{"class":666}," (cRef ",[599,12029,1349],{"class":605},[599,12031,1286],{"class":949},[599,12033,1029],{"class":666},[599,12035,12036,12039,12042],{"class":601,"line":1720},[599,12037,12038],{"class":605},"        delete",[599,12040,12041],{"class":949}," this",[599,12043,1066],{"class":666},[599,12045,12046,12048],{"class":601,"line":1731},[599,12047,3551],{"class":605},[599,12049,12050],{"class":666}," cRef;\n",[599,12052,12053],{"class":601,"line":1745},[599,12054,981],{"class":666},[599,12056,12057],{"class":601,"line":1750},[599,12058,651],{"emptyLinePlaceholder":650},[599,12060,12061,12064,12066,12068,12071,12073,12075,12077,12079,12081,12083],{"class":601,"line":1761},[599,12062,12063],{"class":609},"IFACEMETHODIMP",[599,12065,10954],{"class":609},[599,12067,688],{"class":666},[599,12069,12070],{"class":609},"QueryInterface",[599,12072,679],{"class":666},[599,12074,11042],{"class":609},[599,12076,11045],{"class":697},[599,12078,212],{"class":666},[599,12080,11050],{"class":605},[599,12082,11053],{"class":697},[599,12084,1029],{"class":666},[599,12086,12087],{"class":601,"line":1787},[599,12088,667],{"class":666},[599,12090,12091,12093,12095,12097],{"class":601,"line":1792},[599,12092,3514],{"class":605},[599,12094,1327],{"class":666},[599,12096,2435],{"class":605},[599,12098,12099],{"class":666},"ppv)\n",[599,12101,12102,12104],{"class":601,"line":1815},[599,12103,1211],{"class":605},[599,12105,12106],{"class":666}," E_POINTER;\n",[599,12108,12109,12111,12113,12116,12119,12121,12124,12127,12130],{"class":601,"line":1820},[599,12110,3514],{"class":605},[599,12112,1327],{"class":666},[599,12114,12115],{"class":609},"IsEqualIID",[599,12117,12118],{"class":666},"(riid, IID_IUnknown) ",[599,12120,6568],{"class":605},[599,12122,12123],{"class":609}," IsEqualIID",[599,12125,12126],{"class":666},"(riid, ",[599,12128,12129],{"class":609},"__uuidof",[599,12131,12132],{"class":666},"(ICredentialProvider)))\n",[599,12134,12135],{"class":601,"line":1833},[599,12136,1095],{"class":666},[599,12138,12139,12142,12145,12147,12149,12151,12153,12155,12157],{"class":601,"line":1863},[599,12140,12141],{"class":605},"        *",[599,12143,12144],{"class":666},"ppv ",[599,12146,1060],{"class":605},[599,12148,2374],{"class":605},[599,12150,203],{"class":666},[599,12152,5897],{"class":605},[599,12154,679],{"class":666},[599,12156,8593],{"class":949},[599,12158,725],{"class":666},[599,12160,12161,12164],{"class":601,"line":1870},[599,12162,12163],{"class":609},"        AddRef",[599,12165,1313],{"class":666},[599,12167,12168,12170],{"class":601,"line":1875},[599,12169,1211],{"class":605},[599,12171,12172],{"class":666}," S_OK;\n",[599,12174,12175],{"class":601,"line":1880},[599,12176,1224],{"class":666},[599,12178,12179,12181,12183,12185,12187,12189],{"class":601,"line":1946},[599,12180,3514],{"class":605},[599,12182,1327],{"class":666},[599,12184,12115],{"class":609},[599,12186,12126],{"class":666},[599,12188,12129],{"class":609},[599,12190,12191],{"class":666},"(ICredentialProviderSetUserArray)))\n",[599,12193,12194],{"class":601,"line":1951},[599,12195,1095],{"class":666},[599,12197,12198,12200,12202,12204,12206,12208,12210,12212,12214],{"class":601,"line":1967},[599,12199,12141],{"class":605},[599,12201,12144],{"class":666},[599,12203,1060],{"class":605},[599,12205,2374],{"class":605},[599,12207,253],{"class":666},[599,12209,5897],{"class":605},[599,12211,679],{"class":666},[599,12213,8593],{"class":949},[599,12215,725],{"class":666},[599,12217,12218,12220],{"class":601,"line":1982},[599,12219,12163],{"class":609},[599,12221,1313],{"class":666},[599,12223,12224,12226],{"class":601,"line":1997},[599,12225,1211],{"class":605},[599,12227,12172],{"class":666},[599,12229,12230],{"class":601,"line":2002},[599,12231,1224],{"class":666},[599,12233,12234,12237,12239,12241,12243],{"class":601,"line":2024},[599,12235,12236],{"class":605},"    *",[599,12238,12144],{"class":666},[599,12240,1060],{"class":605},[599,12242,1962],{"class":949},[599,12244,1066],{"class":666},[599,12246,12247,12249],{"class":601,"line":2037},[599,12248,3551],{"class":605},[599,12250,12251],{"class":666}," E_NOINTERFACE;\n",[599,12253,12254],{"class":601,"line":2047},[599,12255,981],{"class":666},[599,12257,12258],{"class":601,"line":2052},[599,12259,651],{"emptyLinePlaceholder":650},[599,12261,12262],{"class":601,"line":2096},[599,12263,12264],{"class":772},"\u002F\u002F --- ICredentialProvider ----------------------------------------------------\n",[599,12266,12267],{"class":601,"line":2124},[599,12268,651],{"emptyLinePlaceholder":650},[599,12270,12271,12273,12275,12277,12279,12281,12283,12285,12287,12289],{"class":601,"line":2129},[599,12272,12063],{"class":609},[599,12274,10954],{"class":609},[599,12276,688],{"class":666},[599,12278,223],{"class":609},[599,12280,679],{"class":666},[599,12282,11076],{"class":609},[599,12284,11079],{"class":697},[599,12286,212],{"class":666},[599,12288,5878],{"class":609},[599,12290,1029],{"class":666},[599,12292,12293],{"class":601,"line":2163},[599,12294,667],{"class":666},[599,12296,12297,12300],{"class":601,"line":2186},[599,12298,12299],{"class":605},"    switch",[599,12301,12302],{"class":666}," (cpus)\n",[599,12304,12305],{"class":601,"line":2195},[599,12306,1095],{"class":666},[599,12308,12309,12312],{"class":601,"line":2200},[599,12310,12311],{"class":605},"    case",[599,12313,12314],{"class":666}," CPUS_LOGON:\n",[599,12316,12317,12319],{"class":601,"line":2212},[599,12318,12311],{"class":605},[599,12320,12321],{"class":666}," CPUS_UNLOCK_WORKSTATION:\n",[599,12323,12324,12327,12329],{"class":601,"line":2220},[599,12325,12326],{"class":666},"        _cpus ",[599,12328,1060],{"class":605},[599,12330,12331],{"class":666}," cpus;\n",[599,12333,12334,12336],{"class":601,"line":2225},[599,12335,1211],{"class":605},[599,12337,12172],{"class":666},[599,12339,12340],{"class":601,"line":2230},[599,12341,651],{"emptyLinePlaceholder":650},[599,12343,12344],{"class":601,"line":2265},[599,12345,12346],{"class":772},"    \u002F\u002F We take part in logon and unlock only. Declining the rest cleanly is\n",[599,12348,12349],{"class":601,"line":2286},[599,12350,12351],{"class":772},"    \u002F\u002F important: misbehaving in CPUS_CREDUI would break UAC prompts.\n",[599,12353,12354,12356],{"class":601,"line":2291},[599,12355,12311],{"class":605},[599,12357,12358],{"class":666}," CPUS_CHANGE_PASSWORD:\n",[599,12360,12361,12363],{"class":601,"line":2297},[599,12362,12311],{"class":605},[599,12364,12365],{"class":666}," CPUS_CREDUI:\n",[599,12367,12368,12370],{"class":601,"line":2317},[599,12369,12311],{"class":605},[599,12371,12372],{"class":666}," CPUS_PLAP:\n",[599,12374,12375,12377],{"class":601,"line":2331},[599,12376,1211],{"class":605},[599,12378,12379],{"class":666}," E_NOTIMPL;\n",[599,12381,12382],{"class":601,"line":2361},[599,12383,651],{"emptyLinePlaceholder":650},[599,12385,12386,12389],{"class":601,"line":2366},[599,12387,12388],{"class":605},"    default",[599,12390,3457],{"class":666},[599,12392,12393,12395],{"class":601,"line":2393},[599,12394,1211],{"class":605},[599,12396,12397],{"class":666}," E_INVALIDARG;\n",[599,12399,12400],{"class":601,"line":2406},[599,12401,1224],{"class":666},[599,12403,12404],{"class":601,"line":2411},[599,12405,981],{"class":666},[599,12407,12408],{"class":601,"line":2416},[599,12409,651],{"emptyLinePlaceholder":650},[599,12411,12412],{"class":601,"line":2428},[599,12413,12414],{"class":772},"\u002F\u002F A qualified name is local when the part before the backslash is this computer.\n",[599,12416,12417],{"class":601,"line":2450},[599,12418,12419],{"class":772},"\u002F\u002F \"CONTOSO\\alice\" or \"MicrosoftAccount\\...\" are not, and get no tile: the secret\n",[599,12421,12422],{"class":601,"line":2459},[599,12423,12424],{"class":772},"\u002F\u002F is stored per bare name and this demo authenticates only against the local SAM.\n",[599,12426,12427,12429,12431,12434,12436,12438,12441],{"class":601,"line":2464},[599,12428,8856],{"class":605},[599,12430,1885],{"class":605},[599,12432,12433],{"class":609}," IsLocalAccount",[599,12435,679],{"class":666},[599,12437,11361],{"class":609},[599,12439,12440],{"class":697}," qualified",[599,12442,1029],{"class":666},[599,12444,12445],{"class":601,"line":2470},[599,12446,667],{"class":666},[599,12448,12449,12452,12454,12457,12459,12461,12463,12466,12469,12471,12473,12475,12477,12479,12481],{"class":601,"line":2476},[599,12450,12451],{"class":605},"    const",[599,12453,6785],{"class":605},[599,12455,12456],{"class":666}," slash ",[599,12458,1060],{"class":605},[599,12460,6410],{"class":666},[599,12462,9412],{"class":605},[599,12464,12465],{"class":609}," wcschr",[599,12467,12468],{"class":666},"(qualified, ",[599,12470,5720],{"class":619},[599,12472,5576],{"class":949},[599,12474,5725],{"class":619},[599,12476,1124],{"class":666},[599,12478,590],{"class":605},[599,12480,1962],{"class":949},[599,12482,1066],{"class":666},[599,12484,12485,12487,12489,12491],{"class":601,"line":2503},[599,12486,3514],{"class":605},[599,12488,1327],{"class":666},[599,12490,2435],{"class":605},[599,12492,12493],{"class":666},"slash)\n",[599,12495,12496,12498,12500],{"class":601,"line":2537},[599,12497,1211],{"class":605},[599,12499,1411],{"class":949},[599,12501,1066],{"class":666},[599,12503,12504],{"class":601,"line":2569},[599,12505,651],{"emptyLinePlaceholder":650},[599,12507,12508,12511,12513,12515,12517,12519],{"class":601,"line":2600},[599,12509,12510],{"class":666},"    WCHAR computer[MAX_COMPUTERNAME_LENGTH ",[599,12512,2543],{"class":605},[599,12514,973],{"class":949},[599,12516,2491],{"class":666},[599,12518,1060],{"class":605},[599,12520,5921],{"class":666},[599,12522,12523,12525,12527,12529,12531],{"class":601,"line":2623},[599,12524,11440],{"class":609},[599,12526,6360],{"class":666},[599,12528,1060],{"class":605},[599,12530,6365],{"class":609},[599,12532,6368],{"class":666},[599,12534,12535,12537,12539,12541,12543,12545,12547],{"class":601,"line":2628},[599,12536,3514],{"class":605},[599,12538,1327],{"class":666},[599,12540,2435],{"class":605},[599,12542,6379],{"class":609},[599,12544,6382],{"class":666},[599,12546,694],{"class":605},[599,12548,6387],{"class":666},[599,12550,12551,12553,12555],{"class":601,"line":2642},[599,12552,1211],{"class":605},[599,12554,1411],{"class":949},[599,12556,1066],{"class":666},[599,12558,12559],{"class":601,"line":2668},[599,12560,651],{"emptyLinePlaceholder":650},[599,12562,12563,12566,12569,12571,12573,12576,12578],{"class":601,"line":2682},[599,12564,12565],{"class":605},"    size_t",[599,12567,12568],{"class":666}," domainLen ",[599,12570,1060],{"class":605},[599,12572,2845],{"class":605},[599,12574,12575],{"class":666},"(slash ",[599,12577,1132],{"class":605},[599,12579,12580],{"class":666}," qualified);\n",[599,12582,12583,12585,12587,12589,12591,12593,12596,12599,12601,12603],{"class":601,"line":2698},[599,12584,3551],{"class":605},[599,12586,12568],{"class":666},[599,12588,1349],{"class":605},[599,12590,6360],{"class":666},[599,12592,3154],{"class":605},[599,12594,12595],{"class":609}," _wcsnicmp",[599,12597,12598],{"class":666},"(qualified, computer, domainLen) ",[599,12600,1349],{"class":605},[599,12602,1286],{"class":949},[599,12604,1066],{"class":666},[599,12606,12607],{"class":601,"line":2707},[599,12608,981],{"class":666},[599,12610,12611],{"class":601,"line":2712},[599,12612,651],{"emptyLinePlaceholder":650},[599,12614,12615,12618,12620,12622,12625,12627,12629,12631,12633,12635,12637,12639,12641,12643],{"class":601,"line":2717},[599,12616,12617],{"class":609},"HRESULT",[599,12619,10954],{"class":609},[599,12621,688],{"class":666},[599,12623,12624],{"class":609},"_AddCredential",[599,12626,679],{"class":666},[599,12628,11361],{"class":609},[599,12630,11364],{"class":697},[599,12632,212],{"class":666},[599,12634,11361],{"class":609},[599,12636,11371],{"class":697},[599,12638,212],{"class":666},[599,12640,11361],{"class":609},[599,12642,11378],{"class":697},[599,12644,1029],{"class":666},[599,12646,12647],{"class":601,"line":2760},[599,12648,667],{"class":666},[599,12650,12651,12654,12656,12659,12661,12664,12666,12668,12671,12673],{"class":601,"line":2781},[599,12652,12653],{"class":609},"    CTacCredential",[599,12655,748],{"class":605},[599,12657,12658],{"class":666}," cred ",[599,12660,1060],{"class":605},[599,12662,12663],{"class":605}," new",[599,12665,1327],{"class":666},[599,12667,703],{"class":609},[599,12669,12670],{"class":666},"::nothrow) ",[599,12672,11423],{"class":609},[599,12674,1313],{"class":666},[599,12676,12677,12679,12681,12683],{"class":601,"line":2802},[599,12678,3514],{"class":605},[599,12680,1327],{"class":666},[599,12682,2435],{"class":605},[599,12684,12685],{"class":666},"cred)\n",[599,12687,12688,12690],{"class":601,"line":2807},[599,12689,1211],{"class":605},[599,12691,12692],{"class":666}," E_OUTOFMEMORY;\n",[599,12694,12695],{"class":601,"line":2819},[599,12696,651],{"emptyLinePlaceholder":650},[599,12698,12699,12701,12704,12706,12709,12712],{"class":601,"line":2824},[599,12700,11344],{"class":609},[599,12702,12703],{"class":666}," hr ",[599,12705,1060],{"class":605},[599,12707,12708],{"class":666}," cred->",[599,12710,12711],{"class":609},"Initialize",[599,12713,12714],{"class":666},"(_cpus, s_rgFieldDescriptors, s_rgFieldStatePairs,\n",[599,12716,12717],{"class":601,"line":2830},[599,12718,12719],{"class":666},"                                  pwzUser, pwzPassword, pwzSid);\n",[599,12721,12722,12724,12726,12729],{"class":601,"line":2851},[599,12723,3514],{"class":605},[599,12725,1327],{"class":666},[599,12727,12728],{"class":609},"FAILED",[599,12730,12731],{"class":666},"(hr))\n",[599,12733,12734],{"class":601,"line":2860},[599,12735,1095],{"class":666},[599,12737,12738,12741,12743],{"class":601,"line":2874},[599,12739,12740],{"class":666},"        cred->",[599,12742,11027],{"class":609},[599,12744,1313],{"class":666},[599,12746,12747,12749],{"class":601,"line":2887},[599,12748,1211],{"class":605},[599,12750,12751],{"class":666}," hr;\n",[599,12753,12754],{"class":601,"line":2892},[599,12755,1224],{"class":666},[599,12757,12758],{"class":601,"line":2915},[599,12759,651],{"emptyLinePlaceholder":650},[599,12761,12762,12764,12766],{"class":601,"line":2924},[599,12763,11900],{"class":666},[599,12765,1502],{"class":609},[599,12767,12768],{"class":666},"(cred);\n",[599,12770,12771,12773],{"class":601,"line":2951},[599,12772,3551],{"class":605},[599,12774,12172],{"class":666},[599,12776,12777],{"class":601,"line":2956},[599,12778,981],{"class":666},[599,12780,12781],{"class":601,"line":2961},[599,12782,651],{"emptyLinePlaceholder":650},[599,12784,12785,12787,12789,12791,12794],{"class":601,"line":2982},[599,12786,12617],{"class":609},[599,12788,10954],{"class":609},[599,12790,688],{"class":666},[599,12792,12793],{"class":609},"_CreateCredentials",[599,12795,3717],{"class":666},[599,12797,12798],{"class":601,"line":3011},[599,12799,667],{"class":666},[599,12801,12802,12804],{"class":601,"line":3016},[599,12803,3514],{"class":605},[599,12805,12806],{"class":666}," (_built)\n",[599,12808,12809,12811],{"class":601,"line":3044},[599,12810,1211],{"class":605},[599,12812,12172],{"class":666},[599,12814,12815,12817],{"class":601,"line":3051},[599,12816,11337],{"class":609},[599,12818,1313],{"class":666},[599,12820,12821],{"class":601,"line":3073},[599,12822,651],{"emptyLinePlaceholder":650},[599,12824,12825],{"class":601,"line":3078},[599,12826,12827],{"class":772},"    \u002F\u002F RDP path: one tile, pre-filled with the forwarded name and password.\n",[599,12829,12830,12832],{"class":601,"line":3084},[599,12831,3514],{"class":605},[599,12833,12834],{"class":666}," (_haveRemote)\n",[599,12836,12837],{"class":601,"line":3090},[599,12838,1095],{"class":666},[599,12840,12841,12843,12845,12848,12850,12852,12855,12857,12860,12862,12864,12866],{"class":601,"line":3096},[599,12842,1100],{"class":605},[599,12844,1327],{"class":666},[599,12846,12847],{"class":609},"SUCCEEDED",[599,12849,679],{"class":666},[599,12851,12624],{"class":609},[599,12853,12854],{"class":666},"(_remoteUser.",[599,12856,6513],{"class":609},[599,12858,12859],{"class":666},"(), _remotePassword.",[599,12861,6513],{"class":609},[599,12863,7241],{"class":666},[599,12865,2019],{"class":949},[599,12867,12868],{"class":666},")))\n",[599,12870,12871,12874,12876,12878],{"class":601,"line":3109},[599,12872,12873],{"class":666},"            _defaultIndex ",[599,12875,1060],{"class":605},[599,12877,1286],{"class":949},[599,12879,1066],{"class":666},[599,12881,12882],{"class":601,"line":3116},[599,12883,651],{"emptyLinePlaceholder":650},[599,12885,12886],{"class":601,"line":3121},[599,12887,12888],{"class":772},"        \u002F\u002F The tile has its own copy now, so drop ours.\n",[599,12890,12891,12893,12895,12897,12899,12901],{"class":601,"line":3136},[599,12892,1100],{"class":605},[599,12894,1327],{"class":666},[599,12896,2435],{"class":605},[599,12898,11793],{"class":666},[599,12900,6322],{"class":609},[599,12902,6325],{"class":666},[599,12904,12905],{"class":601,"line":3164},[599,12906,1338],{"class":666},[599,12908,12909,12912,12914,12916,12918,12920,12922,12924,12926,12928,12930],{"class":601,"line":3169},[599,12910,12911],{"class":609},"            SecureZeroMemory",[599,12913,679],{"class":666},[599,12915,694],{"class":605},[599,12917,11808],{"class":666},[599,12919,2074],{"class":949},[599,12921,11813],{"class":666},[599,12923,2108],{"class":609},[599,12925,2840],{"class":666},[599,12927,748],{"class":605},[599,12929,6453],{"class":605},[599,12931,11824],{"class":666},[599,12933,12934,12937,12939],{"class":601,"line":3180},[599,12935,12936],{"class":666},"            _remotePassword.",[599,12938,1310],{"class":609},[599,12940,1313],{"class":666},[599,12942,12943],{"class":601,"line":3189},[599,12944,1564],{"class":666},[599,12946,12947,12950,12952,12954],{"class":601,"line":3194},[599,12948,12949],{"class":666},"        _built ",[599,12951,1060],{"class":605},[599,12953,1572],{"class":949},[599,12955,1066],{"class":666},[599,12957,12958,12960],{"class":601,"line":3199},[599,12959,1211],{"class":605},[599,12961,12172],{"class":666},[599,12963,12964],{"class":601,"line":3208},[599,12965,1224],{"class":666},[599,12967,12968],{"class":601,"line":3213},[599,12969,651],{"emptyLinePlaceholder":650},[599,12971,12972,12974,12977,12979,12981],{"class":601,"line":7367},[599,12973,11440],{"class":609},[599,12975,12976],{"class":666}," count ",[599,12978,1060],{"class":605},[599,12980,1286],{"class":949},[599,12982,1066],{"class":666},[599,12984,12985,12987],{"class":601,"line":7376},[599,12986,3514],{"class":605},[599,12988,11831],{"class":666},[599,12990,12991,12993,12996,12998,13000],{"class":601,"line":7381},[599,12992,11836],{"class":666},[599,12994,12995],{"class":609},"GetCount",[599,12997,679],{"class":666},[599,12999,694],{"class":605},[599,13001,13002],{"class":666},"count);\n",[599,13004,13005],{"class":601,"line":7394},[599,13006,651],{"emptyLinePlaceholder":650},[599,13008,13009,13011,13014,13016,13018,13020,13022,13025,13027],{"class":601,"line":7421},[599,13010,3407],{"class":605},[599,13012,13013],{"class":666}," (DWORD i ",[599,13015,1060],{"class":605},[599,13017,1286],{"class":949},[599,13019,1681],{"class":666},[599,13021,711],{"class":605},[599,13023,13024],{"class":666}," count; ",[599,13026,1689],{"class":605},[599,13028,1692],{"class":666},[599,13030,13031],{"class":601,"line":7430},[599,13032,1095],{"class":666},[599,13034,13035,13038,13040,13042,13044,13046],{"class":601,"line":7435},[599,13036,13037],{"class":609},"        ICredentialProviderUser",[599,13039,748],{"class":605},[599,13041,9683],{"class":666},[599,13043,1060],{"class":605},[599,13045,1962],{"class":949},[599,13047,1066],{"class":666},[599,13049,13050,13052,13054,13056,13059,13062,13065,13067,13070,13072,13074],{"class":601,"line":7449},[599,13051,1100],{"class":605},[599,13053,1327],{"class":666},[599,13055,12728],{"class":609},[599,13057,13058],{"class":666},"(_pUserArray->",[599,13060,13061],{"class":609},"GetAt",[599,13063,13064],{"class":666},"(i, ",[599,13066,694],{"class":605},[599,13068,13069],{"class":666},"user)) ",[599,13071,6568],{"class":605},[599,13073,9609],{"class":605},[599,13075,13076],{"class":666},"user)\n",[599,13078,13079,13082],{"class":601,"line":7463},[599,13080,13081],{"class":605},"            continue",[599,13083,1066],{"class":666},[599,13085,13086],{"class":601,"line":7478},[599,13087,651],{"emptyLinePlaceholder":650},[599,13089,13090,13092,13094,13096,13098],{"class":601,"line":7514},[599,13091,6597],{"class":609},[599,13093,6410],{"class":666},[599,13095,1060],{"class":605},[599,13097,1962],{"class":949},[599,13099,1066],{"class":666},[599,13101,13102,13104,13107,13109,13111],{"class":601,"line":7544},[599,13103,6597],{"class":609},[599,13105,13106],{"class":666}," sid       ",[599,13108,1060],{"class":605},[599,13110,1962],{"class":949},[599,13112,1066],{"class":666},[599,13114,13115,13118,13121,13124,13126],{"class":601,"line":7549},[599,13116,13117],{"class":666},"        user->",[599,13119,13120],{"class":609},"GetStringValue",[599,13122,13123],{"class":666},"(PKEY_QualifiedUserName, ",[599,13125,694],{"class":605},[599,13127,13128],{"class":666},"qualified);\n",[599,13130,13131,13133,13136,13138,13140],{"class":601,"line":7561},[599,13132,13117],{"class":666},[599,13134,13135],{"class":609},"GetSid",[599,13137,679],{"class":666},[599,13139,694],{"class":605},[599,13141,13142],{"class":666},"sid);\n",[599,13144,13145],{"class":601,"line":7593},[599,13146,651],{"emptyLinePlaceholder":650},[599,13148,13149,13151,13154,13156,13159,13161,13163],{"class":601,"line":7598},[599,13150,1100],{"class":605},[599,13152,13153],{"class":666}," (qualified ",[599,13155,3154],{"class":605},[599,13157,13158],{"class":666}," sid ",[599,13160,3154],{"class":605},[599,13162,12433],{"class":609},[599,13164,13165],{"class":666},"(qualified))\n",[599,13167,13168,13171,13173,13176],{"class":601,"line":7606},[599,13169,13170],{"class":609},"            _AddCredential",[599,13172,12468],{"class":666},[599,13174,13175],{"class":619},"L\"\"",[599,13177,13178],{"class":666},", sid);\n",[599,13180,13181],{"class":601,"line":7626},[599,13182,651],{"emptyLinePlaceholder":650},[599,13184,13185,13188],{"class":601,"line":7635},[599,13186,13187],{"class":609},"        CoTaskMemFree",[599,13189,13190],{"class":666},"(qualified);\n",[599,13192,13193,13195],{"class":601,"line":7640},[599,13194,13187],{"class":609},[599,13196,13197],{"class":666},"(sid);\n",[599,13199,13200,13202,13204],{"class":601,"line":7652},[599,13201,13117],{"class":666},[599,13203,11027],{"class":609},[599,13205,1313],{"class":666},[599,13207,13208],{"class":601,"line":7667},[599,13209,1224],{"class":666},[599,13211,13212],{"class":601,"line":7676},[599,13213,651],{"emptyLinePlaceholder":650},[599,13215,13216],{"class":601,"line":7681},[599,13217,13218],{"class":772},"    \u002F\u002F If no local user tile was created (for example when Windows does not list\n",[599,13220,13221],{"class":601,"line":7695},[599,13222,13223],{"class":772},"    \u002F\u002F local users), add one generic tile with a username field. Without it the\n",[599,13225,13226],{"class":601,"line":7716},[599,13227,13228],{"class":772},"    \u002F\u002F filter could leave nobody a way to log on.\n",[599,13230,13231,13233,13236,13238],{"class":601,"line":7721},[599,13232,3514],{"class":605},[599,13234,13235],{"class":666}," (_credentials.",[599,13237,6322],{"class":609},[599,13239,6325],{"class":666},[599,13241,13242,13245,13247,13249,13251,13253,13255,13257],{"class":601,"line":7727},[599,13243,13244],{"class":609},"        _AddCredential",[599,13246,679],{"class":666},[599,13248,13175],{"class":619},[599,13250,212],{"class":666},[599,13252,13175],{"class":619},[599,13254,212],{"class":666},[599,13256,2019],{"class":949},[599,13258,725],{"class":666},[599,13260,13261],{"class":601,"line":7733},[599,13262,651],{"emptyLinePlaceholder":650},[599,13264,13265,13267,13269,13271],{"class":601,"line":7760},[599,13266,11909],{"class":666},[599,13268,1060],{"class":605},[599,13270,1572],{"class":949},[599,13272,1066],{"class":666},[599,13274,13275,13277],{"class":601,"line":7765},[599,13276,3551],{"class":605},[599,13278,12172],{"class":666},[599,13280,13281],{"class":601,"line":7781},[599,13282,981],{"class":666},[599,13284,13285],{"class":601,"line":7798},[599,13286,651],{"emptyLinePlaceholder":650},[599,13288,13289],{"class":601,"line":7808},[599,13290,13291],{"class":772},"\u002F\u002F RDP with NLA forwards the credential over CredSSP before any tile is drawn.\n",[599,13293,13294],{"class":601,"line":7817},[599,13295,13296],{"class":772},"\u002F\u002F We unpack it and remember the name and password to pre-fill the tile.\n",[599,13298,13299,13301,13303,13305,13308],{"class":601,"line":7822},[599,13300,12063],{"class":609},[599,13302,10954],{"class":609},[599,13304,688],{"class":666},[599,13306,13307],{"class":609},"SetSerialization",[599,13309,13310],{"class":666},"(\n",[599,13312,13313,13315,13317,13319,13321],{"class":601,"line":7831},[599,13314,12451],{"class":605},[599,13316,11102],{"class":609},[599,13318,748],{"class":605},[599,13320,11107],{"class":697},[599,13322,1029],{"class":666},[599,13324,13325],{"class":601,"line":7836},[599,13326,667],{"class":666},[599,13328,13329,13331,13333,13335,13338,13340,13342,13345],{"class":601,"line":7841},[599,13330,3514],{"class":605},[599,13332,1327],{"class":666},[599,13334,2435],{"class":605},[599,13336,13337],{"class":666},"pcpcs ",[599,13339,6568],{"class":605},[599,13341,9609],{"class":605},[599,13343,13344],{"class":666},"pcpcs->rgbSerialization ",[599,13346,13347],{"class":605},"||\n",[599,13349,13350,13353,13355,13357],{"class":601,"line":7872},[599,13351,13352],{"class":666},"        pcpcs->cbSerialization ",[599,13354,711],{"class":605},[599,13356,6453],{"class":605},[599,13358,13359],{"class":666},"(KERB_INTERACTIVE_UNLOCK_LOGON))\n",[599,13361,13362,13364],{"class":601,"line":7877},[599,13363,1211],{"class":605},[599,13365,12379],{"class":666},[599,13367,13368,13370,13372,13374,13377],{"class":601,"line":7895},[599,13369,3514],{"class":605},[599,13371,1327],{"class":666},[599,13373,2435],{"class":605},[599,13375,13376],{"class":609},"IsEqualCLSID",[599,13378,13379],{"class":666},"(pcpcs->clsidCredentialProvider, CLSID_CTacProvider))\n",[599,13381,13382,13384,13387],{"class":601,"line":7908},[599,13383,1211],{"class":605},[599,13385,13386],{"class":666}," E_NOTIMPL;",[599,13388,13389],{"class":772},"   \u002F\u002F not addressed to us\n",[599,13391,13392],{"class":601,"line":7917},[599,13393,651],{"emptyLinePlaceholder":650},[599,13395,13396],{"class":601,"line":7922},[599,13397,13398],{"class":772},"    \u002F\u002F Work on our own copy, because unpacking rewrites the offsets to pointers.\n",[599,13400,13401,13404,13406,13409],{"class":601,"line":7935},[599,13402,13403],{"class":609},"    KERB_INTERACTIVE_UNLOCK_LOGON",[599,13405,748],{"class":605},[599,13407,13408],{"class":666}," pkiul ",[599,13410,10667],{"class":605},[599,13412,13413,13416,13419,13421,13423,13426],{"class":601,"line":7958},[599,13414,13415],{"class":605},"        static_cast\u003C",[599,13417,13418],{"class":666},"KERB_INTERACTIVE_UNLOCK_LOGON",[599,13420,5897],{"class":605},[599,13422,679],{"class":666},[599,13424,13425],{"class":609},"CoTaskMemAlloc",[599,13427,13428],{"class":666},"(pcpcs->cbSerialization));\n",[599,13430,13431,13433,13435,13437],{"class":601,"line":7970},[599,13432,3514],{"class":605},[599,13434,1327],{"class":666},[599,13436,2435],{"class":605},[599,13438,13439],{"class":666},"pkiul)\n",[599,13441,13442,13444],{"class":601,"line":7982},[599,13443,1211],{"class":605},[599,13445,12692],{"class":666},[599,13447,13448,13451],{"class":601,"line":7993},[599,13449,13450],{"class":609},"    CopyMemory",[599,13452,13453],{"class":666},"(pkiul, pcpcs->rgbSerialization, pcpcs->cbSerialization);\n",[599,13455,13456],{"class":601,"line":8002},[599,13457,651],{"emptyLinePlaceholder":650},[599,13459,13460],{"class":601,"line":8007},[599,13461,13462],{"class":772},"    \u002F\u002F RDP can also forward other logon types, a smartcard logon for example.\n",[599,13464,13465],{"class":601,"line":8020},[599,13466,13467],{"class":772},"    \u002F\u002F Only a password logon has the layout we unpack below.\n",[599,13469,13470,13472,13474,13476],{"class":601,"line":8034},[599,13471,11344],{"class":609},[599,13473,12703],{"class":666},[599,13475,1060],{"class":605},[599,13477,12172],{"class":666},[599,13479,13480,13482,13485,13487,13490],{"class":601,"line":8059},[599,13481,3514],{"class":605},[599,13483,13484],{"class":666}," (pkiul->Logon.MessageType ",[599,13486,2030],{"class":605},[599,13488,13489],{"class":666}," KerbInteractiveLogon ",[599,13491,13492],{"class":605},"&&\n",[599,13494,13495,13498,13500],{"class":601,"line":8080},[599,13496,13497],{"class":666},"        pkiul->Logon.MessageType ",[599,13499,2030],{"class":605},[599,13501,13502],{"class":666}," KerbWorkstationUnlockLogon)\n",[599,13504,13505,13508,13510],{"class":601,"line":8087},[599,13506,13507],{"class":666},"        hr ",[599,13509,1060],{"class":605},[599,13511,12379],{"class":666},[599,13513,13514],{"class":601,"line":8092},[599,13515,651],{"emptyLinePlaceholder":650},[599,13517,13518,13520,13522,13524],{"class":601,"line":8103},[599,13519,3514],{"class":605},[599,13521,1327],{"class":666},[599,13523,12847],{"class":609},[599,13525,12731],{"class":666},[599,13527,13528,13530,13532,13535],{"class":601,"line":8108},[599,13529,13507],{"class":666},[599,13531,1060],{"class":605},[599,13533,13534],{"class":609}," KerbInteractiveUnlockLogonUnpackInPlace",[599,13536,13537],{"class":666},"(pkiul, pcpcs->cbSerialization);\n",[599,13539,13540,13542,13544,13546],{"class":601,"line":8124},[599,13541,3514],{"class":605},[599,13543,1327],{"class":666},[599,13545,12847],{"class":609},[599,13547,12731],{"class":666},[599,13549,13550],{"class":601,"line":8136},[599,13551,1095],{"class":666},[599,13553,13554,13556,13559,13561,13564,13566],{"class":601,"line":8141},[599,13555,2964],{"class":605},[599,13557,13558],{"class":609}," KERB_INTERACTIVE_LOGON",[599,13560,694],{"class":605},[599,13562,13563],{"class":666}," kil ",[599,13565,1060],{"class":605},[599,13567,13568],{"class":666}," pkiul->Logon;\n",[599,13570,13571],{"class":601,"line":8147},[599,13572,651],{"emptyLinePlaceholder":650},[599,13574,13575],{"class":601,"line":8153},[599,13576,13577],{"class":772},"        \u002F\u002F A UNICODE_STRING is counted, not null-terminated, and Buffer can be\n",[599,13579,13580],{"class":601,"line":8182},[599,13581,13582],{"class":772},"        \u002F\u002F null (empty domain), which std::wstring must not be built from.\n",[599,13584,13585,13588,13591,13593,13596,13598,13601,13603,13606,13609,13612],{"class":601,"line":8187},[599,13586,13587],{"class":605},"        auto",[599,13589,13590],{"class":666}," toString ",[599,13592,1060],{"class":605},[599,13594,13595],{"class":666}," [](",[599,13597,682],{"class":605},[599,13599,13600],{"class":609}," UNICODE_STRING",[599,13602,694],{"class":605},[599,13604,13605],{"class":697}," us",[599,13607,13608],{"class":666},") -> ",[599,13610,13611],{"class":605},"std::wstring",[599,13613,4734],{"class":666},[599,13615,13616,13618,13620,13622,13625,13627,13630,13632,13634],{"class":601,"line":8192},[599,13617,1344],{"class":605},[599,13619,1327],{"class":666},[599,13621,2435],{"class":605},[599,13623,13624],{"class":666},"us.Buffer ",[599,13626,6568],{"class":605},[599,13628,13629],{"class":666}," us.Length ",[599,13631,1349],{"class":605},[599,13633,1286],{"class":949},[599,13635,1029],{"class":666},[599,13637,13638,13640,13642,13644,13646],{"class":601,"line":8225},[599,13639,1408],{"class":605},[599,13641,685],{"class":609},[599,13643,688],{"class":666},[599,13645,902],{"class":609},[599,13647,1313],{"class":666},[599,13649,13650,13652,13654,13656,13658,13661,13663,13665],{"class":601,"line":8230},[599,13651,2040],{"class":605},[599,13653,685],{"class":609},[599,13655,688],{"class":666},[599,13657,902],{"class":609},[599,13659,13660],{"class":666},"(us.Buffer, us.Length ",[599,13662,2311],{"class":605},[599,13664,6453],{"class":605},[599,13666,11824],{"class":666},[599,13668,13669],{"class":601,"line":8243},[599,13670,13671],{"class":666},"        };\n",[599,13673,13674],{"class":601,"line":8252},[599,13675,651],{"emptyLinePlaceholder":650},[599,13677,13678,13680,13682,13684,13687,13689,13692],{"class":601,"line":8257},[599,13679,1624],{"class":609},[599,13681,688],{"class":666},[599,13683,902],{"class":609},[599,13685,13686],{"class":666}," domain ",[599,13688,1060],{"class":605},[599,13690,13691],{"class":609}," toString",[599,13693,13694],{"class":666},"(kil.LogonDomainName);\n",[599,13696,13697,13699,13701,13703,13706,13708,13710],{"class":601,"line":8270},[599,13698,1624],{"class":609},[599,13700,688],{"class":666},[599,13702,902],{"class":609},[599,13704,13705],{"class":666}," user   ",[599,13707,1060],{"class":605},[599,13709,13691],{"class":609},[599,13711,13712],{"class":666},"(kil.UserName);\n",[599,13714,13715,13717,13719,13721,13724,13726,13728],{"class":601,"line":8288},[599,13716,1624],{"class":609},[599,13718,688],{"class":666},[599,13720,902],{"class":609},[599,13722,13723],{"class":666}," pass   ",[599,13725,1060],{"class":605},[599,13727,13691],{"class":609},[599,13729,13730],{"class":666},"(kil.Password);\n",[599,13732,13733],{"class":601,"line":8299},[599,13734,651],{"emptyLinePlaceholder":650},[599,13736,13737,13739,13741,13743,13745,13747],{"class":601,"line":8304},[599,13738,1100],{"class":605},[599,13740,1327],{"class":666},[599,13742,2435],{"class":605},[599,13744,11793],{"class":666},[599,13746,6322],{"class":609},[599,13748,6325],{"class":666},[599,13750,13751,13753,13755,13757,13759,13761,13763,13765,13767,13769,13771],{"class":601,"line":8323},[599,13752,12911],{"class":609},[599,13754,679],{"class":666},[599,13756,694],{"class":605},[599,13758,11808],{"class":666},[599,13760,2074],{"class":949},[599,13762,11813],{"class":666},[599,13764,2108],{"class":609},[599,13766,2840],{"class":666},[599,13768,748],{"class":605},[599,13770,6453],{"class":605},[599,13772,11824],{"class":666},[599,13774,13775],{"class":601,"line":8343},[599,13776,651],{"emptyLinePlaceholder":650},[599,13778,13779,13782,13784,13787,13789,13791,13793,13795,13797,13800,13802,13804,13806,13808,13810],{"class":601,"line":8355},[599,13780,13781],{"class":666},"        _remoteUser     ",[599,13783,1060],{"class":605},[599,13785,13786],{"class":666}," domain.",[599,13788,6322],{"class":609},[599,13790,2840],{"class":666},[599,13792,9412],{"class":605},[599,13794,9683],{"class":666},[599,13796,590],{"class":605},[599,13798,13799],{"class":666}," (domain ",[599,13801,2543],{"class":605},[599,13803,6426],{"class":619},[599,13805,5576],{"class":949},[599,13807,4362],{"class":619},[599,13809,1201],{"class":605},[599,13811,13812],{"class":666}," user);\n",[599,13814,13815,13818,13820],{"class":601,"line":8362},[599,13816,13817],{"class":666},"        _remotePassword ",[599,13819,1060],{"class":605},[599,13821,13822],{"class":666}," pass;\n",[599,13824,13825,13828,13830,13832],{"class":601,"line":8367},[599,13826,13827],{"class":666},"        _haveRemote     ",[599,13829,1060],{"class":605},[599,13831,1572],{"class":949},[599,13833,1066],{"class":666},[599,13835,13836,13839,13841,13843],{"class":601,"line":8378},[599,13837,13838],{"class":666},"        _built          ",[599,13840,1060],{"class":605},[599,13842,1411],{"class":949},[599,13844,1066],{"class":666},[599,13846,13847],{"class":601,"line":8383},[599,13848,651],{"emptyLinePlaceholder":650},[599,13850,13851,13853,13855,13857,13860,13862],{"class":601,"line":8388},[599,13852,1100],{"class":605},[599,13854,1327],{"class":666},[599,13856,2435],{"class":605},[599,13858,13859],{"class":666},"pass.",[599,13861,6322],{"class":609},[599,13863,6325],{"class":666},[599,13865,13866,13868,13870,13872,13875,13877,13880,13882,13884,13886,13888],{"class":601,"line":8411},[599,13867,12911],{"class":609},[599,13869,679],{"class":666},[599,13871,694],{"class":605},[599,13873,13874],{"class":666},"pass[",[599,13876,2074],{"class":949},[599,13878,13879],{"class":666},"], pass.",[599,13881,2108],{"class":609},[599,13883,2840],{"class":666},[599,13885,748],{"class":605},[599,13887,6453],{"class":605},[599,13889,11824],{"class":666},[599,13891,13892],{"class":601,"line":8416},[599,13893,1224],{"class":666},[599,13895,13896],{"class":601,"line":8429},[599,13897,651],{"emptyLinePlaceholder":650},[599,13899,13900,13902],{"class":601,"line":8438},[599,13901,10068],{"class":609},[599,13903,13537],{"class":666},[599,13905,13906,13909],{"class":601,"line":8443},[599,13907,13908],{"class":609},"    CoTaskMemFree",[599,13910,13911],{"class":666},"(pkiul);\n",[599,13913,13914,13916],{"class":601,"line":8456},[599,13915,3551],{"class":605},[599,13917,12751],{"class":666},[599,13919,13920],{"class":601,"line":8478},[599,13921,981],{"class":666},[599,13923,13924],{"class":601,"line":8489},[599,13925,651],{"emptyLinePlaceholder":650},[599,13927,13928,13930,13932,13934,13937,13939,13941,13943,13945,13947,13950,13952],{"class":601,"line":8498},[599,13929,12063],{"class":609},[599,13931,10954],{"class":609},[599,13933,688],{"class":666},[599,13935,13936],{"class":609},"Advise",[599,13938,679],{"class":666},[599,13940,11121],{"class":609},[599,13942,748],{"class":605},[599,13944,212],{"class":666},[599,13946,11131],{"class":609},[599,13948,13949],{"class":666},") { ",[599,13951,1127],{"class":605},[599,13953,13954],{"class":666}," S_OK; }\n",[599,13956,13957,13959,13961,13963,13966,13969,13971],{"class":601,"line":8509},[599,13958,12063],{"class":609},[599,13960,10954],{"class":609},[599,13962,688],{"class":666},[599,13964,13965],{"class":609},"UnAdvise",[599,13967,13968],{"class":666},"() { ",[599,13970,1127],{"class":605},[599,13972,13954],{"class":666},[599,13974,13975],{"class":601,"line":8518},[599,13976,651],{"emptyLinePlaceholder":650},[599,13978,13979,13981,13983,13985,13987,13989,13991,13993,13995],{"class":601,"line":8523},[599,13980,12063],{"class":609},[599,13982,10954],{"class":609},[599,13984,688],{"class":666},[599,13986,211],{"class":609},[599,13988,679],{"class":666},[599,13990,5878],{"class":609},[599,13992,748],{"class":605},[599,13994,11161],{"class":697},[599,13996,1029],{"class":666},[599,13998,13999],{"class":601,"line":8539},[599,14000,667],{"class":666},[599,14002,14003,14005,14008,14010],{"class":601,"line":8546},[599,14004,12236],{"class":605},[599,14006,14007],{"class":666},"pdwCount ",[599,14009,1060],{"class":605},[599,14011,14012],{"class":666}," TFI_NUM_FIELDS;\n",[599,14014,14015,14017],{"class":601,"line":8566},[599,14016,3551],{"class":605},[599,14018,12172],{"class":666},[599,14020,14021],{"class":601,"line":8571},[599,14022,981],{"class":666},[599,14024,14026],{"class":601,"line":14025},259,[599,14027,651],{"emptyLinePlaceholder":650},[599,14029,14031,14033,14035,14037,14039,14041,14043,14045],{"class":601,"line":14030},260,[599,14032,12063],{"class":609},[599,14034,10954],{"class":609},[599,14036,688],{"class":666},[599,14038,215],{"class":609},[599,14040,679],{"class":666},[599,14042,5878],{"class":609},[599,14044,11177],{"class":697},[599,14046,813],{"class":666},[599,14048,14050,14053,14055,14057],{"class":601,"line":14049},261,[599,14051,14052],{"class":609},"                                                  CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR",[599,14054,4056],{"class":605},[599,14056,11187],{"class":697},[599,14058,1029],{"class":666},[599,14060,14062],{"class":601,"line":14061},262,[599,14063,667],{"class":666},[599,14065,14067,14069,14072,14074,14077,14079,14081],{"class":601,"line":14066},263,[599,14068,3514],{"class":605},[599,14070,14071],{"class":666}," (dwIndex ",[599,14073,1106],{"class":605},[599,14075,14076],{"class":666}," TFI_NUM_FIELDS ",[599,14078,6568],{"class":605},[599,14080,9609],{"class":605},[599,14082,14083],{"class":666},"ppcpfd)\n",[599,14085,14087,14089],{"class":601,"line":14086},264,[599,14088,1211],{"class":605},[599,14090,12397],{"class":666},[599,14092,14094,14096,14099],{"class":601,"line":14093},265,[599,14095,3551],{"class":605},[599,14097,14098],{"class":609}," FieldDescriptorCoAllocCopy",[599,14100,14101],{"class":666},"(s_rgFieldDescriptors[dwIndex], ppcpfd);\n",[599,14103,14105],{"class":601,"line":14104},266,[599,14106,981],{"class":666},[599,14108,14110],{"class":601,"line":14109},267,[599,14111,651],{"emptyLinePlaceholder":650},[599,14113,14115,14117,14119,14121,14123,14125,14127,14129,14131,14133,14135,14137,14139],{"class":601,"line":14114},268,[599,14116,12063],{"class":609},[599,14118,10954],{"class":609},[599,14120,688],{"class":666},[599,14122,207],{"class":609},[599,14124,679],{"class":666},[599,14126,5878],{"class":609},[599,14128,748],{"class":605},[599,14130,11161],{"class":697},[599,14132,212],{"class":666},[599,14134,5878],{"class":609},[599,14136,748],{"class":605},[599,14138,11213],{"class":697},[599,14140,813],{"class":666},[599,14142,14144,14147,14149,14151],{"class":601,"line":14143},269,[599,14145,14146],{"class":609},"                                                BOOL",[599,14148,748],{"class":605},[599,14150,11223],{"class":697},[599,14152,1029],{"class":666},[599,14154,14156],{"class":601,"line":14155},270,[599,14157,667],{"class":666},[599,14159,14161,14164],{"class":601,"line":14160},271,[599,14162,14163],{"class":609},"    _CreateCredentials",[599,14165,1313],{"class":666},[599,14167,14169,14171,14173,14175,14177,14179,14181,14184,14186],{"class":601,"line":14168},272,[599,14170,12236],{"class":605},[599,14172,14007],{"class":666},[599,14174,1060],{"class":605},[599,14176,2374],{"class":605},[599,14178,5878],{"class":666},[599,14180,717],{"class":605},[599,14182,14183],{"class":666},"(_credentials.",[599,14185,2108],{"class":609},[599,14187,6864],{"class":666},[599,14189,14191,14193,14196,14198],{"class":601,"line":14190},273,[599,14192,12236],{"class":605},[599,14194,14195],{"class":666},"pdwDefault ",[599,14197,1060],{"class":605},[599,14199,14200],{"class":666}," _defaultIndex;\n",[599,14202,14204,14206,14209,14211],{"class":601,"line":14203},274,[599,14205,12236],{"class":605},[599,14207,14208],{"class":666},"pbAutoLogonWithDefault ",[599,14210,1060],{"class":605},[599,14212,14213],{"class":666}," FALSE;\n",[599,14215,14217,14219],{"class":601,"line":14216},275,[599,14218,3551],{"class":605},[599,14220,12172],{"class":666},[599,14222,14224],{"class":601,"line":14223},276,[599,14225,981],{"class":666},[599,14227,14229],{"class":601,"line":14228},277,[599,14230,651],{"emptyLinePlaceholder":650},[599,14232,14234,14236,14238,14240,14242,14244,14246,14248],{"class":601,"line":14233},278,[599,14235,12063],{"class":609},[599,14237,10954],{"class":609},[599,14239,688],{"class":666},[599,14241,219],{"class":609},[599,14243,679],{"class":666},[599,14245,5878],{"class":609},[599,14247,11177],{"class":697},[599,14249,813],{"class":666},[599,14251,14253,14256,14258,14260],{"class":601,"line":14252},279,[599,14254,14255],{"class":609},"                                             ICredentialProviderCredential",[599,14257,4056],{"class":605},[599,14259,11247],{"class":697},[599,14261,1029],{"class":666},[599,14263,14265],{"class":601,"line":14264},280,[599,14266,667],{"class":666},[599,14268,14270,14272,14274,14276],{"class":601,"line":14269},281,[599,14271,3514],{"class":605},[599,14273,1327],{"class":666},[599,14275,2435],{"class":605},[599,14277,14278],{"class":666},"ppcpc)\n",[599,14280,14282,14284],{"class":601,"line":14281},282,[599,14283,1211],{"class":605},[599,14285,12397],{"class":666},[599,14287,14289,14291],{"class":601,"line":14288},283,[599,14290,14163],{"class":609},[599,14292,1313],{"class":666},[599,14294,14296,14298,14300,14302,14305,14307],{"class":601,"line":14295},284,[599,14297,3514],{"class":605},[599,14299,14071],{"class":666},[599,14301,1106],{"class":605},[599,14303,14304],{"class":666}," _credentials.",[599,14306,2108],{"class":609},[599,14308,6325],{"class":666},[599,14310,14312,14314],{"class":601,"line":14311},285,[599,14313,1211],{"class":605},[599,14315,12397],{"class":666},[599,14317,14319,14321,14324,14326,14328,14331],{"class":601,"line":14318},286,[599,14320,3551],{"class":605},[599,14322,14323],{"class":666}," _credentials[dwIndex]->",[599,14325,12070],{"class":609},[599,14327,679],{"class":666},[599,14329,14330],{"class":609},"IID_PPV_ARGS",[599,14332,14333],{"class":666},"(ppcpc));\n",[599,14335,14337],{"class":601,"line":14336},287,[599,14338,981],{"class":666},[599,14340,14342],{"class":601,"line":14341},288,[599,14343,651],{"emptyLinePlaceholder":650},[599,14345,14347],{"class":601,"line":14346},289,[599,14348,14349],{"class":772},"\u002F\u002F --- ICredentialProviderSetUserArray ----------------------------------------\n",[599,14351,14353],{"class":601,"line":14352},290,[599,14354,651],{"emptyLinePlaceholder":650},[599,14356,14358,14360,14362,14364,14366,14368,14370,14372,14374],{"class":601,"line":14357},291,[599,14359,12063],{"class":609},[599,14361,10954],{"class":609},[599,14363,688],{"class":666},[599,14365,257],{"class":609},[599,14367,679],{"class":666},[599,14369,11270],{"class":609},[599,14371,748],{"class":605},[599,14373,11275],{"class":697},[599,14375,1029],{"class":666},[599,14377,14379],{"class":601,"line":14378},292,[599,14380,667],{"class":666},[599,14382,14384,14386],{"class":601,"line":14383},293,[599,14385,3514],{"class":605},[599,14387,11831],{"class":666},[599,14389,14391,14393,14395],{"class":601,"line":14390},294,[599,14392,11836],{"class":666},[599,14394,11027],{"class":609},[599,14396,1313],{"class":666},[599,14398,14400,14403,14405],{"class":601,"line":14399},295,[599,14401,14402],{"class":666},"    _pUserArray ",[599,14404,1060],{"class":605},[599,14406,14407],{"class":666}," users;\n",[599,14409,14411,14413],{"class":601,"line":14410},296,[599,14412,3514],{"class":605},[599,14414,11831],{"class":666},[599,14416,14418,14420,14422],{"class":601,"line":14417},297,[599,14419,11836],{"class":666},[599,14421,11012],{"class":609},[599,14423,1313],{"class":666},[599,14425,14427,14429,14431,14433],{"class":601,"line":14426},298,[599,14428,11909],{"class":666},[599,14430,1060],{"class":605},[599,14432,1411],{"class":949},[599,14434,1066],{"class":666},[599,14436,14438,14440],{"class":601,"line":14437},299,[599,14439,3551],{"class":605},[599,14441,12172],{"class":666},[599,14443,14445],{"class":601,"line":14444},300,[599,14446,981],{"class":666},[599,14448,14450],{"class":601,"line":14449},301,[599,14451,651],{"emptyLinePlaceholder":650},[599,14453,14455,14457,14459,14461,14463,14465,14467,14469,14471],{"class":601,"line":14454},302,[599,14456,12617],{"class":609},[599,14458,11292],{"class":609},[599,14460,679],{"class":666},[599,14462,11042],{"class":609},[599,14464,11045],{"class":697},[599,14466,212],{"class":666},[599,14468,11050],{"class":605},[599,14470,11053],{"class":697},[599,14472,1029],{"class":666},[599,14474,14476],{"class":601,"line":14475},303,[599,14477,667],{"class":666},[599,14479,14481,14483,14485,14488,14490,14492,14494,14496,14498,14500],{"class":601,"line":14480},304,[599,14482,10987],{"class":609},[599,14484,748],{"class":605},[599,14486,14487],{"class":666}," provider ",[599,14489,1060],{"class":605},[599,14491,12663],{"class":605},[599,14493,1327],{"class":666},[599,14495,703],{"class":609},[599,14497,12670],{"class":666},[599,14499,11677],{"class":609},[599,14501,1313],{"class":666},[599,14503,14505,14507,14509,14511],{"class":601,"line":14504},305,[599,14506,3514],{"class":605},[599,14508,1327],{"class":666},[599,14510,2435],{"class":605},[599,14512,14513],{"class":666},"provider)\n",[599,14515,14517,14519],{"class":601,"line":14516},306,[599,14518,1211],{"class":605},[599,14520,12692],{"class":666},[599,14522,14524,14526,14528,14530,14533,14535],{"class":601,"line":14523},307,[599,14525,11344],{"class":609},[599,14527,12703],{"class":666},[599,14529,1060],{"class":605},[599,14531,14532],{"class":666}," provider->",[599,14534,12070],{"class":609},[599,14536,14537],{"class":666},"(riid, ppv);\n",[599,14539,14541,14544,14546],{"class":601,"line":14540},308,[599,14542,14543],{"class":666},"    provider->",[599,14545,11027],{"class":609},[599,14547,1313],{"class":666},[599,14549,14551,14553],{"class":601,"line":14550},309,[599,14552,3551],{"class":605},[599,14554,12751],{"class":666},[599,14556,14558],{"class":601,"line":14557},310,[599,14559,981],{"class":666},[15,14561,14562],{},"The provider creates one tile per local user. So the logon screen looks like the normal one from Windows. This is how it works:",[172,14564,14565,14571,14584],{},[59,14566,14567,14568,14570],{},"LogonUI calls ",[69,14569,257],{}," and gives us the list of users.",[59,14572,14573,14574,8721,14576,101,14578,14580,14581,262],{},"When LogonUI asks for the tiles (",[69,14575,207],{},[69,14577,219],{},[69,14579,12793],{}," goes through this list. For every user it reads the name (",[69,14582,14583],{},"PC\\alice",[59,14585,14586,14587,14589,14590,14592],{},"For every local account it creates a ",[69,14588,11423],{}," with this name and SID. The tile returns the SID in ",[69,14591,247],{},". This one function makes Windows show the name and the round profile picture.",[15,14594,14595,14596,14598,14599,14602,14603,14606,14607,14610],{},"Only local accounts get a tile. You can see the type of account in the name: ",[69,14597,14583],{}," is local, ",[69,14600,14601],{},"CONTOSO\\alice"," is a domain account and ",[69,14604,14605],{},"MicrosoftAccount\\alice@..."," is a Microsoft account. ",[69,14608,14609],{},"IsLocalAccount"," checks if the part before the backslash is the computer name. All other accounts are skipped, because the secret is saved per username and the demo only logs on against the local SAM.",[15,14612,14613],{},"There is one special case. On some machines, mostly domain joined ones, Windows doesn't give us any local users. Then there would be no tile at all, and with the filter nobody could log in. That's why the provider creates one tile with a username field in this case.",[15,14615,14616],{},"This is also why the tile has a username field. On a normal user tile it is hidden, because the name comes from the account. On the fallback tile it is visible. The RDP tile uses it too.",[15,14618,14619,14620,14622],{},"Why user tiles at all? My first version had a single tile with a username field and its own picture. It worked, but the picture was always square, not round like on Windows 11. So I made the bitmap round myself with transparent corners. Result: black corners. LogonUI just ignores transparency on a tile that is not bound to a user, and Windows only rounds the pictures of real user tiles. The solution was to bind the tile to a user with ",[69,14621,247],{},". Windows now draws the real account picture, round, and you don't have to type your username anymore.",[15,14624,14625,14626,14629,14630,14633,14634,14637,14638,14641],{},"About ",[69,14627,14628],{},"PKEY_QualifiedUserName",": this is a ",[69,14631,14632],{},"PROPERTYKEY"," from the Windows property system. I didn't want to link ",[69,14635,14636],{},"propsys"," just for one value, so I define it directly in the code. The values are from the Microsoft documentation (formatID ",[69,14639,14640],{},"DA520E51-...",", propID 100).",[15,14643,14644,14646],{},[69,14645,13307],{}," is for RDP. With Network Level Authentication the RDP client sends the credentials before a tile is shown. LogonUI passes them to this function.",[15,14648,14649,14650,14653],{},"First I check the ",[69,14651,14652],{},"MessageType",". RDP can also send other logon types, for example a smartcard logon. Only a password logon has the structure I unpack here. Then the name and password are saved and the provider creates a tile where both are already filled in. The code field stays empty, so the code is still required.",[15,14655,14656,14657,14660,14661,14664,14665,14668,14669,14671],{},"The ",[69,14658,14659],{},"toString"," lambda is there for a reason. A ",[69,14662,14663],{},"UNICODE_STRING"," has a length and is not terminated with a zero. If the domain is empty, the ",[69,14666,14667],{},"Buffer"," can be a null pointer. Creating a ",[69,14670,13611],{}," from a null pointer is undefined behavior. You would never see this bug in your own tests, only on someone else's machine.",[126,14673,14675],{"id":14674},"the-tile-and-the-code-check","The tile and the code check",[15,14677,14678,590],{},[69,14679,14680],{},"CTacCredential.h",[148,14682,14684],{"className":593,"code":14683,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccredentialprovider.h>\n#include \"common.h\"\n\n\u002F\u002F One tile. ICredentialProviderCredential2 adds GetUserSid, which binds the\n\u002F\u002F tile to an account. That is what makes Windows show the account's name and\n\u002F\u002F its round picture, like on the built-in tiles.\nclass CTacCredential : public ICredentialProviderCredential2\n{\npublic:\n    CTacCredential();\n\n    HRESULT Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,\n                       const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd,\n                       const FIELD_STATE_PAIR* rgfsp,\n                       PCWSTR pwzUser, PCWSTR pwzPassword, PCWSTR pwzSid);\n\n    \u002F\u002F IUnknown\n    IFACEMETHODIMP_(ULONG) AddRef();\n    IFACEMETHODIMP_(ULONG) Release();\n    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);\n\n    \u002F\u002F ICredentialProviderCredential\n    IFACEMETHODIMP Advise(ICredentialProviderCredentialEvents* pcpce);\n    IFACEMETHODIMP UnAdvise();\n    IFACEMETHODIMP SetSelected(BOOL* pbAutoLogon);\n    IFACEMETHODIMP SetDeselected();\n    IFACEMETHODIMP GetFieldState(DWORD dwFieldID,\n                                 CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs,\n                                 CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis);\n    IFACEMETHODIMP GetStringValue(DWORD dwFieldID, PWSTR* ppwsz);\n    IFACEMETHODIMP GetBitmapValue(DWORD dwFieldID, HBITMAP* phbmp);\n    IFACEMETHODIMP GetCheckboxValue(DWORD dwFieldID, BOOL* pbChecked, PWSTR* ppwszLabel);\n    IFACEMETHODIMP GetSubmitButtonValue(DWORD dwFieldID, DWORD* pdwAdjacentTo);\n    IFACEMETHODIMP GetComboBoxValueCount(DWORD dwFieldID, DWORD* pcItems, DWORD* pdwSelectedItem);\n    IFACEMETHODIMP GetComboBoxValueAt(DWORD dwFieldID, DWORD dwItem, PWSTR* ppwszItem);\n    IFACEMETHODIMP SetStringValue(DWORD dwFieldID, PCWSTR pwz);\n    IFACEMETHODIMP SetCheckboxValue(DWORD dwFieldID, BOOL bChecked);\n    IFACEMETHODIMP SetComboBoxSelectedValue(DWORD dwFieldID, DWORD dwSelectedItem);\n    IFACEMETHODIMP CommandLinkClicked(DWORD dwFieldID);\n    IFACEMETHODIMP GetSerialization(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,\n                                    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,\n                                    PWSTR* ppwszOptionalStatusText,\n                                    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon);\n    IFACEMETHODIMP ReportResult(NTSTATUS ntsStatus, NTSTATUS ntsSubstatus,\n                                PWSTR* ppwszOptionalStatusText,\n                                CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon);\n\n    \u002F\u002F ICredentialProviderCredential2\n    IFACEMETHODIMP GetUserSid(PWSTR* ppszSid);\n\nprivate:\n    virtual ~CTacCredential();\n\n    void _FreeField(DWORD dwFieldID);\n    void _ResetField(DWORD dwFieldID);\n\n    LONG                                 _cRef;\n    CREDENTIAL_PROVIDER_USAGE_SCENARIO   _cpus;\n    CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR _rgFieldDescriptors[TFI_NUM_FIELDS];\n    FIELD_STATE_PAIR                     _rgFieldStatePairs[TFI_NUM_FIELDS];\n    PWSTR                                _rgFieldStrings[TFI_NUM_FIELDS];\n    PWSTR                                _pszSid;   \u002F\u002F null on the fallback and RDP tile\n    ICredentialProviderCredentialEvents* _pCredProvCredentialEvents;\n};\n",[69,14685,14686,14692,14698,14704,14710,14714,14719,14724,14729,14743,14747,14751,14757,14761,14776,14790,14803,14824,14828,14832,14846,14860,14880,14884,14889,14907,14915,14933,14942,14958,14970,14982,15006,15031,15064,15088,15121,15152,15174,15196,15218,15233,15252,15263,15275,15287,15311,15322,15333,15337,15342,15360,15364,15368,15377,15381,15396,15411,15415,15422,15429,15437,15445,15453,15463,15473],{"__ignoreMap":154},[599,14687,14688,14690],{"class":601,"line":602},[599,14689,606],{"class":605},[599,14691,610],{"class":609},[599,14693,14694,14696],{"class":601,"line":613},[599,14695,616],{"class":605},[599,14697,620],{"class":619},[599,14699,14700,14702],{"class":601,"line":623},[599,14701,616],{"class":605},[599,14703,10483],{"class":619},[599,14705,14706,14708],{"class":601,"line":631},[599,14707,616],{"class":605},[599,14709,11516],{"class":619},[599,14711,14712],{"class":601,"line":639},[599,14713,651],{"emptyLinePlaceholder":650},[599,14715,14716],{"class":601,"line":647},[599,14717,14718],{"class":772},"\u002F\u002F One tile. ICredentialProviderCredential2 adds GetUserSid, which binds the\n",[599,14720,14721],{"class":601,"line":654},[599,14722,14723],{"class":772},"\u002F\u002F tile to an account. That is what makes Windows show the account's name and\n",[599,14725,14726],{"class":601,"line":663},[599,14727,14728],{"class":772},"\u002F\u002F its round picture, like on the built-in tiles.\n",[599,14730,14731,14733,14736,14738,14740],{"class":601,"line":670},[599,14732,10951],{"class":605},[599,14734,14735],{"class":609}," CTacCredential",[599,14737,10957],{"class":666},[599,14739,10960],{"class":605},[599,14741,14742],{"class":609}," ICredentialProviderCredential2\n",[599,14744,14745],{"class":601,"line":728},[599,14746,667],{"class":666},[599,14748,14749],{"class":601,"line":764},[599,14750,10982],{"class":605},[599,14752,14753,14755],{"class":601,"line":769},[599,14754,12653],{"class":609},[599,14756,1313],{"class":666},[599,14758,14759],{"class":601,"line":776},[599,14760,651],{"emptyLinePlaceholder":650},[599,14762,14763,14765,14768,14770,14772,14774],{"class":601,"line":816},[599,14764,11344],{"class":609},[599,14766,14767],{"class":609}," Initialize",[599,14769,679],{"class":666},[599,14771,11076],{"class":609},[599,14773,11079],{"class":697},[599,14775,813],{"class":666},[599,14777,14778,14781,14783,14785,14788],{"class":601,"line":843},[599,14779,14780],{"class":605},"                       const",[599,14782,10661],{"class":609},[599,14784,748],{"class":605},[599,14786,14787],{"class":697}," rgcpfd",[599,14789,813],{"class":666},[599,14791,14792,14794,14796,14798,14801],{"class":601,"line":848},[599,14793,14780],{"class":605},[599,14795,10810],{"class":609},[599,14797,748],{"class":605},[599,14799,14800],{"class":697}," rgfsp",[599,14802,813],{"class":666},[599,14804,14805,14808,14810,14812,14814,14816,14818,14820,14822],{"class":601,"line":854},[599,14806,14807],{"class":609},"                       PCWSTR",[599,14809,11364],{"class":697},[599,14811,212],{"class":666},[599,14813,11361],{"class":609},[599,14815,11371],{"class":697},[599,14817,212],{"class":666},[599,14819,11361],{"class":609},[599,14821,11378],{"class":697},[599,14823,725],{"class":666},[599,14825,14826],{"class":601,"line":860},[599,14827,651],{"emptyLinePlaceholder":650},[599,14829,14830],{"class":601,"line":866},[599,14831,10998],{"class":772},[599,14833,14834,14836,14838,14840,14842,14844],{"class":601,"line":912},[599,14835,11003],{"class":609},[599,14837,679],{"class":666},[599,14839,1924],{"class":609},[599,14841,1124],{"class":666},[599,14843,11012],{"class":609},[599,14845,1313],{"class":666},[599,14847,14848,14850,14852,14854,14856,14858],{"class":601,"line":938},[599,14849,11003],{"class":609},[599,14851,679],{"class":666},[599,14853,1924],{"class":609},[599,14855,1124],{"class":666},[599,14857,11027],{"class":609},[599,14859,1313],{"class":666},[599,14861,14862,14864,14866,14868,14870,14872,14874,14876,14878],{"class":601,"line":978},[599,14863,11034],{"class":609},[599,14865,11037],{"class":609},[599,14867,679],{"class":666},[599,14869,11042],{"class":609},[599,14871,11045],{"class":697},[599,14873,212],{"class":666},[599,14875,11050],{"class":605},[599,14877,11053],{"class":697},[599,14879,725],{"class":666},[599,14881,14882],{"class":601,"line":1316},[599,14883,651],{"emptyLinePlaceholder":650},[599,14885,14886],{"class":601,"line":1321},[599,14887,14888],{"class":772},"    \u002F\u002F ICredentialProviderCredential\n",[599,14890,14891,14893,14895,14897,14900,14902,14905],{"class":601,"line":1335},[599,14892,11034],{"class":609},[599,14894,11116],{"class":609},[599,14896,679],{"class":666},[599,14898,14899],{"class":609},"ICredentialProviderCredentialEvents",[599,14901,748],{"class":605},[599,14903,14904],{"class":697}," pcpce",[599,14906,725],{"class":666},[599,14908,14909,14911,14913],{"class":601,"line":1341},[599,14910,11034],{"class":609},[599,14912,11143],{"class":609},[599,14914,1313],{"class":666},[599,14916,14917,14919,14922,14924,14926,14928,14931],{"class":601,"line":1367},[599,14918,11034],{"class":609},[599,14920,14921],{"class":609}," SetSelected",[599,14923,679],{"class":666},[599,14925,11218],{"class":609},[599,14927,748],{"class":605},[599,14929,14930],{"class":697}," pbAutoLogon",[599,14932,725],{"class":666},[599,14934,14935,14937,14940],{"class":601,"line":1375},[599,14936,11034],{"class":609},[599,14938,14939],{"class":609}," SetDeselected",[599,14941,1313],{"class":666},[599,14943,14944,14946,14949,14951,14953,14956],{"class":601,"line":1391},[599,14945,11034],{"class":609},[599,14947,14948],{"class":609}," GetFieldState",[599,14950,679],{"class":666},[599,14952,5878],{"class":609},[599,14954,14955],{"class":697}," dwFieldID",[599,14957,813],{"class":666},[599,14959,14960,14963,14965,14968],{"class":601,"line":1405},[599,14961,14962],{"class":609},"                                 CREDENTIAL_PROVIDER_FIELD_STATE",[599,14964,748],{"class":605},[599,14966,14967],{"class":697}," pcpfs",[599,14969,813],{"class":666},[599,14971,14972,14975,14977,14980],{"class":601,"line":1416},[599,14973,14974],{"class":609},"                                 CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE",[599,14976,748],{"class":605},[599,14978,14979],{"class":697}," pcpfis",[599,14981,725],{"class":666},[599,14983,14984,14986,14989,14991,14993,14995,14997,14999,15001,15004],{"class":601,"line":1421},[599,14985,11034],{"class":609},[599,14987,14988],{"class":609}," GetStringValue",[599,14990,679],{"class":666},[599,14992,5878],{"class":609},[599,14994,14955],{"class":697},[599,14996,212],{"class":666},[599,14998,10681],{"class":609},[599,15000,748],{"class":605},[599,15002,15003],{"class":697}," ppwsz",[599,15005,725],{"class":666},[599,15007,15008,15010,15013,15015,15017,15019,15021,15024,15026,15029],{"class":601,"line":1449},[599,15009,11034],{"class":609},[599,15011,15012],{"class":609}," GetBitmapValue",[599,15014,679],{"class":666},[599,15016,5878],{"class":609},[599,15018,14955],{"class":697},[599,15020,212],{"class":666},[599,15022,15023],{"class":609},"HBITMAP",[599,15025,748],{"class":605},[599,15027,15028],{"class":697}," phbmp",[599,15030,725],{"class":666},[599,15032,15033,15035,15038,15040,15042,15044,15046,15048,15050,15053,15055,15057,15059,15062],{"class":601,"line":1462},[599,15034,11034],{"class":609},[599,15036,15037],{"class":609}," GetCheckboxValue",[599,15039,679],{"class":666},[599,15041,5878],{"class":609},[599,15043,14955],{"class":697},[599,15045,212],{"class":666},[599,15047,11218],{"class":609},[599,15049,748],{"class":605},[599,15051,15052],{"class":697}," pbChecked",[599,15054,212],{"class":666},[599,15056,10681],{"class":609},[599,15058,748],{"class":605},[599,15060,15061],{"class":697}," ppwszLabel",[599,15063,725],{"class":666},[599,15065,15066,15068,15071,15073,15075,15077,15079,15081,15083,15086],{"class":601,"line":1477},[599,15067,11034],{"class":609},[599,15069,15070],{"class":609}," GetSubmitButtonValue",[599,15072,679],{"class":666},[599,15074,5878],{"class":609},[599,15076,14955],{"class":697},[599,15078,212],{"class":666},[599,15080,5878],{"class":609},[599,15082,748],{"class":605},[599,15084,15085],{"class":697}," pdwAdjacentTo",[599,15087,725],{"class":666},[599,15089,15090,15092,15095,15097,15099,15101,15103,15105,15107,15110,15112,15114,15116,15119],{"class":601,"line":1483},[599,15091,11034],{"class":609},[599,15093,15094],{"class":609}," GetComboBoxValueCount",[599,15096,679],{"class":666},[599,15098,5878],{"class":609},[599,15100,14955],{"class":697},[599,15102,212],{"class":666},[599,15104,5878],{"class":609},[599,15106,748],{"class":605},[599,15108,15109],{"class":697}," pcItems",[599,15111,212],{"class":666},[599,15113,5878],{"class":609},[599,15115,748],{"class":605},[599,15117,15118],{"class":697}," pdwSelectedItem",[599,15120,725],{"class":666},[599,15122,15123,15125,15128,15130,15132,15134,15136,15138,15141,15143,15145,15147,15150],{"class":601,"line":1496},[599,15124,11034],{"class":609},[599,15126,15127],{"class":609}," GetComboBoxValueAt",[599,15129,679],{"class":666},[599,15131,5878],{"class":609},[599,15133,14955],{"class":697},[599,15135,212],{"class":666},[599,15137,5878],{"class":609},[599,15139,15140],{"class":697}," dwItem",[599,15142,212],{"class":666},[599,15144,10681],{"class":609},[599,15146,748],{"class":605},[599,15148,15149],{"class":697}," ppwszItem",[599,15151,725],{"class":666},[599,15153,15154,15156,15159,15161,15163,15165,15167,15169,15172],{"class":601,"line":1523},[599,15155,11034],{"class":609},[599,15157,15158],{"class":609}," SetStringValue",[599,15160,679],{"class":666},[599,15162,5878],{"class":609},[599,15164,14955],{"class":697},[599,15166,212],{"class":666},[599,15168,11361],{"class":609},[599,15170,15171],{"class":697}," pwz",[599,15173,725],{"class":666},[599,15175,15176,15178,15181,15183,15185,15187,15189,15191,15194],{"class":601,"line":1555},[599,15177,11034],{"class":609},[599,15179,15180],{"class":609}," SetCheckboxValue",[599,15182,679],{"class":666},[599,15184,5878],{"class":609},[599,15186,14955],{"class":697},[599,15188,212],{"class":666},[599,15190,11218],{"class":609},[599,15192,15193],{"class":697}," bChecked",[599,15195,725],{"class":666},[599,15197,15198,15200,15203,15205,15207,15209,15211,15213,15216],{"class":601,"line":1561},[599,15199,11034],{"class":609},[599,15201,15202],{"class":609}," SetComboBoxSelectedValue",[599,15204,679],{"class":666},[599,15206,5878],{"class":609},[599,15208,14955],{"class":697},[599,15210,212],{"class":666},[599,15212,5878],{"class":609},[599,15214,15215],{"class":697}," dwSelectedItem",[599,15217,725],{"class":666},[599,15219,15220,15222,15225,15227,15229,15231],{"class":601,"line":1567},[599,15221,11034],{"class":609},[599,15223,15224],{"class":609}," CommandLinkClicked",[599,15226,679],{"class":666},[599,15228,5878],{"class":609},[599,15230,14955],{"class":697},[599,15232,725],{"class":666},[599,15234,15235,15237,15240,15242,15245,15247,15250],{"class":601,"line":1577},[599,15236,11034],{"class":609},[599,15238,15239],{"class":609}," GetSerialization",[599,15241,679],{"class":666},[599,15243,15244],{"class":609},"CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE",[599,15246,748],{"class":605},[599,15248,15249],{"class":697}," pcpgsr",[599,15251,813],{"class":666},[599,15253,15254,15257,15259,15261],{"class":601,"line":1582},[599,15255,15256],{"class":609},"                                    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION",[599,15258,748],{"class":605},[599,15260,11107],{"class":697},[599,15262,813],{"class":666},[599,15264,15265,15268,15270,15273],{"class":601,"line":1587},[599,15266,15267],{"class":609},"                                    PWSTR",[599,15269,748],{"class":605},[599,15271,15272],{"class":697}," ppwszOptionalStatusText",[599,15274,813],{"class":666},[599,15276,15277,15280,15282,15285],{"class":601,"line":1616},[599,15278,15279],{"class":609},"                                    CREDENTIAL_PROVIDER_STATUS_ICON",[599,15281,748],{"class":605},[599,15283,15284],{"class":697}," pcpsiOptionalStatusIcon",[599,15286,725],{"class":666},[599,15288,15289,15291,15294,15296,15299,15302,15304,15306,15309],{"class":601,"line":1621},[599,15290,11034],{"class":609},[599,15292,15293],{"class":609}," ReportResult",[599,15295,679],{"class":666},[599,15297,15298],{"class":609},"NTSTATUS",[599,15300,15301],{"class":697}," ntsStatus",[599,15303,212],{"class":666},[599,15305,15298],{"class":609},[599,15307,15308],{"class":697}," ntsSubstatus",[599,15310,813],{"class":666},[599,15312,15313,15316,15318,15320],{"class":601,"line":1634},[599,15314,15315],{"class":609},"                                PWSTR",[599,15317,748],{"class":605},[599,15319,15272],{"class":697},[599,15321,813],{"class":666},[599,15323,15324,15327,15329,15331],{"class":601,"line":1647},[599,15325,15326],{"class":609},"                                CREDENTIAL_PROVIDER_STATUS_ICON",[599,15328,748],{"class":605},[599,15330,15284],{"class":697},[599,15332,725],{"class":666},[599,15334,15335],{"class":601,"line":1660},[599,15336,651],{"emptyLinePlaceholder":650},[599,15338,15339],{"class":601,"line":1665},[599,15340,15341],{"class":772},"    \u002F\u002F ICredentialProviderCredential2\n",[599,15343,15344,15346,15349,15351,15353,15355,15358],{"class":601,"line":1695},[599,15345,11034],{"class":609},[599,15347,15348],{"class":609}," GetUserSid",[599,15350,679],{"class":666},[599,15352,10681],{"class":609},[599,15354,748],{"class":605},[599,15356,15357],{"class":697}," ppszSid",[599,15359,725],{"class":666},[599,15361,15362],{"class":601,"line":1700},[599,15363,651],{"emptyLinePlaceholder":650},[599,15365,15366],{"class":601,"line":1720},[599,15367,11315],{"class":605},[599,15369,15370,15372,15375],{"class":601,"line":1731},[599,15371,11320],{"class":605},[599,15373,15374],{"class":609}," ~CTacCredential",[599,15376,1313],{"class":666},[599,15378,15379],{"class":601,"line":1745},[599,15380,651],{"emptyLinePlaceholder":650},[599,15382,15383,15385,15388,15390,15392,15394],{"class":601,"line":1750},[599,15384,11334],{"class":605},[599,15386,15387],{"class":609}," _FreeField",[599,15389,679],{"class":666},[599,15391,5878],{"class":609},[599,15393,14955],{"class":697},[599,15395,725],{"class":666},[599,15397,15398,15400,15403,15405,15407,15409],{"class":601,"line":1761},[599,15399,11334],{"class":605},[599,15401,15402],{"class":609}," _ResetField",[599,15404,679],{"class":666},[599,15406,5878],{"class":609},[599,15408,14955],{"class":697},[599,15410,725],{"class":666},[599,15412,15413],{"class":601,"line":1787},[599,15414,651],{"emptyLinePlaceholder":650},[599,15416,15417,15419],{"class":601,"line":1792},[599,15418,11389],{"class":609},[599,15420,15421],{"class":666},"                                 _cRef;\n",[599,15423,15424,15426],{"class":601,"line":1815},[599,15425,11397],{"class":609},[599,15427,15428],{"class":666},"   _cpus;\n",[599,15430,15431,15434],{"class":601,"line":1820},[599,15432,15433],{"class":609},"    CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR",[599,15435,15436],{"class":666}," _rgFieldDescriptors[TFI_NUM_FIELDS];\n",[599,15438,15439,15442],{"class":601,"line":1833},[599,15440,15441],{"class":609},"    FIELD_STATE_PAIR",[599,15443,15444],{"class":666},"                     _rgFieldStatePairs[TFI_NUM_FIELDS];\n",[599,15446,15447,15450],{"class":601,"line":1863},[599,15448,15449],{"class":609},"    PWSTR",[599,15451,15452],{"class":666},"                                _rgFieldStrings[TFI_NUM_FIELDS];\n",[599,15454,15455,15457,15460],{"class":601,"line":1870},[599,15456,15449],{"class":609},[599,15458,15459],{"class":666},"                                _pszSid;",[599,15461,15462],{"class":772},"   \u002F\u002F null on the fallback and RDP tile\n",[599,15464,15465,15468,15470],{"class":601,"line":1875},[599,15466,15467],{"class":609},"    ICredentialProviderCredentialEvents",[599,15469,748],{"class":605},[599,15471,15472],{"class":666}," _pCredProvCredentialEvents;\n",[599,15474,15475],{"class":601,"line":1880},[599,15476,10612],{"class":666},[15,15478,15479,590],{},[69,15480,15481],{},"CTacCredential.cpp",[148,15483,15485],{"className":593,"code":15484,"language":595,"meta":154,"style":154},"#include \"CTacCredential.h\"\n#include \"helpers.h\"\n#include \"guid.h\"\n#include \"store.h\"\n#include \"verify.h\"\n#include \"eventlog.h\"\n#include \"dll.h\"\n\n#include \u003Cntsecapi.h>\n#include \u003Cshlwapi.h>\n#include \u003Cstrsafe.h>\n#include \u003Ccstdio>\n#include \u003Cctime>\n#include \u003Cstring>\n#include \u003Cvector>\n\n#pragma comment(lib, \"shlwapi.lib\")\n#pragma comment(lib, \"gdi32.lib\")\n#pragma comment(lib, \"user32.lib\")\n\n\u002F\u002F STATUS_LOGON_FAILURE lives in ntstatus.h, which clashes with windows.h unless\n\u002F\u002F WIN32_NO_STATUS is set everywhere. Defining the one value we need is simpler.\n#ifndef STATUS_LOGON_FAILURE\n#define STATUS_LOGON_FAILURE ((NTSTATUS)0xC000006DL)\n#endif\n\nCTacCredential::CTacCredential()\n    : _cRef(1), _cpus(CPUS_INVALID), _pszSid(nullptr), _pCredProvCredentialEvents(nullptr)\n{\n    ZeroMemory(_rgFieldDescriptors, sizeof(_rgFieldDescriptors));\n    ZeroMemory(_rgFieldStatePairs, sizeof(_rgFieldStatePairs));\n    ZeroMemory(_rgFieldStrings, sizeof(_rgFieldStrings));\n    DllAddRef();\n}\n\nCTacCredential::~CTacCredential()\n{\n    for (DWORD i = 0; i \u003C TFI_NUM_FIELDS; ++i)\n        _FreeField(i);\n    CoTaskMemFree(_pszSid);\n    if (_pCredProvCredentialEvents)\n        _pCredProvCredentialEvents->Release();\n    DllRelease();\n}\n\n\u002F\u002F Wipe and free a field string.\nvoid CTacCredential::_FreeField(DWORD dwFieldID)\n{\n    PWSTR& s = _rgFieldStrings[dwFieldID];\n    if (s)\n    {\n        size_t len = 0;\n        if (SUCCEEDED(StringCchLengthW(s, STRSAFE_MAX_CCH, &len)))\n            SecureZeroMemory(s, len * sizeof(WCHAR));\n        CoTaskMemFree(s);\n        s = nullptr;\n    }\n}\n\n\u002F\u002F Clear a field back to an empty string, both in our copy and on screen.\nvoid CTacCredential::_ResetField(DWORD dwFieldID)\n{\n    _FreeField(dwFieldID);\n    SHStrDupW(L\"\", &_rgFieldStrings[dwFieldID]);\n    if (_pCredProvCredentialEvents)\n        _pCredProvCredentialEvents->SetFieldString(this, dwFieldID, L\"\");\n}\n\nHRESULT CTacCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,\n                                   const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd,\n                                   const FIELD_STATE_PAIR* rgfsp,\n                                   PCWSTR pwzUser, PCWSTR pwzPassword, PCWSTR pwzSid)\n{\n    _cpus = cpus;\n    for (DWORD i = 0; i \u003C TFI_NUM_FIELDS; ++i)\n    {\n        _rgFieldDescriptors[i] = rgcpfd[i];\n        _rgFieldStatePairs[i]  = rgfsp[i];\n    }\n\n    const bool hasUser = pwzUser && *pwzUser;\n    const bool hasPass = pwzPassword && *pwzPassword;\n\n    \u002F\u002F A tile without a SID is the fallback or RDP tile: it is not bound to an\n    \u002F\u002F account, so the username field is shown. Put the caret on the first empty\n    \u002F\u002F field.\n    if (!pwzSid)\n    {\n        _rgFieldStatePairs[TFI_USERNAME] = { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE };\n        _rgFieldStatePairs[TFI_PASSWORD].cpfis = CPFIS_NONE;\n        if (!hasUser)\n            _rgFieldStatePairs[TFI_USERNAME].cpfis = CPFIS_FOCUSED;\n        else if (!hasPass)\n            _rgFieldStatePairs[TFI_PASSWORD].cpfis = CPFIS_FOCUSED;\n        else\n            _rgFieldStatePairs[TFI_OTP].cpfis = CPFIS_FOCUSED;\n    }\n\n    HRESULT hr = pwzSid ? SHStrDupW(pwzSid, &_pszSid) : S_OK;\n    if (SUCCEEDED(hr))\n        hr = SHStrDupW(L\"TheAdminCafe 2FA\", &_rgFieldStrings[TFI_LABEL]);\n    if (SUCCEEDED(hr))\n        hr = SHStrDupW(hasUser ? pwzUser : L\"\", &_rgFieldStrings[TFI_USERNAME]);\n    if (SUCCEEDED(hr))\n        hr = SHStrDupW(hasPass ? pwzPassword : L\"\", &_rgFieldStrings[TFI_PASSWORD]);\n    if (SUCCEEDED(hr))\n        hr = SHStrDupW(L\"\", &_rgFieldStrings[TFI_OTP]);\n    return hr;\n}\n\n\u002F\u002F --- IUnknown ---------------------------------------------------------------\n\nIFACEMETHODIMP_(ULONG) CTacCredential::AddRef()\n{\n    return InterlockedIncrement(&_cRef);\n}\n\nIFACEMETHODIMP_(ULONG) CTacCredential::Release()\n{\n    LONG cRef = InterlockedDecrement(&_cRef);\n    if (cRef == 0)\n        delete this;\n    return cRef;\n}\n\nIFACEMETHODIMP CTacCredential::QueryInterface(REFIID riid, void** ppv)\n{\n    if (!ppv)\n        return E_POINTER;\n    if (IsEqualIID(riid, IID_IUnknown) ||\n        IsEqualIID(riid, __uuidof(ICredentialProviderCredential)) ||\n        IsEqualIID(riid, __uuidof(ICredentialProviderCredential2)))\n    {\n        *ppv = static_cast\u003CICredentialProviderCredential2*>(this);\n        AddRef();\n        return S_OK;\n    }\n    *ppv = nullptr;\n    return E_NOINTERFACE;\n}\n\n\u002F\u002F --- ICredentialProviderCredential ------------------------------------------\n\nIFACEMETHODIMP CTacCredential::Advise(ICredentialProviderCredentialEvents* pcpce)\n{\n    if (_pCredProvCredentialEvents)\n        _pCredProvCredentialEvents->Release();\n    _pCredProvCredentialEvents = pcpce;\n    if (_pCredProvCredentialEvents)\n        _pCredProvCredentialEvents->AddRef();\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::UnAdvise()\n{\n    if (_pCredProvCredentialEvents)\n    {\n        _pCredProvCredentialEvents->Release();\n        _pCredProvCredentialEvents = nullptr;\n    }\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::SetSelected(BOOL* pbAutoLogon)\n{\n    *pbAutoLogon = FALSE;   \u002F\u002F we always need the code, so never log on automatically\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::SetDeselected()\n{\n    \u002F\u002F Do not leave the password or the code in memory once the tile is left.\n    _ResetField(TFI_PASSWORD);\n    _ResetField(TFI_OTP);\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::GetFieldState(DWORD dwFieldID,\n                                             CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs,\n                                             CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis)\n{\n    if (dwFieldID >= TFI_NUM_FIELDS)\n        return E_INVALIDARG;\n    *pcpfs  = _rgFieldStatePairs[dwFieldID].cpfs;\n    *pcpfis = _rgFieldStatePairs[dwFieldID].cpfis;\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::GetStringValue(DWORD dwFieldID, PWSTR* ppwsz)\n{\n    if (dwFieldID >= TFI_NUM_FIELDS)\n        return E_INVALIDARG;\n    return SHStrDupW(_rgFieldStrings[dwFieldID] ? _rgFieldStrings[dwFieldID] : L\"\", ppwsz);\n}\n\n\u002F\u002F The provider logo, drawn in code so no image file is required. A coffee-brown\n\u002F\u002F square with \"2FA\". This is only the small icon under \"Sign-in options\"; the\n\u002F\u002F large round picture on a user tile is the account picture drawn by Windows.\nstatic HBITMAP CreateLogo()\n{\n    const int size = 128;\n\n    BITMAPINFO bmi = {};\n    bmi.bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);\n    bmi.bmiHeader.biWidth    = size;\n    bmi.bmiHeader.biHeight   = -size;   \u002F\u002F top-down\n    bmi.bmiHeader.biPlanes   = 1;\n    bmi.bmiHeader.biBitCount = 24;      \u002F\u002F no alpha channel to worry about\n    bmi.bmiHeader.biCompression = BI_RGB;\n\n    void* pvBits = nullptr;\n    HBITMAP hbmp = CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &pvBits, nullptr, 0);\n    if (!hbmp)\n        return nullptr;\n\n    HDC hdc = CreateCompatibleDC(nullptr);\n    if (!hdc)\n    {\n        DeleteObject(hbmp);\n        return nullptr;\n    }\n\n    HGDIOBJ hOldBmp = SelectObject(hdc, hbmp);\n\n    RECT rc = { 0, 0, size, size };\n    HBRUSH hBrush = CreateSolidBrush(RGB(0x6F, 0x4E, 0x37));\n    FillRect(hdc, &rc, hBrush);\n    DeleteObject(hBrush);\n\n    HFONT hFont = CreateFontW(-48, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE,\n                              DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\n                              ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_SWISS, L\"Segoe UI\");\n    HGDIOBJ hOldFont = hFont ? SelectObject(hdc, hFont) : nullptr;\n    SetBkMode(hdc, TRANSPARENT);\n    SetTextColor(hdc, RGB(0xFF, 0xFF, 0xFF));\n    DrawTextW(hdc, L\"2FA\", -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);\n\n    if (hOldFont)\n        SelectObject(hdc, hOldFont);\n    if (hFont)\n        DeleteObject(hFont);\n    SelectObject(hdc, hOldBmp);\n    DeleteDC(hdc);\n    GdiFlush();\n    return hbmp;\n}\n\nIFACEMETHODIMP CTacCredential::GetBitmapValue(DWORD dwFieldID, HBITMAP* phbmp)\n{\n    if (dwFieldID != TFI_TILEIMAGE || !phbmp)\n        return E_INVALIDARG;\n\n    HBITMAP hbmp = CreateLogo();\n    if (!hbmp)\n        return E_FAIL;\n\n    *phbmp = hbmp;   \u002F\u002F LogonUI takes ownership and deletes it\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::GetSubmitButtonValue(DWORD dwFieldID, DWORD* pdwAdjacentTo)\n{\n    if (dwFieldID != TFI_SUBMIT || !pdwAdjacentTo)\n        return E_INVALIDARG;\n    *pdwAdjacentTo = TFI_OTP;   \u002F\u002F the arrow sits next to the code field\n    return S_OK;\n}\n\nIFACEMETHODIMP CTacCredential::SetStringValue(DWORD dwFieldID, PCWSTR pwz)\n{\n    if (dwFieldID != TFI_USERNAME && dwFieldID != TFI_PASSWORD && dwFieldID != TFI_OTP)\n        return E_INVALIDARG;\n    _FreeField(dwFieldID);\n    return SHStrDupW(pwz ? pwz : L\"\", &_rgFieldStrings[dwFieldID]);\n}\n\n\u002F\u002F Our tile has no checkbox or combo box fields.\nIFACEMETHODIMP CTacCredential::GetCheckboxValue(DWORD, BOOL*, PWSTR*)       { return E_NOTIMPL; }\nIFACEMETHODIMP CTacCredential::GetComboBoxValueCount(DWORD, DWORD*, DWORD*) { return E_NOTIMPL; }\nIFACEMETHODIMP CTacCredential::GetComboBoxValueAt(DWORD, DWORD, PWSTR*)     { return E_NOTIMPL; }\nIFACEMETHODIMP CTacCredential::SetCheckboxValue(DWORD, BOOL)                { return E_NOTIMPL; }\nIFACEMETHODIMP CTacCredential::SetComboBoxSelectedValue(DWORD, DWORD)       { return E_NOTIMPL; }\nIFACEMETHODIMP CTacCredential::CommandLinkClicked(DWORD)                    { return E_NOTIMPL; }\n\n\u002F\u002F --- ICredentialProviderCredential2 -----------------------------------------\n\n\u002F\u002F Returning a SID binds the tile to that account, so Windows shows its name and\n\u002F\u002F round picture. The fallback and RDP tiles have no SID and return S_FALSE,\n\u002F\u002F which makes them a generic tile with a username field.\nIFACEMETHODIMP CTacCredential::GetUserSid(PWSTR* ppszSid)\n{\n    if (!ppszSid)\n        return E_POINTER;\n    *ppszSid = nullptr;\n    if (!_pszSid)\n        return S_FALSE;\n    return SHStrDupW(_pszSid, ppszSid);\n}\n\n\u002F\u002F --- the actual work: check the code, then serialize the password -----------\n\nIFACEMETHODIMP CTacCredential::GetSerialization(\n    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,\n    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,\n    PWSTR* ppwszOptionalStatusText,\n    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon)\n{\n    *pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;\n    pcpcs->rgbSerialization = nullptr;\n    pcpcs->cbSerialization  = 0;\n\n    \u002F\u002F The username field holds \"PC\\user\" on a user tile, or whatever was typed\n    \u002F\u002F on the fallback tile. We only ever use the bare name, so the account we\n    \u002F\u002F check the code for is the same local account we log on below.\n    std::wstring bare = _rgFieldStrings[TFI_USERNAME] ? _rgFieldStrings[TFI_USERNAME] : L\"\";\n    size_t slash = bare.find_last_of(L'\\\\');\n    if (slash != std::wstring::npos)\n        bare.erase(0, slash + 1);\n\n    \u002F\u002F --- which account is this? ---\n    \u002F\u002F The secret belongs to a SID. We resolve COMPUTERNAME\\name exactly like\n    \u002F\u002F LSA will. On a user tile the result has to be the SID of the tile.\n    std::wstring sid;\n    bool known = tac::ResolveLocalUserSid(bare, sid);\n    if (known && _pszSid && _wcsicmp(sid.c_str(), _pszSid) != 0)\n        known = false;\n\n    const std::wstring who     = bare + L\" (\" + (known ? sid : std::wstring(L\"unknown account\")) + L\")\";\n    const std::wstring session = tac::DescribeSession();\n\n    \u002F\u002F --- the second factor ---\n    std::wstring code = _rgFieldStrings[TFI_OTP] ? _rgFieldStrings[TFI_OTP] : L\"\";\n    tac::OtpInfo info = {};\n    tac::OtpResult result = known\n        ? tac::VerifyOtp(sid, code, static_cast\u003Cuint64_t>(time(nullptr)), info)\n        : tac::OtpResult::NotEnrolled;\n    if (!code.empty())\n        SecureZeroMemory(&code[0], code.size() * sizeof(WCHAR));\n\n    if (result != tac::OtpResult::Ok)\n    {\n        \u002F\u002F \"Not enrolled\", \"wrong\" and \"already used\" look the same on screen,\n        \u002F\u002F so the screen never reveals who is enrolled. Only the lock gets its\n        \u002F\u002F own message, otherwise a locked user would keep typing valid codes.\n        PCWSTR message = L\"Invalid one-time code.\";\n        wchar_t lockText[128];\n\n        switch (result)\n        {\n        case tac::OtpResult::Wrong:\n        case tac::OtpResult::Replayed:\n            tac::LogEvent(EVENTLOG_WARNING_TYPE,\n                          result == tac::OtpResult::Wrong ? tac::EVT_CODE_WRONG : tac::EVT_CODE_REPLAYED,\n                          (result == tac::OtpResult::Wrong ? L\"Wrong one-time code for \"\n                                                           : L\"Already used one-time code for \") +\n                              who + L\". Wrong codes in a row: \" + std::to_wstring(info.failures) +\n                              L\". \" + session + L\".\");\n            if (info.minutesLeft)\n            {\n                tac::LogEvent(EVENTLOG_ERROR_TYPE, tac::EVT_LOCK_STARTED,\n                              L\"Account \" + who + L\" locked for \" + std::to_wstring(info.minutesLeft) +\n                                  L\" minutes after \" + std::to_wstring(info.failures) +\n                                  L\" wrong codes in a row. \" + session + L\".\");\n                swprintf_s(lockText, L\"Too many wrong codes. Try again in %u minutes.\", info.minutesLeft);\n                message = lockText;\n            }\n            break;\n\n        case tac::OtpResult::LockedOut:\n            tac::LogEvent(EVENTLOG_WARNING_TYPE, tac::EVT_LOCKED_OUT,\n                          L\"Logon attempt for locked account \" + who + L\", \" +\n                              std::to_wstring(info.minutesLeft) + L\" minutes left. \" + session + L\".\");\n            swprintf_s(lockText, L\"Too many wrong codes. Try again in %u minutes.\", info.minutesLeft);\n            message = lockText;\n            break;\n\n        case tac::OtpResult::NotEnrolled:\n            tac::LogEvent(EVENTLOG_WARNING_TYPE, tac::EVT_NOT_ENROLLED,\n                          L\"Logon attempt for \" + who + L\", which is not enrolled. \" + session + L\".\");\n            break;\n\n        default:\n            tac::LogEvent(EVENTLOG_ERROR_TYPE, tac::EVT_ERROR,\n                          L\"Could not read or write the 2FA state of \" + who +\n                              L\". The logon was refused. \" + session + L\".\");\n            break;\n        }\n\n        SHStrDupW(message, ppwszOptionalStatusText);\n        *pcpsiOptionalStatusIcon = CPSI_ERROR;\n        return S_OK;   \u002F\u002F S_OK keeps the tile alive; a failing HRESULT would kill it\n    }\n\n    tac::LogEvent(EVENTLOG_INFORMATION_TYPE, tac::EVT_CODE_OK,\n                  L\"Valid one-time code for \" + who + L\" (time step \" + std::to_wstring(info.step) +\n                      L\"). The password goes to LSA now. \" + session + L\".\");\n\n    \u002F\u002F --- the ordinary password logon, once the code is valid ---\n    PWSTR pwzPassword = nullptr;\n    HRESULT hr = ProtectIfNecessaryAndCopyPassword(_rgFieldStrings[TFI_PASSWORD], _cpus, &pwzPassword);\n\n    \u002F\u002F Always log on as COMPUTERNAME\\user. This is a local-account demo, so we\n    \u002F\u002F never authenticate a domain the user might have typed.\n    WCHAR computer[MAX_COMPUTERNAME_LENGTH + 1] = {};\n    DWORD cchComputer = ARRAYSIZE(computer);\n    if (SUCCEEDED(hr) && !GetComputerNameW(computer, &cchComputer))\n        hr = HRESULT_FROM_WIN32(GetLastError());\n\n    std::wstring qualified = std::wstring(computer) + L\"\\\\\" + bare;\n\n    WCHAR domain[64] = {};\n    WCHAR user[256]  = {};\n    if (SUCCEEDED(hr))\n        hr = SplitDomainAndUsername(qualified.c_str(), domain, ARRAYSIZE(domain),\n                                    user, ARRAYSIZE(user));\n\n    KERB_INTERACTIVE_UNLOCK_LOGON kiul;\n    if (SUCCEEDED(hr))\n        hr = KerbInteractiveUnlockLogonInit(domain, user, pwzPassword, _cpus, &kiul);\n    if (SUCCEEDED(hr))\n        hr = KerbInteractiveUnlockLogonPack(kiul, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);\n    if (SUCCEEDED(hr))\n    {\n        ULONG ulAuthPackage = 0;\n        hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);\n        if (SUCCEEDED(hr))\n        {\n            pcpcs->ulAuthenticationPackage = ulAuthPackage;\n            pcpcs->clsidCredentialProvider = CLSID_CTacProvider;\n            *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;\n        }\n    }\n\n    if (FAILED(hr) && pcpcs->rgbSerialization)\n    {\n        SecureZeroMemory(pcpcs->rgbSerialization, pcpcs->cbSerialization);\n        CoTaskMemFree(pcpcs->rgbSerialization);\n        pcpcs->rgbSerialization = nullptr;\n        pcpcs->cbSerialization  = 0;\n    }\n    if (pwzPassword)\n    {\n        SecureZeroMemory(pwzPassword, wcslen(pwzPassword) * sizeof(WCHAR));\n        CoTaskMemFree(pwzPassword);\n    }\n    return hr;\n}\n\n\u002F\u002F LSA reports the result of the logon here. If it failed, clear password and\n\u002F\u002F code like the built-in tile does (the code is used up anyway), and turn a\n\u002F\u002F wrong password into a readable message.\nIFACEMETHODIMP CTacCredential::ReportResult(NTSTATUS ntsStatus, NTSTATUS,\n                                            PWSTR* ppwszOptionalStatusText,\n                                            CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon)\n{\n    *ppwszOptionalStatusText = nullptr;\n    *pcpsiOptionalStatusIcon = CPSI_NONE;\n\n    if (ntsStatus != 0)\n    {\n        _ResetField(TFI_PASSWORD);\n        _ResetField(TFI_OTP);\n    }\n\n    if (ntsStatus == STATUS_LOGON_FAILURE)\n    {\n        SHStrDupW(L\"Incorrect password.\", ppwszOptionalStatusText);\n        *pcpsiOptionalStatusIcon = CPSI_ERROR;\n    }\n    return S_OK;\n}\n",[69,15486,15487,15493,15499,15505,15511,15518,15525,15531,15535,15541,15548,15555,15561,15567,15573,15579,15583,15600,15617,15634,15638,15643,15648,15656,15677,15682,15686,15696,15730,15734,15747,15759,15771,15777,15781,15785,15797,15801,15822,15830,15837,15844,15853,15859,15863,15867,15872,15891,15895,15909,15916,15920,15933,15954,15967,15974,15985,15989,15993,15997,16002,16021,16025,16033,16049,16055,16073,16077,16081,16099,16112,16124,16145,16149,16158,16178,16182,16192,16202,16206,16210,16232,16253,16257,16262,16267,16272,16283,16287,16297,16307,16318,16328,16342,16351,16355,16364,16368,16372,16400,16410,16429,16439,16466,16476,16502,16512,16531,16537,16541,16545,16549,16553,16567,16571,16583,16587,16591,16605,16609,16625,16637,16645,16651,16655,16659,16683,16687,16697,16703,16715,16729,16740,16744,16764,16770,16776,16780,16792,16798,16802,16806,16811,16815,16835,16839,16845,16853,16863,16869,16877,16883,16887,16891,16903,16907,16913,16917,16925,16936,16940,16946,16950,16954,16975,16979,16994,17000,17004,17008,17021,17025,17030,17038,17045,17051,17055,17059,17078,17089,17100,17104,17116,17122,17134,17146,17152,17156,17160,17186,17190,17200,17206,17227,17231,17235,17240,17245,17250,17262,17266,17282,17286,17298,17310,17320,17335,17346,17360,17370,17374,17388,17425,17436,17444,17448,17467,17478,17482,17490,17498,17502,17506,17522,17526,17547,17588,17601,17609,17613,17648,17653,17668,17692,17700,17729,17762,17766,17773,17781,17788,17795,17803,17811,17818,17825,17829,17833,17860,17864,17882,17888,17892,17904,17914,17921,17925,17940,17946,17950,17954,17981,17985,18003,18009,18024,18030,18034,18038,18062,18066,18096,18102,18108,18132,18136,18140,18145,18180,18213,18245,18271,18296,18318,18322,18327,18331,18336,18341,18346,18366,18370,18381,18387,18400,18411,18418,18427,18431,18435,18440,18444,18456,18467,18478,18488,18499,18503,18515,18526,18537,18542,18548,18554,18560,18587,18611,18629,18651,18656,18662,18668,18674,18685,18704,18735,18747,18752,18806,18831,18836,18842,18869,18886,18904,18934,18949,18965,18992,18997,19016,19021,19027,19033,19039,19055,19069,19074,19083,19088,19103,19117,19131,19162,19183,19196,19221,19238,19246,19251,19269,19298,19316,19332,19352,19363,19368,19376,19381,19395,19412,19430,19457,19473,19483,19490,19495,19509,19525,19550,19557,19562,19570,19586,19598,19614,19621,19626,19631,19640,19653,19664,19669,19674,19691,19719,19735,19740,19746,19759,19779,19784,19790,19796,19811,19824,19848,19864,19869,19903,19908,19923,19938,19949,19973,19984,19989,19997,20008,20026,20037,20060,20071,20076,20091,20108,20119,20124,20135,20146,20159,20164,20169,20174,20190,20195,20203,20211,20223,20235,20240,20248,20253,20273,20281,20286,20293,20298,20303,20309,20315,20321,20345,20357,20369,20374,20388,20400,20405,20419,20424,20432,20439,20444,20449,20461,20466,20479,20490,20495,20502],{"__ignoreMap":154},[599,15488,15489,15491],{"class":601,"line":602},[599,15490,616],{"class":605},[599,15492,10927],{"class":619},[599,15494,15495,15497],{"class":601,"line":613},[599,15496,616],{"class":605},[599,15498,11509],{"class":619},[599,15500,15501,15503],{"class":601,"line":623},[599,15502,616],{"class":605},[599,15504,11530],{"class":619},[599,15506,15507,15509],{"class":601,"line":631},[599,15508,616],{"class":605},[599,15510,5477],{"class":619},[599,15512,15513,15515],{"class":601,"line":639},[599,15514,616],{"class":605},[599,15516,15517],{"class":619}," \"verify.h\"\n",[599,15519,15520,15522],{"class":601,"line":647},[599,15521,616],{"class":605},[599,15523,15524],{"class":619}," \"eventlog.h\"\n",[599,15526,15527,15529],{"class":601,"line":654},[599,15528,616],{"class":605},[599,15530,11523],{"class":619},[599,15532,15533],{"class":601,"line":663},[599,15534,651],{"emptyLinePlaceholder":650},[599,15536,15537,15539],{"class":601,"line":670},[599,15538,616],{"class":605},[599,15540,11541],{"class":619},[599,15542,15543,15545],{"class":601,"line":728},[599,15544,616],{"class":605},[599,15546,15547],{"class":619}," \u003Cshlwapi.h>\n",[599,15549,15550,15552],{"class":601,"line":764},[599,15551,616],{"class":605},[599,15553,15554],{"class":619}," \u003Cstrsafe.h>\n",[599,15556,15557,15559],{"class":601,"line":769},[599,15558,616],{"class":605},[599,15560,8787],{"class":619},[599,15562,15563,15565],{"class":601,"line":776},[599,15564,616],{"class":605},[599,15566,8794],{"class":619},[599,15568,15569,15571],{"class":601,"line":816},[599,15570,616],{"class":605},[599,15572,636],{"class":619},[599,15574,15575,15577],{"class":601,"line":843},[599,15576,616],{"class":605},[599,15578,644],{"class":619},[599,15580,15581],{"class":601,"line":848},[599,15582,651],{"emptyLinePlaceholder":650},[599,15584,15585,15587,15589,15591,15593,15595,15598],{"class":601,"line":854},[599,15586,606],{"class":605},[599,15588,1016],{"class":609},[599,15590,679],{"class":666},[599,15592,1021],{"class":609},[599,15594,212],{"class":666},[599,15596,15597],{"class":619},"\"shlwapi.lib\"",[599,15599,1029],{"class":666},[599,15601,15602,15604,15606,15608,15610,15612,15615],{"class":601,"line":860},[599,15603,606],{"class":605},[599,15605,1016],{"class":609},[599,15607,679],{"class":666},[599,15609,1021],{"class":609},[599,15611,212],{"class":666},[599,15613,15614],{"class":619},"\"gdi32.lib\"",[599,15616,1029],{"class":666},[599,15618,15619,15621,15623,15625,15627,15629,15632],{"class":601,"line":866},[599,15620,606],{"class":605},[599,15622,1016],{"class":609},[599,15624,679],{"class":666},[599,15626,1021],{"class":609},[599,15628,212],{"class":666},[599,15630,15631],{"class":619},"\"user32.lib\"",[599,15633,1029],{"class":666},[599,15635,15636],{"class":601,"line":912},[599,15637,651],{"emptyLinePlaceholder":650},[599,15639,15640],{"class":601,"line":938},[599,15641,15642],{"class":772},"\u002F\u002F STATUS_LOGON_FAILURE lives in ntstatus.h, which clashes with windows.h unless\n",[599,15644,15645],{"class":601,"line":978},[599,15646,15647],{"class":772},"\u002F\u002F WIN32_NO_STATUS is set everywhere. Defining the one value we need is simpler.\n",[599,15649,15650,15653],{"class":601,"line":1316},[599,15651,15652],{"class":605},"#ifndef",[599,15654,15655],{"class":609}," STATUS_LOGON_FAILURE\n",[599,15657,15658,15661,15664,15667,15669,15672,15675],{"class":601,"line":1321},[599,15659,15660],{"class":605},"#define",[599,15662,15663],{"class":609}," STATUS_LOGON_FAILURE",[599,15665,15666],{"class":666}," ((NTSTATUS)",[599,15668,11586],{"class":605},[599,15670,15671],{"class":949},"C000006D",[599,15673,15674],{"class":605},"L",[599,15676,1029],{"class":666},[599,15678,15679],{"class":601,"line":1335},[599,15680,15681],{"class":605},"#endif\n",[599,15683,15684],{"class":601,"line":1341},[599,15685,651],{"emptyLinePlaceholder":650},[599,15687,15688,15690,15692,15694],{"class":601,"line":1367},[599,15689,11423],{"class":609},[599,15691,688],{"class":666},[599,15693,11423],{"class":609},[599,15695,3717],{"class":666},[599,15697,15698,15700,15702,15704,15706,15708,15710,15712,15715,15717,15719,15721,15724,15726,15728],{"class":601,"line":1375},[599,15699,11688],{"class":666},[599,15701,11691],{"class":609},[599,15703,679],{"class":666},[599,15705,1217],{"class":949},[599,15707,101],{"class":666},[599,15709,11700],{"class":609},[599,15711,11703],{"class":666},[599,15713,15714],{"class":609},"_pszSid",[599,15716,679],{"class":666},[599,15718,2019],{"class":949},[599,15720,101],{"class":666},[599,15722,15723],{"class":609},"_pCredProvCredentialEvents",[599,15725,679],{"class":666},[599,15727,2019],{"class":949},[599,15729,1029],{"class":666},[599,15731,15732],{"class":601,"line":1391},[599,15733,667],{"class":666},[599,15735,15736,15739,15742,15744],{"class":601,"line":1405},[599,15737,15738],{"class":609},"    ZeroMemory",[599,15740,15741],{"class":666},"(_rgFieldDescriptors, ",[599,15743,2444],{"class":605},[599,15745,15746],{"class":666},"(_rgFieldDescriptors));\n",[599,15748,15749,15751,15754,15756],{"class":601,"line":1416},[599,15750,15738],{"class":609},[599,15752,15753],{"class":666},"(_rgFieldStatePairs, ",[599,15755,2444],{"class":605},[599,15757,15758],{"class":666},"(_rgFieldStatePairs));\n",[599,15760,15761,15763,15766,15768],{"class":601,"line":1421},[599,15762,15738],{"class":609},[599,15764,15765],{"class":666},"(_rgFieldStrings, ",[599,15767,2444],{"class":605},[599,15769,15770],{"class":666},"(_rgFieldStrings));\n",[599,15772,15773,15775],{"class":601,"line":1449},[599,15774,11749],{"class":609},[599,15776,1313],{"class":666},[599,15778,15779],{"class":601,"line":1462},[599,15780,981],{"class":666},[599,15782,15783],{"class":601,"line":1477},[599,15784,651],{"emptyLinePlaceholder":650},[599,15786,15787,15789,15791,15793,15795],{"class":601,"line":1483},[599,15788,11423],{"class":609},[599,15790,688],{"class":666},[599,15792,11768],{"class":605},[599,15794,11423],{"class":609},[599,15796,3717],{"class":666},[599,15798,15799],{"class":601,"line":1496},[599,15800,667],{"class":666},[599,15802,15803,15805,15807,15809,15811,15813,15815,15818,15820],{"class":601,"line":1523},[599,15804,3407],{"class":605},[599,15806,13013],{"class":666},[599,15808,1060],{"class":605},[599,15810,1286],{"class":949},[599,15812,1681],{"class":666},[599,15814,711],{"class":605},[599,15816,15817],{"class":666}," TFI_NUM_FIELDS; ",[599,15819,1689],{"class":605},[599,15821,1692],{"class":666},[599,15823,15824,15827],{"class":601,"line":1555},[599,15825,15826],{"class":609},"        _FreeField",[599,15828,15829],{"class":666},"(i);\n",[599,15831,15832,15834],{"class":601,"line":1561},[599,15833,13908],{"class":609},[599,15835,15836],{"class":666},"(_pszSid);\n",[599,15838,15839,15841],{"class":601,"line":1567},[599,15840,3514],{"class":605},[599,15842,15843],{"class":666}," (_pCredProvCredentialEvents)\n",[599,15845,15846,15849,15851],{"class":601,"line":1577},[599,15847,15848],{"class":666},"        _pCredProvCredentialEvents->",[599,15850,11027],{"class":609},[599,15852,1313],{"class":666},[599,15854,15855,15857],{"class":601,"line":1582},[599,15856,11845],{"class":609},[599,15858,1313],{"class":666},[599,15860,15861],{"class":601,"line":1587},[599,15862,981],{"class":666},[599,15864,15865],{"class":601,"line":1616},[599,15866,651],{"emptyLinePlaceholder":650},[599,15868,15869],{"class":601,"line":1621},[599,15870,15871],{"class":772},"\u002F\u002F Wipe and free a field string.\n",[599,15873,15874,15876,15878,15880,15883,15885,15887,15889],{"class":601,"line":1634},[599,15875,11860],{"class":605},[599,15877,14735],{"class":609},[599,15879,688],{"class":666},[599,15881,15882],{"class":609},"_FreeField",[599,15884,679],{"class":666},[599,15886,5878],{"class":609},[599,15888,14955],{"class":697},[599,15890,1029],{"class":666},[599,15892,15893],{"class":601,"line":1647},[599,15894,667],{"class":666},[599,15896,15897,15899,15901,15904,15906],{"class":601,"line":1660},[599,15898,15449],{"class":609},[599,15900,694],{"class":605},[599,15902,15903],{"class":666}," s ",[599,15905,1060],{"class":605},[599,15907,15908],{"class":666}," _rgFieldStrings[dwFieldID];\n",[599,15910,15911,15913],{"class":601,"line":1665},[599,15912,3514],{"class":605},[599,15914,15915],{"class":666}," (s)\n",[599,15917,15918],{"class":601,"line":1695},[599,15919,1095],{"class":666},[599,15921,15922,15924,15927,15929,15931],{"class":601,"line":1700},[599,15923,5704],{"class":605},[599,15925,15926],{"class":666}," len ",[599,15928,1060],{"class":605},[599,15930,1286],{"class":949},[599,15932,1066],{"class":666},[599,15934,15935,15937,15939,15941,15943,15946,15949,15951],{"class":601,"line":1720},[599,15936,1100],{"class":605},[599,15938,1327],{"class":666},[599,15940,12847],{"class":609},[599,15942,679],{"class":666},[599,15944,15945],{"class":609},"StringCchLengthW",[599,15947,15948],{"class":666},"(s, STRSAFE_MAX_CCH, ",[599,15950,694],{"class":605},[599,15952,15953],{"class":666},"len)))\n",[599,15955,15956,15958,15961,15963,15965],{"class":601,"line":1731},[599,15957,12911],{"class":609},[599,15959,15960],{"class":666},"(s, len ",[599,15962,748],{"class":605},[599,15964,6453],{"class":605},[599,15966,11824],{"class":666},[599,15968,15969,15971],{"class":601,"line":1745},[599,15970,13187],{"class":609},[599,15972,15973],{"class":666},"(s);\n",[599,15975,15976,15979,15981,15983],{"class":601,"line":1750},[599,15977,15978],{"class":666},"        s ",[599,15980,1060],{"class":605},[599,15982,1962],{"class":949},[599,15984,1066],{"class":666},[599,15986,15987],{"class":601,"line":1761},[599,15988,1224],{"class":666},[599,15990,15991],{"class":601,"line":1787},[599,15992,981],{"class":666},[599,15994,15995],{"class":601,"line":1792},[599,15996,651],{"emptyLinePlaceholder":650},[599,15998,15999],{"class":601,"line":1815},[599,16000,16001],{"class":772},"\u002F\u002F Clear a field back to an empty string, both in our copy and on screen.\n",[599,16003,16004,16006,16008,16010,16013,16015,16017,16019],{"class":601,"line":1820},[599,16005,11860],{"class":605},[599,16007,14735],{"class":609},[599,16009,688],{"class":666},[599,16011,16012],{"class":609},"_ResetField",[599,16014,679],{"class":666},[599,16016,5878],{"class":609},[599,16018,14955],{"class":697},[599,16020,1029],{"class":666},[599,16022,16023],{"class":601,"line":1833},[599,16024,667],{"class":666},[599,16026,16027,16030],{"class":601,"line":1863},[599,16028,16029],{"class":609},"    _FreeField",[599,16031,16032],{"class":666},"(dwFieldID);\n",[599,16034,16035,16038,16040,16042,16044,16046],{"class":601,"line":1870},[599,16036,16037],{"class":609},"    SHStrDupW",[599,16039,679],{"class":666},[599,16041,13175],{"class":619},[599,16043,212],{"class":666},[599,16045,694],{"class":605},[599,16047,16048],{"class":666},"_rgFieldStrings[dwFieldID]);\n",[599,16050,16051,16053],{"class":601,"line":1875},[599,16052,3514],{"class":605},[599,16054,15843],{"class":666},[599,16056,16057,16059,16062,16064,16066,16069,16071],{"class":601,"line":1880},[599,16058,15848],{"class":666},[599,16060,16061],{"class":609},"SetFieldString",[599,16063,679],{"class":666},[599,16065,8593],{"class":949},[599,16067,16068],{"class":666},", dwFieldID, ",[599,16070,13175],{"class":619},[599,16072,725],{"class":666},[599,16074,16075],{"class":601,"line":1946},[599,16076,981],{"class":666},[599,16078,16079],{"class":601,"line":1951},[599,16080,651],{"emptyLinePlaceholder":650},[599,16082,16083,16085,16087,16089,16091,16093,16095,16097],{"class":601,"line":1967},[599,16084,12617],{"class":609},[599,16086,14735],{"class":609},[599,16088,688],{"class":666},[599,16090,12711],{"class":609},[599,16092,679],{"class":666},[599,16094,11076],{"class":609},[599,16096,11079],{"class":697},[599,16098,813],{"class":666},[599,16100,16101,16104,16106,16108,16110],{"class":601,"line":1982},[599,16102,16103],{"class":605},"                                   const",[599,16105,10661],{"class":609},[599,16107,748],{"class":605},[599,16109,14787],{"class":697},[599,16111,813],{"class":666},[599,16113,16114,16116,16118,16120,16122],{"class":601,"line":1997},[599,16115,16103],{"class":605},[599,16117,10810],{"class":609},[599,16119,748],{"class":605},[599,16121,14800],{"class":697},[599,16123,813],{"class":666},[599,16125,16126,16129,16131,16133,16135,16137,16139,16141,16143],{"class":601,"line":2002},[599,16127,16128],{"class":609},"                                   PCWSTR",[599,16130,11364],{"class":697},[599,16132,212],{"class":666},[599,16134,11361],{"class":609},[599,16136,11371],{"class":697},[599,16138,212],{"class":666},[599,16140,11361],{"class":609},[599,16142,11378],{"class":697},[599,16144,1029],{"class":666},[599,16146,16147],{"class":601,"line":2024},[599,16148,667],{"class":666},[599,16150,16151,16154,16156],{"class":601,"line":2037},[599,16152,16153],{"class":666},"    _cpus ",[599,16155,1060],{"class":605},[599,16157,12331],{"class":666},[599,16159,16160,16162,16164,16166,16168,16170,16172,16174,16176],{"class":601,"line":2047},[599,16161,3407],{"class":605},[599,16163,13013],{"class":666},[599,16165,1060],{"class":605},[599,16167,1286],{"class":949},[599,16169,1681],{"class":666},[599,16171,711],{"class":605},[599,16173,15817],{"class":666},[599,16175,1689],{"class":605},[599,16177,1692],{"class":666},[599,16179,16180],{"class":601,"line":2052},[599,16181,1095],{"class":666},[599,16183,16184,16187,16189],{"class":601,"line":2096},[599,16185,16186],{"class":666},"        _rgFieldDescriptors[i] ",[599,16188,1060],{"class":605},[599,16190,16191],{"class":666}," rgcpfd[i];\n",[599,16193,16194,16197,16199],{"class":601,"line":2124},[599,16195,16196],{"class":666},"        _rgFieldStatePairs[i]  ",[599,16198,1060],{"class":605},[599,16200,16201],{"class":666}," rgfsp[i];\n",[599,16203,16204],{"class":601,"line":2129},[599,16205,1224],{"class":666},[599,16207,16208],{"class":601,"line":2163},[599,16209,651],{"emptyLinePlaceholder":650},[599,16211,16212,16214,16216,16219,16221,16224,16226,16229],{"class":601,"line":2186},[599,16213,12451],{"class":605},[599,16215,1885],{"class":605},[599,16217,16218],{"class":666}," hasUser ",[599,16220,1060],{"class":605},[599,16222,16223],{"class":666}," pwzUser ",[599,16225,3154],{"class":605},[599,16227,16228],{"class":605}," *",[599,16230,16231],{"class":666},"pwzUser;\n",[599,16233,16234,16236,16238,16241,16243,16246,16248,16250],{"class":601,"line":2195},[599,16235,12451],{"class":605},[599,16237,1885],{"class":605},[599,16239,16240],{"class":666}," hasPass ",[599,16242,1060],{"class":605},[599,16244,16245],{"class":666}," pwzPassword ",[599,16247,3154],{"class":605},[599,16249,16228],{"class":605},[599,16251,16252],{"class":666},"pwzPassword;\n",[599,16254,16255],{"class":601,"line":2200},[599,16256,651],{"emptyLinePlaceholder":650},[599,16258,16259],{"class":601,"line":2212},[599,16260,16261],{"class":772},"    \u002F\u002F A tile without a SID is the fallback or RDP tile: it is not bound to an\n",[599,16263,16264],{"class":601,"line":2220},[599,16265,16266],{"class":772},"    \u002F\u002F account, so the username field is shown. Put the caret on the first empty\n",[599,16268,16269],{"class":601,"line":2225},[599,16270,16271],{"class":772},"    \u002F\u002F field.\n",[599,16273,16274,16276,16278,16280],{"class":601,"line":2230},[599,16275,3514],{"class":605},[599,16277,1327],{"class":666},[599,16279,2435],{"class":605},[599,16281,16282],{"class":666},"pwzSid)\n",[599,16284,16285],{"class":601,"line":2265},[599,16286,1095],{"class":666},[599,16288,16289,16292,16294],{"class":601,"line":2286},[599,16290,16291],{"class":666},"        _rgFieldStatePairs[TFI_USERNAME] ",[599,16293,1060],{"class":605},[599,16295,16296],{"class":666}," { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE };\n",[599,16298,16299,16302,16304],{"class":601,"line":2291},[599,16300,16301],{"class":666},"        _rgFieldStatePairs[TFI_PASSWORD].cpfis ",[599,16303,1060],{"class":605},[599,16305,16306],{"class":666}," CPFIS_NONE;\n",[599,16308,16309,16311,16313,16315],{"class":601,"line":2297},[599,16310,1100],{"class":605},[599,16312,1327],{"class":666},[599,16314,2435],{"class":605},[599,16316,16317],{"class":666},"hasUser)\n",[599,16319,16320,16323,16325],{"class":601,"line":2317},[599,16321,16322],{"class":666},"            _rgFieldStatePairs[TFI_USERNAME].cpfis ",[599,16324,1060],{"class":605},[599,16326,16327],{"class":666}," CPFIS_FOCUSED;\n",[599,16329,16330,16333,16335,16337,16339],{"class":601,"line":2331},[599,16331,16332],{"class":605},"        else",[599,16334,4321],{"class":605},[599,16336,1327],{"class":666},[599,16338,2435],{"class":605},[599,16340,16341],{"class":666},"hasPass)\n",[599,16343,16344,16347,16349],{"class":601,"line":2361},[599,16345,16346],{"class":666},"            _rgFieldStatePairs[TFI_PASSWORD].cpfis ",[599,16348,1060],{"class":605},[599,16350,16327],{"class":666},[599,16352,16353],{"class":601,"line":2366},[599,16354,9143],{"class":605},[599,16356,16357,16360,16362],{"class":601,"line":2393},[599,16358,16359],{"class":666},"            _rgFieldStatePairs[TFI_OTP].cpfis ",[599,16361,1060],{"class":605},[599,16363,16327],{"class":666},[599,16365,16366],{"class":601,"line":2406},[599,16367,1224],{"class":666},[599,16369,16370],{"class":601,"line":2411},[599,16371,651],{"emptyLinePlaceholder":650},[599,16373,16374,16376,16378,16380,16383,16385,16388,16391,16393,16396,16398],{"class":601,"line":2416},[599,16375,11344],{"class":609},[599,16377,12703],{"class":666},[599,16379,1060],{"class":605},[599,16381,16382],{"class":666}," pwzSid ",[599,16384,9412],{"class":605},[599,16386,16387],{"class":609}," SHStrDupW",[599,16389,16390],{"class":666},"(pwzSid, ",[599,16392,694],{"class":605},[599,16394,16395],{"class":666},"_pszSid) ",[599,16397,590],{"class":605},[599,16399,12172],{"class":666},[599,16401,16402,16404,16406,16408],{"class":601,"line":2428},[599,16403,3514],{"class":605},[599,16405,1327],{"class":666},[599,16407,12847],{"class":609},[599,16409,12731],{"class":666},[599,16411,16412,16414,16416,16418,16420,16422,16424,16426],{"class":601,"line":2450},[599,16413,13507],{"class":666},[599,16415,1060],{"class":605},[599,16417,16387],{"class":609},[599,16419,679],{"class":666},[599,16421,10707],{"class":619},[599,16423,212],{"class":666},[599,16425,694],{"class":605},[599,16427,16428],{"class":666},"_rgFieldStrings[TFI_LABEL]);\n",[599,16430,16431,16433,16435,16437],{"class":601,"line":2459},[599,16432,3514],{"class":605},[599,16434,1327],{"class":666},[599,16436,12847],{"class":609},[599,16438,12731],{"class":666},[599,16440,16441,16443,16445,16447,16450,16452,16454,16456,16459,16461,16463],{"class":601,"line":2464},[599,16442,13507],{"class":666},[599,16444,1060],{"class":605},[599,16446,16387],{"class":609},[599,16448,16449],{"class":666},"(hasUser ",[599,16451,9412],{"class":605},[599,16453,16223],{"class":666},[599,16455,590],{"class":605},[599,16457,16458],{"class":619}," L\"\"",[599,16460,212],{"class":666},[599,16462,694],{"class":605},[599,16464,16465],{"class":666},"_rgFieldStrings[TFI_USERNAME]);\n",[599,16467,16468,16470,16472,16474],{"class":601,"line":2470},[599,16469,3514],{"class":605},[599,16471,1327],{"class":666},[599,16473,12847],{"class":609},[599,16475,12731],{"class":666},[599,16477,16478,16480,16482,16484,16487,16489,16491,16493,16495,16497,16499],{"class":601,"line":2476},[599,16479,13507],{"class":666},[599,16481,1060],{"class":605},[599,16483,16387],{"class":609},[599,16485,16486],{"class":666},"(hasPass ",[599,16488,9412],{"class":605},[599,16490,16245],{"class":666},[599,16492,590],{"class":605},[599,16494,16458],{"class":619},[599,16496,212],{"class":666},[599,16498,694],{"class":605},[599,16500,16501],{"class":666},"_rgFieldStrings[TFI_PASSWORD]);\n",[599,16503,16504,16506,16508,16510],{"class":601,"line":2503},[599,16505,3514],{"class":605},[599,16507,1327],{"class":666},[599,16509,12847],{"class":609},[599,16511,12731],{"class":666},[599,16513,16514,16516,16518,16520,16522,16524,16526,16528],{"class":601,"line":2537},[599,16515,13507],{"class":666},[599,16517,1060],{"class":605},[599,16519,16387],{"class":609},[599,16521,679],{"class":666},[599,16523,13175],{"class":619},[599,16525,212],{"class":666},[599,16527,694],{"class":605},[599,16529,16530],{"class":666},"_rgFieldStrings[TFI_OTP]);\n",[599,16532,16533,16535],{"class":601,"line":2569},[599,16534,3551],{"class":605},[599,16536,12751],{"class":666},[599,16538,16539],{"class":601,"line":2600},[599,16540,981],{"class":666},[599,16542,16543],{"class":601,"line":2623},[599,16544,651],{"emptyLinePlaceholder":650},[599,16546,16547],{"class":601,"line":2628},[599,16548,11938],{"class":772},[599,16550,16551],{"class":601,"line":2642},[599,16552,651],{"emptyLinePlaceholder":650},[599,16554,16555,16557,16559,16561,16563,16565],{"class":601,"line":2668},[599,16556,11947],{"class":609},[599,16558,11950],{"class":666},[599,16560,11423],{"class":609},[599,16562,688],{"class":666},[599,16564,11012],{"class":609},[599,16566,3717],{"class":666},[599,16568,16569],{"class":601,"line":2682},[599,16570,667],{"class":666},[599,16572,16573,16575,16577,16579,16581],{"class":601,"line":2698},[599,16574,3551],{"class":605},[599,16576,11969],{"class":609},[599,16578,679],{"class":666},[599,16580,694],{"class":605},[599,16582,11976],{"class":666},[599,16584,16585],{"class":601,"line":2707},[599,16586,981],{"class":666},[599,16588,16589],{"class":601,"line":2712},[599,16590,651],{"emptyLinePlaceholder":650},[599,16592,16593,16595,16597,16599,16601,16603],{"class":601,"line":2717},[599,16594,11947],{"class":609},[599,16596,11950],{"class":666},[599,16598,11423],{"class":609},[599,16600,688],{"class":666},[599,16602,11027],{"class":609},[599,16604,3717],{"class":666},[599,16606,16607],{"class":601,"line":2760},[599,16608,667],{"class":666},[599,16610,16611,16613,16615,16617,16619,16621,16623],{"class":601,"line":2781},[599,16612,11389],{"class":609},[599,16614,12009],{"class":666},[599,16616,1060],{"class":605},[599,16618,12014],{"class":609},[599,16620,679],{"class":666},[599,16622,694],{"class":605},[599,16624,11976],{"class":666},[599,16626,16627,16629,16631,16633,16635],{"class":601,"line":2802},[599,16628,3514],{"class":605},[599,16630,12027],{"class":666},[599,16632,1349],{"class":605},[599,16634,1286],{"class":949},[599,16636,1029],{"class":666},[599,16638,16639,16641,16643],{"class":601,"line":2807},[599,16640,12038],{"class":605},[599,16642,12041],{"class":949},[599,16644,1066],{"class":666},[599,16646,16647,16649],{"class":601,"line":2819},[599,16648,3551],{"class":605},[599,16650,12050],{"class":666},[599,16652,16653],{"class":601,"line":2824},[599,16654,981],{"class":666},[599,16656,16657],{"class":601,"line":2830},[599,16658,651],{"emptyLinePlaceholder":650},[599,16660,16661,16663,16665,16667,16669,16671,16673,16675,16677,16679,16681],{"class":601,"line":2851},[599,16662,12063],{"class":609},[599,16664,14735],{"class":609},[599,16666,688],{"class":666},[599,16668,12070],{"class":609},[599,16670,679],{"class":666},[599,16672,11042],{"class":609},[599,16674,11045],{"class":697},[599,16676,212],{"class":666},[599,16678,11050],{"class":605},[599,16680,11053],{"class":697},[599,16682,1029],{"class":666},[599,16684,16685],{"class":601,"line":2860},[599,16686,667],{"class":666},[599,16688,16689,16691,16693,16695],{"class":601,"line":2874},[599,16690,3514],{"class":605},[599,16692,1327],{"class":666},[599,16694,2435],{"class":605},[599,16696,12099],{"class":666},[599,16698,16699,16701],{"class":601,"line":2887},[599,16700,1211],{"class":605},[599,16702,12106],{"class":666},[599,16704,16705,16707,16709,16711,16713],{"class":601,"line":2892},[599,16706,3514],{"class":605},[599,16708,1327],{"class":666},[599,16710,12115],{"class":609},[599,16712,12118],{"class":666},[599,16714,13347],{"class":605},[599,16716,16717,16720,16722,16724,16727],{"class":601,"line":2915},[599,16718,16719],{"class":609},"        IsEqualIID",[599,16721,12126],{"class":666},[599,16723,12129],{"class":609},[599,16725,16726],{"class":666},"(ICredentialProviderCredential)) ",[599,16728,13347],{"class":605},[599,16730,16731,16733,16735,16737],{"class":601,"line":2924},[599,16732,16719],{"class":609},[599,16734,12126],{"class":666},[599,16736,12129],{"class":609},[599,16738,16739],{"class":666},"(ICredentialProviderCredential2)))\n",[599,16741,16742],{"class":601,"line":2951},[599,16743,1095],{"class":666},[599,16745,16746,16748,16750,16752,16754,16756,16758,16760,16762],{"class":601,"line":2956},[599,16747,12141],{"class":605},[599,16749,12144],{"class":666},[599,16751,1060],{"class":605},[599,16753,2374],{"class":605},[599,16755,243],{"class":666},[599,16757,5897],{"class":605},[599,16759,679],{"class":666},[599,16761,8593],{"class":949},[599,16763,725],{"class":666},[599,16765,16766,16768],{"class":601,"line":2961},[599,16767,12163],{"class":609},[599,16769,1313],{"class":666},[599,16771,16772,16774],{"class":601,"line":2982},[599,16773,1211],{"class":605},[599,16775,12172],{"class":666},[599,16777,16778],{"class":601,"line":3011},[599,16779,1224],{"class":666},[599,16781,16782,16784,16786,16788,16790],{"class":601,"line":3016},[599,16783,12236],{"class":605},[599,16785,12144],{"class":666},[599,16787,1060],{"class":605},[599,16789,1962],{"class":949},[599,16791,1066],{"class":666},[599,16793,16794,16796],{"class":601,"line":3044},[599,16795,3551],{"class":605},[599,16797,12251],{"class":666},[599,16799,16800],{"class":601,"line":3051},[599,16801,981],{"class":666},[599,16803,16804],{"class":601,"line":3073},[599,16805,651],{"emptyLinePlaceholder":650},[599,16807,16808],{"class":601,"line":3078},[599,16809,16810],{"class":772},"\u002F\u002F --- ICredentialProviderCredential ------------------------------------------\n",[599,16812,16813],{"class":601,"line":3084},[599,16814,651],{"emptyLinePlaceholder":650},[599,16816,16817,16819,16821,16823,16825,16827,16829,16831,16833],{"class":601,"line":3090},[599,16818,12063],{"class":609},[599,16820,14735],{"class":609},[599,16822,688],{"class":666},[599,16824,13936],{"class":609},[599,16826,679],{"class":666},[599,16828,14899],{"class":609},[599,16830,748],{"class":605},[599,16832,14904],{"class":697},[599,16834,1029],{"class":666},[599,16836,16837],{"class":601,"line":3096},[599,16838,667],{"class":666},[599,16840,16841,16843],{"class":601,"line":3109},[599,16842,3514],{"class":605},[599,16844,15843],{"class":666},[599,16846,16847,16849,16851],{"class":601,"line":3116},[599,16848,15848],{"class":666},[599,16850,11027],{"class":609},[599,16852,1313],{"class":666},[599,16854,16855,16858,16860],{"class":601,"line":3121},[599,16856,16857],{"class":666},"    _pCredProvCredentialEvents ",[599,16859,1060],{"class":605},[599,16861,16862],{"class":666}," pcpce;\n",[599,16864,16865,16867],{"class":601,"line":3136},[599,16866,3514],{"class":605},[599,16868,15843],{"class":666},[599,16870,16871,16873,16875],{"class":601,"line":3164},[599,16872,15848],{"class":666},[599,16874,11012],{"class":609},[599,16876,1313],{"class":666},[599,16878,16879,16881],{"class":601,"line":3169},[599,16880,3551],{"class":605},[599,16882,12172],{"class":666},[599,16884,16885],{"class":601,"line":3180},[599,16886,981],{"class":666},[599,16888,16889],{"class":601,"line":3189},[599,16890,651],{"emptyLinePlaceholder":650},[599,16892,16893,16895,16897,16899,16901],{"class":601,"line":3194},[599,16894,12063],{"class":609},[599,16896,14735],{"class":609},[599,16898,688],{"class":666},[599,16900,13965],{"class":609},[599,16902,3717],{"class":666},[599,16904,16905],{"class":601,"line":3199},[599,16906,667],{"class":666},[599,16908,16909,16911],{"class":601,"line":3208},[599,16910,3514],{"class":605},[599,16912,15843],{"class":666},[599,16914,16915],{"class":601,"line":3213},[599,16916,1095],{"class":666},[599,16918,16919,16921,16923],{"class":601,"line":7367},[599,16920,15848],{"class":666},[599,16922,11027],{"class":609},[599,16924,1313],{"class":666},[599,16926,16927,16930,16932,16934],{"class":601,"line":7376},[599,16928,16929],{"class":666},"        _pCredProvCredentialEvents ",[599,16931,1060],{"class":605},[599,16933,1962],{"class":949},[599,16935,1066],{"class":666},[599,16937,16938],{"class":601,"line":7381},[599,16939,1224],{"class":666},[599,16941,16942,16944],{"class":601,"line":7394},[599,16943,3551],{"class":605},[599,16945,12172],{"class":666},[599,16947,16948],{"class":601,"line":7421},[599,16949,981],{"class":666},[599,16951,16952],{"class":601,"line":7430},[599,16953,651],{"emptyLinePlaceholder":650},[599,16955,16956,16958,16960,16962,16965,16967,16969,16971,16973],{"class":601,"line":7435},[599,16957,12063],{"class":609},[599,16959,14735],{"class":609},[599,16961,688],{"class":666},[599,16963,16964],{"class":609},"SetSelected",[599,16966,679],{"class":666},[599,16968,11218],{"class":609},[599,16970,748],{"class":605},[599,16972,14930],{"class":697},[599,16974,1029],{"class":666},[599,16976,16977],{"class":601,"line":7449},[599,16978,667],{"class":666},[599,16980,16981,16983,16986,16988,16991],{"class":601,"line":7463},[599,16982,12236],{"class":605},[599,16984,16985],{"class":666},"pbAutoLogon ",[599,16987,1060],{"class":605},[599,16989,16990],{"class":666}," FALSE;",[599,16992,16993],{"class":772},"   \u002F\u002F we always need the code, so never log on automatically\n",[599,16995,16996,16998],{"class":601,"line":7478},[599,16997,3551],{"class":605},[599,16999,12172],{"class":666},[599,17001,17002],{"class":601,"line":7514},[599,17003,981],{"class":666},[599,17005,17006],{"class":601,"line":7544},[599,17007,651],{"emptyLinePlaceholder":650},[599,17009,17010,17012,17014,17016,17019],{"class":601,"line":7549},[599,17011,12063],{"class":609},[599,17013,14735],{"class":609},[599,17015,688],{"class":666},[599,17017,17018],{"class":609},"SetDeselected",[599,17020,3717],{"class":666},[599,17022,17023],{"class":601,"line":7561},[599,17024,667],{"class":666},[599,17026,17027],{"class":601,"line":7593},[599,17028,17029],{"class":772},"    \u002F\u002F Do not leave the password or the code in memory once the tile is left.\n",[599,17031,17032,17035],{"class":601,"line":7598},[599,17033,17034],{"class":609},"    _ResetField",[599,17036,17037],{"class":666},"(TFI_PASSWORD);\n",[599,17039,17040,17042],{"class":601,"line":7606},[599,17041,17034],{"class":609},[599,17043,17044],{"class":666},"(TFI_OTP);\n",[599,17046,17047,17049],{"class":601,"line":7626},[599,17048,3551],{"class":605},[599,17050,12172],{"class":666},[599,17052,17053],{"class":601,"line":7635},[599,17054,981],{"class":666},[599,17056,17057],{"class":601,"line":7640},[599,17058,651],{"emptyLinePlaceholder":650},[599,17060,17061,17063,17065,17067,17070,17072,17074,17076],{"class":601,"line":7652},[599,17062,12063],{"class":609},[599,17064,14735],{"class":609},[599,17066,688],{"class":666},[599,17068,17069],{"class":609},"GetFieldState",[599,17071,679],{"class":666},[599,17073,5878],{"class":609},[599,17075,14955],{"class":697},[599,17077,813],{"class":666},[599,17079,17080,17083,17085,17087],{"class":601,"line":7667},[599,17081,17082],{"class":609},"                                             CREDENTIAL_PROVIDER_FIELD_STATE",[599,17084,748],{"class":605},[599,17086,14967],{"class":697},[599,17088,813],{"class":666},[599,17090,17091,17094,17096,17098],{"class":601,"line":7676},[599,17092,17093],{"class":609},"                                             CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE",[599,17095,748],{"class":605},[599,17097,14979],{"class":697},[599,17099,1029],{"class":666},[599,17101,17102],{"class":601,"line":7681},[599,17103,667],{"class":666},[599,17105,17106,17108,17111,17113],{"class":601,"line":7695},[599,17107,3514],{"class":605},[599,17109,17110],{"class":666}," (dwFieldID ",[599,17112,1106],{"class":605},[599,17114,17115],{"class":666}," TFI_NUM_FIELDS)\n",[599,17117,17118,17120],{"class":601,"line":7716},[599,17119,1211],{"class":605},[599,17121,12397],{"class":666},[599,17123,17124,17126,17129,17131],{"class":601,"line":7721},[599,17125,12236],{"class":605},[599,17127,17128],{"class":666},"pcpfs  ",[599,17130,1060],{"class":605},[599,17132,17133],{"class":666}," _rgFieldStatePairs[dwFieldID].cpfs;\n",[599,17135,17136,17138,17141,17143],{"class":601,"line":7727},[599,17137,12236],{"class":605},[599,17139,17140],{"class":666},"pcpfis ",[599,17142,1060],{"class":605},[599,17144,17145],{"class":666}," _rgFieldStatePairs[dwFieldID].cpfis;\n",[599,17147,17148,17150],{"class":601,"line":7733},[599,17149,3551],{"class":605},[599,17151,12172],{"class":666},[599,17153,17154],{"class":601,"line":7760},[599,17155,981],{"class":666},[599,17157,17158],{"class":601,"line":7765},[599,17159,651],{"emptyLinePlaceholder":650},[599,17161,17162,17164,17166,17168,17170,17172,17174,17176,17178,17180,17182,17184],{"class":601,"line":7781},[599,17163,12063],{"class":609},[599,17165,14735],{"class":609},[599,17167,688],{"class":666},[599,17169,13120],{"class":609},[599,17171,679],{"class":666},[599,17173,5878],{"class":609},[599,17175,14955],{"class":697},[599,17177,212],{"class":666},[599,17179,10681],{"class":609},[599,17181,748],{"class":605},[599,17183,15003],{"class":697},[599,17185,1029],{"class":666},[599,17187,17188],{"class":601,"line":7798},[599,17189,667],{"class":666},[599,17191,17192,17194,17196,17198],{"class":601,"line":7808},[599,17193,3514],{"class":605},[599,17195,17110],{"class":666},[599,17197,1106],{"class":605},[599,17199,17115],{"class":666},[599,17201,17202,17204],{"class":601,"line":7817},[599,17203,1211],{"class":605},[599,17205,12397],{"class":666},[599,17207,17208,17210,17212,17215,17217,17220,17222,17224],{"class":601,"line":7822},[599,17209,3551],{"class":605},[599,17211,16387],{"class":609},[599,17213,17214],{"class":666},"(_rgFieldStrings[dwFieldID] ",[599,17216,9412],{"class":605},[599,17218,17219],{"class":666}," _rgFieldStrings[dwFieldID] ",[599,17221,590],{"class":605},[599,17223,16458],{"class":619},[599,17225,17226],{"class":666},", ppwsz);\n",[599,17228,17229],{"class":601,"line":7831},[599,17230,981],{"class":666},[599,17232,17233],{"class":601,"line":7836},[599,17234,651],{"emptyLinePlaceholder":650},[599,17236,17237],{"class":601,"line":7841},[599,17238,17239],{"class":772},"\u002F\u002F The provider logo, drawn in code so no image file is required. A coffee-brown\n",[599,17241,17242],{"class":601,"line":7872},[599,17243,17244],{"class":772},"\u002F\u002F square with \"2FA\". This is only the small icon under \"Sign-in options\"; the\n",[599,17246,17247],{"class":601,"line":7877},[599,17248,17249],{"class":772},"\u002F\u002F large round picture on a user tile is the account picture drawn by Windows.\n",[599,17251,17252,17254,17257,17260],{"class":601,"line":7895},[599,17253,8856],{"class":605},[599,17255,17256],{"class":609}," HBITMAP",[599,17258,17259],{"class":609}," CreateLogo",[599,17261,3717],{"class":666},[599,17263,17264],{"class":601,"line":7908},[599,17265,667],{"class":666},[599,17267,17268,17270,17272,17275,17277,17280],{"class":601,"line":7917},[599,17269,12451],{"class":605},[599,17271,1077],{"class":605},[599,17273,17274],{"class":666}," size ",[599,17276,1060],{"class":605},[599,17278,17279],{"class":949}," 128",[599,17281,1066],{"class":666},[599,17283,17284],{"class":601,"line":7922},[599,17285,651],{"emptyLinePlaceholder":650},[599,17287,17288,17291,17294,17296],{"class":601,"line":7935},[599,17289,17290],{"class":609},"    BITMAPINFO",[599,17292,17293],{"class":666}," bmi ",[599,17295,1060],{"class":605},[599,17297,5921],{"class":666},[599,17299,17300,17303,17305,17307],{"class":601,"line":7958},[599,17301,17302],{"class":666},"    bmi.bmiHeader.biSize     ",[599,17304,1060],{"class":605},[599,17306,6453],{"class":605},[599,17308,17309],{"class":666},"(BITMAPINFOHEADER);\n",[599,17311,17312,17315,17317],{"class":601,"line":7970},[599,17313,17314],{"class":666},"    bmi.bmiHeader.biWidth    ",[599,17316,1060],{"class":605},[599,17318,17319],{"class":666}," size;\n",[599,17321,17322,17325,17327,17329,17332],{"class":601,"line":7982},[599,17323,17324],{"class":666},"    bmi.bmiHeader.biHeight   ",[599,17326,1060],{"class":605},[599,17328,1214],{"class":605},[599,17330,17331],{"class":666},"size;",[599,17333,17334],{"class":772},"   \u002F\u002F top-down\n",[599,17336,17337,17340,17342,17344],{"class":601,"line":7993},[599,17338,17339],{"class":666},"    bmi.bmiHeader.biPlanes   ",[599,17341,1060],{"class":605},[599,17343,973],{"class":949},[599,17345,1066],{"class":666},[599,17347,17348,17351,17353,17355,17357],{"class":601,"line":8002},[599,17349,17350],{"class":666},"    bmi.bmiHeader.biBitCount ",[599,17352,1060],{"class":605},[599,17354,2529],{"class":949},[599,17356,1549],{"class":666},[599,17358,17359],{"class":772},"      \u002F\u002F no alpha channel to worry about\n",[599,17361,17362,17365,17367],{"class":601,"line":8007},[599,17363,17364],{"class":666},"    bmi.bmiHeader.biCompression ",[599,17366,1060],{"class":605},[599,17368,17369],{"class":666}," BI_RGB;\n",[599,17371,17372],{"class":601,"line":8020},[599,17373,651],{"emptyLinePlaceholder":650},[599,17375,17376,17379,17382,17384,17386],{"class":601,"line":8034},[599,17377,17378],{"class":605},"    void*",[599,17380,17381],{"class":666}," pvBits ",[599,17383,1060],{"class":605},[599,17385,1962],{"class":949},[599,17387,1066],{"class":666},[599,17389,17390,17393,17396,17398,17401,17403,17405,17407,17409,17412,17414,17417,17419,17421,17423],{"class":601,"line":8059},[599,17391,17392],{"class":609},"    HBITMAP",[599,17394,17395],{"class":666}," hbmp ",[599,17397,1060],{"class":605},[599,17399,17400],{"class":609}," CreateDIBSection",[599,17402,679],{"class":666},[599,17404,2019],{"class":949},[599,17406,212],{"class":666},[599,17408,694],{"class":605},[599,17410,17411],{"class":666},"bmi, DIB_RGB_COLORS, ",[599,17413,694],{"class":605},[599,17415,17416],{"class":666},"pvBits, ",[599,17418,2019],{"class":949},[599,17420,212],{"class":666},[599,17422,2074],{"class":949},[599,17424,725],{"class":666},[599,17426,17427,17429,17431,17433],{"class":601,"line":8080},[599,17428,3514],{"class":605},[599,17430,1327],{"class":666},[599,17432,2435],{"class":605},[599,17434,17435],{"class":666},"hbmp)\n",[599,17437,17438,17440,17442],{"class":601,"line":8087},[599,17439,1211],{"class":605},[599,17441,1962],{"class":949},[599,17443,1066],{"class":666},[599,17445,17446],{"class":601,"line":8092},[599,17447,651],{"emptyLinePlaceholder":650},[599,17449,17450,17453,17456,17458,17461,17463,17465],{"class":601,"line":8103},[599,17451,17452],{"class":609},"    HDC",[599,17454,17455],{"class":666}," hdc ",[599,17457,1060],{"class":605},[599,17459,17460],{"class":609}," CreateCompatibleDC",[599,17462,679],{"class":666},[599,17464,2019],{"class":949},[599,17466,725],{"class":666},[599,17468,17469,17471,17473,17475],{"class":601,"line":8108},[599,17470,3514],{"class":605},[599,17472,1327],{"class":666},[599,17474,2435],{"class":605},[599,17476,17477],{"class":666},"hdc)\n",[599,17479,17480],{"class":601,"line":8124},[599,17481,1095],{"class":666},[599,17483,17484,17487],{"class":601,"line":8136},[599,17485,17486],{"class":609},"        DeleteObject",[599,17488,17489],{"class":666},"(hbmp);\n",[599,17491,17492,17494,17496],{"class":601,"line":8141},[599,17493,1211],{"class":605},[599,17495,1962],{"class":949},[599,17497,1066],{"class":666},[599,17499,17500],{"class":601,"line":8147},[599,17501,1224],{"class":666},[599,17503,17504],{"class":601,"line":8153},[599,17505,651],{"emptyLinePlaceholder":650},[599,17507,17508,17511,17514,17516,17519],{"class":601,"line":8182},[599,17509,17510],{"class":609},"    HGDIOBJ",[599,17512,17513],{"class":666}," hOldBmp ",[599,17515,1060],{"class":605},[599,17517,17518],{"class":609}," SelectObject",[599,17520,17521],{"class":666},"(hdc, hbmp);\n",[599,17523,17524],{"class":601,"line":8187},[599,17525,651],{"emptyLinePlaceholder":650},[599,17527,17528,17531,17534,17536,17538,17540,17542,17544],{"class":601,"line":8192},[599,17529,17530],{"class":609},"    RECT",[599,17532,17533],{"class":666}," rc ",[599,17535,1060],{"class":605},[599,17537,5873],{"class":666},[599,17539,2074],{"class":949},[599,17541,212],{"class":666},[599,17543,2074],{"class":949},[599,17545,17546],{"class":666},", size, size };\n",[599,17548,17549,17552,17555,17557,17560,17562,17565,17567,17569,17572,17574,17576,17579,17581,17583,17586],{"class":601,"line":8225},[599,17550,17551],{"class":609},"    HBRUSH",[599,17553,17554],{"class":666}," hBrush ",[599,17556,1060],{"class":605},[599,17558,17559],{"class":609}," CreateSolidBrush",[599,17561,679],{"class":666},[599,17563,17564],{"class":609},"RGB",[599,17566,679],{"class":666},[599,17568,11586],{"class":605},[599,17570,17571],{"class":949},"6F",[599,17573,212],{"class":666},[599,17575,11586],{"class":605},[599,17577,17578],{"class":949},"4E",[599,17580,212],{"class":666},[599,17582,11586],{"class":605},[599,17584,17585],{"class":949},"37",[599,17587,9364],{"class":666},[599,17589,17590,17593,17596,17598],{"class":601,"line":8230},[599,17591,17592],{"class":609},"    FillRect",[599,17594,17595],{"class":666},"(hdc, ",[599,17597,694],{"class":605},[599,17599,17600],{"class":666},"rc, hBrush);\n",[599,17602,17603,17606],{"class":601,"line":8243},[599,17604,17605],{"class":609},"    DeleteObject",[599,17607,17608],{"class":666},"(hBrush);\n",[599,17610,17611],{"class":601,"line":8252},[599,17612,651],{"emptyLinePlaceholder":650},[599,17614,17615,17618,17621,17623,17626,17628,17630,17633,17635,17637,17639,17641,17643,17645],{"class":601,"line":8257},[599,17616,17617],{"class":609},"    HFONT",[599,17619,17620],{"class":666}," hFont ",[599,17622,1060],{"class":605},[599,17624,17625],{"class":609}," CreateFontW",[599,17627,679],{"class":666},[599,17629,1132],{"class":605},[599,17631,17632],{"class":949},"48",[599,17634,212],{"class":666},[599,17636,2074],{"class":949},[599,17638,212],{"class":666},[599,17640,2074],{"class":949},[599,17642,212],{"class":666},[599,17644,2074],{"class":949},[599,17646,17647],{"class":666},", FW_SEMIBOLD, FALSE, FALSE, FALSE,\n",[599,17649,17650],{"class":601,"line":8270},[599,17651,17652],{"class":666},"                              DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,\n",[599,17654,17655,17658,17660,17663,17666],{"class":601,"line":8288},[599,17656,17657],{"class":666},"                              ANTIALIASED_QUALITY, DEFAULT_PITCH ",[599,17659,1440],{"class":605},[599,17661,17662],{"class":666}," FF_SWISS, ",[599,17664,17665],{"class":619},"L\"Segoe UI\"",[599,17667,725],{"class":666},[599,17669,17670,17672,17675,17677,17679,17681,17683,17686,17688,17690],{"class":601,"line":8299},[599,17671,17510],{"class":609},[599,17673,17674],{"class":666}," hOldFont ",[599,17676,1060],{"class":605},[599,17678,17620],{"class":666},[599,17680,9412],{"class":605},[599,17682,17518],{"class":609},[599,17684,17685],{"class":666},"(hdc, hFont) ",[599,17687,590],{"class":605},[599,17689,1962],{"class":949},[599,17691,1066],{"class":666},[599,17693,17694,17697],{"class":601,"line":8304},[599,17695,17696],{"class":609},"    SetBkMode",[599,17698,17699],{"class":666},"(hdc, TRANSPARENT);\n",[599,17701,17702,17705,17707,17709,17711,17713,17715,17717,17719,17721,17723,17725,17727],{"class":601,"line":8323},[599,17703,17704],{"class":609},"    SetTextColor",[599,17706,17595],{"class":666},[599,17708,17564],{"class":609},[599,17710,679],{"class":666},[599,17712,11586],{"class":605},[599,17714,2388],{"class":949},[599,17716,212],{"class":666},[599,17718,11586],{"class":605},[599,17720,2388],{"class":949},[599,17722,212],{"class":666},[599,17724,11586],{"class":605},[599,17726,2388],{"class":949},[599,17728,9364],{"class":666},[599,17730,17731,17734,17736,17739,17741,17743,17745,17747,17749,17752,17754,17757,17759],{"class":601,"line":8343},[599,17732,17733],{"class":609},"    DrawTextW",[599,17735,17595],{"class":666},[599,17737,17738],{"class":619},"L\"2FA\"",[599,17740,212],{"class":666},[599,17742,1132],{"class":605},[599,17744,1217],{"class":949},[599,17746,212],{"class":666},[599,17748,694],{"class":605},[599,17750,17751],{"class":666},"rc, DT_CENTER ",[599,17753,1440],{"class":605},[599,17755,17756],{"class":666}," DT_VCENTER ",[599,17758,1440],{"class":605},[599,17760,17761],{"class":666}," DT_SINGLELINE);\n",[599,17763,17764],{"class":601,"line":8355},[599,17765,651],{"emptyLinePlaceholder":650},[599,17767,17768,17770],{"class":601,"line":8362},[599,17769,3514],{"class":605},[599,17771,17772],{"class":666}," (hOldFont)\n",[599,17774,17775,17778],{"class":601,"line":8367},[599,17776,17777],{"class":609},"        SelectObject",[599,17779,17780],{"class":666},"(hdc, hOldFont);\n",[599,17782,17783,17785],{"class":601,"line":8378},[599,17784,3514],{"class":605},[599,17786,17787],{"class":666}," (hFont)\n",[599,17789,17790,17792],{"class":601,"line":8383},[599,17791,17486],{"class":609},[599,17793,17794],{"class":666},"(hFont);\n",[599,17796,17797,17800],{"class":601,"line":8388},[599,17798,17799],{"class":609},"    SelectObject",[599,17801,17802],{"class":666},"(hdc, hOldBmp);\n",[599,17804,17805,17808],{"class":601,"line":8411},[599,17806,17807],{"class":609},"    DeleteDC",[599,17809,17810],{"class":666},"(hdc);\n",[599,17812,17813,17816],{"class":601,"line":8416},[599,17814,17815],{"class":609},"    GdiFlush",[599,17817,1313],{"class":666},[599,17819,17820,17822],{"class":601,"line":8429},[599,17821,3551],{"class":605},[599,17823,17824],{"class":666}," hbmp;\n",[599,17826,17827],{"class":601,"line":8438},[599,17828,981],{"class":666},[599,17830,17831],{"class":601,"line":8443},[599,17832,651],{"emptyLinePlaceholder":650},[599,17834,17835,17837,17839,17841,17844,17846,17848,17850,17852,17854,17856,17858],{"class":601,"line":8456},[599,17836,12063],{"class":609},[599,17838,14735],{"class":609},[599,17840,688],{"class":666},[599,17842,17843],{"class":609},"GetBitmapValue",[599,17845,679],{"class":666},[599,17847,5878],{"class":609},[599,17849,14955],{"class":697},[599,17851,212],{"class":666},[599,17853,15023],{"class":609},[599,17855,748],{"class":605},[599,17857,15028],{"class":697},[599,17859,1029],{"class":666},[599,17861,17862],{"class":601,"line":8478},[599,17863,667],{"class":666},[599,17865,17866,17868,17870,17872,17875,17877,17879],{"class":601,"line":8489},[599,17867,3514],{"class":605},[599,17869,17110],{"class":666},[599,17871,2030],{"class":605},[599,17873,17874],{"class":666}," TFI_TILEIMAGE ",[599,17876,6568],{"class":605},[599,17878,9609],{"class":605},[599,17880,17881],{"class":666},"phbmp)\n",[599,17883,17884,17886],{"class":601,"line":8498},[599,17885,1211],{"class":605},[599,17887,12397],{"class":666},[599,17889,17890],{"class":601,"line":8509},[599,17891,651],{"emptyLinePlaceholder":650},[599,17893,17894,17896,17898,17900,17902],{"class":601,"line":8518},[599,17895,17392],{"class":609},[599,17897,17395],{"class":666},[599,17899,1060],{"class":605},[599,17901,17259],{"class":609},[599,17903,1313],{"class":666},[599,17905,17906,17908,17910,17912],{"class":601,"line":8523},[599,17907,3514],{"class":605},[599,17909,1327],{"class":666},[599,17911,2435],{"class":605},[599,17913,17435],{"class":666},[599,17915,17916,17918],{"class":601,"line":8539},[599,17917,1211],{"class":605},[599,17919,17920],{"class":666}," E_FAIL;\n",[599,17922,17923],{"class":601,"line":8546},[599,17924,651],{"emptyLinePlaceholder":650},[599,17926,17927,17929,17932,17934,17937],{"class":601,"line":8566},[599,17928,12236],{"class":605},[599,17930,17931],{"class":666},"phbmp ",[599,17933,1060],{"class":605},[599,17935,17936],{"class":666}," hbmp;",[599,17938,17939],{"class":772},"   \u002F\u002F LogonUI takes ownership and deletes it\n",[599,17941,17942,17944],{"class":601,"line":8571},[599,17943,3551],{"class":605},[599,17945,12172],{"class":666},[599,17947,17948],{"class":601,"line":14025},[599,17949,981],{"class":666},[599,17951,17952],{"class":601,"line":14030},[599,17953,651],{"emptyLinePlaceholder":650},[599,17955,17956,17958,17960,17962,17965,17967,17969,17971,17973,17975,17977,17979],{"class":601,"line":14049},[599,17957,12063],{"class":609},[599,17959,14735],{"class":609},[599,17961,688],{"class":666},[599,17963,17964],{"class":609},"GetSubmitButtonValue",[599,17966,679],{"class":666},[599,17968,5878],{"class":609},[599,17970,14955],{"class":697},[599,17972,212],{"class":666},[599,17974,5878],{"class":609},[599,17976,748],{"class":605},[599,17978,15085],{"class":697},[599,17980,1029],{"class":666},[599,17982,17983],{"class":601,"line":14061},[599,17984,667],{"class":666},[599,17986,17987,17989,17991,17993,17996,17998,18000],{"class":601,"line":14066},[599,17988,3514],{"class":605},[599,17990,17110],{"class":666},[599,17992,2030],{"class":605},[599,17994,17995],{"class":666}," TFI_SUBMIT ",[599,17997,6568],{"class":605},[599,17999,9609],{"class":605},[599,18001,18002],{"class":666},"pdwAdjacentTo)\n",[599,18004,18005,18007],{"class":601,"line":14086},[599,18006,1211],{"class":605},[599,18008,12397],{"class":666},[599,18010,18011,18013,18016,18018,18021],{"class":601,"line":14093},[599,18012,12236],{"class":605},[599,18014,18015],{"class":666},"pdwAdjacentTo ",[599,18017,1060],{"class":605},[599,18019,18020],{"class":666}," TFI_OTP;",[599,18022,18023],{"class":772},"   \u002F\u002F the arrow sits next to the code field\n",[599,18025,18026,18028],{"class":601,"line":14104},[599,18027,3551],{"class":605},[599,18029,12172],{"class":666},[599,18031,18032],{"class":601,"line":14109},[599,18033,981],{"class":666},[599,18035,18036],{"class":601,"line":14114},[599,18037,651],{"emptyLinePlaceholder":650},[599,18039,18040,18042,18044,18046,18048,18050,18052,18054,18056,18058,18060],{"class":601,"line":14143},[599,18041,12063],{"class":609},[599,18043,14735],{"class":609},[599,18045,688],{"class":666},[599,18047,233],{"class":609},[599,18049,679],{"class":666},[599,18051,5878],{"class":609},[599,18053,14955],{"class":697},[599,18055,212],{"class":666},[599,18057,11361],{"class":609},[599,18059,15171],{"class":697},[599,18061,1029],{"class":666},[599,18063,18064],{"class":601,"line":14155},[599,18065,667],{"class":666},[599,18067,18068,18070,18072,18074,18077,18079,18082,18084,18087,18089,18091,18093],{"class":601,"line":14160},[599,18069,3514],{"class":605},[599,18071,17110],{"class":666},[599,18073,2030],{"class":605},[599,18075,18076],{"class":666}," TFI_USERNAME ",[599,18078,3154],{"class":605},[599,18080,18081],{"class":666}," dwFieldID ",[599,18083,2030],{"class":605},[599,18085,18086],{"class":666}," TFI_PASSWORD ",[599,18088,3154],{"class":605},[599,18090,18081],{"class":666},[599,18092,2030],{"class":605},[599,18094,18095],{"class":666}," TFI_OTP)\n",[599,18097,18098,18100],{"class":601,"line":14168},[599,18099,1211],{"class":605},[599,18101,12397],{"class":666},[599,18103,18104,18106],{"class":601,"line":14190},[599,18105,16029],{"class":609},[599,18107,16032],{"class":666},[599,18109,18110,18112,18114,18117,18119,18122,18124,18126,18128,18130],{"class":601,"line":14203},[599,18111,3551],{"class":605},[599,18113,16387],{"class":609},[599,18115,18116],{"class":666},"(pwz ",[599,18118,9412],{"class":605},[599,18120,18121],{"class":666}," pwz ",[599,18123,590],{"class":605},[599,18125,16458],{"class":619},[599,18127,212],{"class":666},[599,18129,694],{"class":605},[599,18131,16048],{"class":666},[599,18133,18134],{"class":601,"line":14216},[599,18135,981],{"class":666},[599,18137,18138],{"class":601,"line":14223},[599,18139,651],{"emptyLinePlaceholder":650},[599,18141,18142],{"class":601,"line":14228},[599,18143,18144],{"class":772},"\u002F\u002F Our tile has no checkbox or combo box fields.\n",[599,18146,18147,18149,18151,18153,18156,18158,18160,18162,18164,18166,18168,18170,18172,18175,18177],{"class":601,"line":14233},[599,18148,12063],{"class":609},[599,18150,14735],{"class":609},[599,18152,688],{"class":666},[599,18154,18155],{"class":609},"GetCheckboxValue",[599,18157,679],{"class":666},[599,18159,5878],{"class":609},[599,18161,212],{"class":666},[599,18163,11218],{"class":609},[599,18165,748],{"class":605},[599,18167,212],{"class":666},[599,18169,10681],{"class":609},[599,18171,748],{"class":605},[599,18173,18174],{"class":666},")       { ",[599,18176,1127],{"class":605},[599,18178,18179],{"class":666}," E_NOTIMPL; }\n",[599,18181,18182,18184,18186,18188,18191,18193,18195,18197,18199,18201,18203,18205,18207,18209,18211],{"class":601,"line":14252},[599,18183,12063],{"class":609},[599,18185,14735],{"class":609},[599,18187,688],{"class":666},[599,18189,18190],{"class":609},"GetComboBoxValueCount",[599,18192,679],{"class":666},[599,18194,5878],{"class":609},[599,18196,212],{"class":666},[599,18198,5878],{"class":609},[599,18200,748],{"class":605},[599,18202,212],{"class":666},[599,18204,5878],{"class":609},[599,18206,748],{"class":605},[599,18208,13949],{"class":666},[599,18210,1127],{"class":605},[599,18212,18179],{"class":666},[599,18214,18215,18217,18219,18221,18224,18226,18228,18230,18232,18234,18236,18238,18241,18243],{"class":601,"line":14264},[599,18216,12063],{"class":609},[599,18218,14735],{"class":609},[599,18220,688],{"class":666},[599,18222,18223],{"class":609},"GetComboBoxValueAt",[599,18225,679],{"class":666},[599,18227,5878],{"class":609},[599,18229,212],{"class":666},[599,18231,5878],{"class":609},[599,18233,212],{"class":666},[599,18235,10681],{"class":609},[599,18237,748],{"class":605},[599,18239,18240],{"class":666},")     { ",[599,18242,1127],{"class":605},[599,18244,18179],{"class":666},[599,18246,18247,18249,18251,18253,18256,18258,18260,18262,18264,18267,18269],{"class":601,"line":14269},[599,18248,12063],{"class":609},[599,18250,14735],{"class":609},[599,18252,688],{"class":666},[599,18254,18255],{"class":609},"SetCheckboxValue",[599,18257,679],{"class":666},[599,18259,5878],{"class":609},[599,18261,212],{"class":666},[599,18263,11218],{"class":609},[599,18265,18266],{"class":666},")                { ",[599,18268,1127],{"class":605},[599,18270,18179],{"class":666},[599,18272,18273,18275,18277,18279,18282,18284,18286,18288,18290,18292,18294],{"class":601,"line":14281},[599,18274,12063],{"class":609},[599,18276,14735],{"class":609},[599,18278,688],{"class":666},[599,18280,18281],{"class":609},"SetComboBoxSelectedValue",[599,18283,679],{"class":666},[599,18285,5878],{"class":609},[599,18287,212],{"class":666},[599,18289,5878],{"class":609},[599,18291,18174],{"class":666},[599,18293,1127],{"class":605},[599,18295,18179],{"class":666},[599,18297,18298,18300,18302,18304,18307,18309,18311,18314,18316],{"class":601,"line":14288},[599,18299,12063],{"class":609},[599,18301,14735],{"class":609},[599,18303,688],{"class":666},[599,18305,18306],{"class":609},"CommandLinkClicked",[599,18308,679],{"class":666},[599,18310,5878],{"class":609},[599,18312,18313],{"class":666},")                    { ",[599,18315,1127],{"class":605},[599,18317,18179],{"class":666},[599,18319,18320],{"class":601,"line":14295},[599,18321,651],{"emptyLinePlaceholder":650},[599,18323,18324],{"class":601,"line":14311},[599,18325,18326],{"class":772},"\u002F\u002F --- ICredentialProviderCredential2 -----------------------------------------\n",[599,18328,18329],{"class":601,"line":14318},[599,18330,651],{"emptyLinePlaceholder":650},[599,18332,18333],{"class":601,"line":14336},[599,18334,18335],{"class":772},"\u002F\u002F Returning a SID binds the tile to that account, so Windows shows its name and\n",[599,18337,18338],{"class":601,"line":14341},[599,18339,18340],{"class":772},"\u002F\u002F round picture. The fallback and RDP tiles have no SID and return S_FALSE,\n",[599,18342,18343],{"class":601,"line":14346},[599,18344,18345],{"class":772},"\u002F\u002F which makes them a generic tile with a username field.\n",[599,18347,18348,18350,18352,18354,18356,18358,18360,18362,18364],{"class":601,"line":14352},[599,18349,12063],{"class":609},[599,18351,14735],{"class":609},[599,18353,688],{"class":666},[599,18355,247],{"class":609},[599,18357,679],{"class":666},[599,18359,10681],{"class":609},[599,18361,748],{"class":605},[599,18363,15357],{"class":697},[599,18365,1029],{"class":666},[599,18367,18368],{"class":601,"line":14357},[599,18369,667],{"class":666},[599,18371,18372,18374,18376,18378],{"class":601,"line":14378},[599,18373,3514],{"class":605},[599,18375,1327],{"class":666},[599,18377,2435],{"class":605},[599,18379,18380],{"class":666},"ppszSid)\n",[599,18382,18383,18385],{"class":601,"line":14383},[599,18384,1211],{"class":605},[599,18386,12106],{"class":666},[599,18388,18389,18391,18394,18396,18398],{"class":601,"line":14390},[599,18390,12236],{"class":605},[599,18392,18393],{"class":666},"ppszSid ",[599,18395,1060],{"class":605},[599,18397,1962],{"class":949},[599,18399,1066],{"class":666},[599,18401,18402,18404,18406,18408],{"class":601,"line":14399},[599,18403,3514],{"class":605},[599,18405,1327],{"class":666},[599,18407,2435],{"class":605},[599,18409,18410],{"class":666},"_pszSid)\n",[599,18412,18413,18415],{"class":601,"line":14410},[599,18414,1211],{"class":605},[599,18416,18417],{"class":666}," S_FALSE;\n",[599,18419,18420,18422,18424],{"class":601,"line":14417},[599,18421,3551],{"class":605},[599,18423,16387],{"class":609},[599,18425,18426],{"class":666},"(_pszSid, ppszSid);\n",[599,18428,18429],{"class":601,"line":14426},[599,18430,981],{"class":666},[599,18432,18433],{"class":601,"line":14437},[599,18434,651],{"emptyLinePlaceholder":650},[599,18436,18437],{"class":601,"line":14444},[599,18438,18439],{"class":772},"\u002F\u002F --- the actual work: check the code, then serialize the password -----------\n",[599,18441,18442],{"class":601,"line":14449},[599,18443,651],{"emptyLinePlaceholder":650},[599,18445,18446,18448,18450,18452,18454],{"class":601,"line":14454},[599,18447,12063],{"class":609},[599,18449,14735],{"class":609},[599,18451,688],{"class":666},[599,18453,237],{"class":609},[599,18455,13310],{"class":666},[599,18457,18458,18461,18463,18465],{"class":601,"line":14475},[599,18459,18460],{"class":609},"    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE",[599,18462,748],{"class":605},[599,18464,15249],{"class":697},[599,18466,813],{"class":666},[599,18468,18469,18472,18474,18476],{"class":601,"line":14480},[599,18470,18471],{"class":609},"    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION",[599,18473,748],{"class":605},[599,18475,11107],{"class":697},[599,18477,813],{"class":666},[599,18479,18480,18482,18484,18486],{"class":601,"line":14504},[599,18481,15449],{"class":609},[599,18483,748],{"class":605},[599,18485,15272],{"class":697},[599,18487,813],{"class":666},[599,18489,18490,18493,18495,18497],{"class":601,"line":14516},[599,18491,18492],{"class":609},"    CREDENTIAL_PROVIDER_STATUS_ICON",[599,18494,748],{"class":605},[599,18496,15284],{"class":697},[599,18498,1029],{"class":666},[599,18500,18501],{"class":601,"line":14523},[599,18502,667],{"class":666},[599,18504,18505,18507,18510,18512],{"class":601,"line":14540},[599,18506,12236],{"class":605},[599,18508,18509],{"class":666},"pcpgsr ",[599,18511,1060],{"class":605},[599,18513,18514],{"class":666}," CPGSR_NO_CREDENTIAL_NOT_FINISHED;\n",[599,18516,18517,18520,18522,18524],{"class":601,"line":14550},[599,18518,18519],{"class":666},"    pcpcs->rgbSerialization ",[599,18521,1060],{"class":605},[599,18523,1962],{"class":949},[599,18525,1066],{"class":666},[599,18527,18528,18531,18533,18535],{"class":601,"line":14557},[599,18529,18530],{"class":666},"    pcpcs->cbSerialization  ",[599,18532,1060],{"class":605},[599,18534,1286],{"class":949},[599,18536,1066],{"class":666},[599,18538,18540],{"class":601,"line":18539},311,[599,18541,651],{"emptyLinePlaceholder":650},[599,18543,18545],{"class":601,"line":18544},312,[599,18546,18547],{"class":772},"    \u002F\u002F The username field holds \"PC\\user\" on a user tile, or whatever was typed\n",[599,18549,18551],{"class":601,"line":18550},313,[599,18552,18553],{"class":772},"    \u002F\u002F on the fallback tile. We only ever use the bare name, so the account we\n",[599,18555,18557],{"class":601,"line":18556},314,[599,18558,18559],{"class":772},"    \u002F\u002F check the code for is the same local account we log on below.\n",[599,18561,18563,18565,18567,18569,18572,18574,18577,18579,18581,18583,18585],{"class":601,"line":18562},315,[599,18564,731],{"class":609},[599,18566,688],{"class":666},[599,18568,902],{"class":609},[599,18570,18571],{"class":666}," bare ",[599,18573,1060],{"class":605},[599,18575,18576],{"class":666}," _rgFieldStrings[TFI_USERNAME] ",[599,18578,9412],{"class":605},[599,18580,18576],{"class":666},[599,18582,590],{"class":605},[599,18584,16458],{"class":619},[599,18586,1066],{"class":666},[599,18588,18590,18592,18594,18596,18599,18601,18603,18605,18607,18609],{"class":601,"line":18589},316,[599,18591,12565],{"class":605},[599,18593,12456],{"class":666},[599,18595,1060],{"class":605},[599,18597,18598],{"class":666}," bare.",[599,18600,5715],{"class":609},[599,18602,679],{"class":666},[599,18604,5720],{"class":619},[599,18606,5576],{"class":949},[599,18608,5725],{"class":619},[599,18610,725],{"class":666},[599,18612,18614,18616,18619,18621,18623,18625,18627],{"class":601,"line":18613},317,[599,18615,3514],{"class":605},[599,18617,18618],{"class":666}," (slash ",[599,18620,2030],{"class":605},[599,18622,685],{"class":609},[599,18624,688],{"class":666},[599,18626,902],{"class":609},[599,18628,5745],{"class":666},[599,18630,18632,18635,18638,18640,18642,18645,18647,18649],{"class":601,"line":18631},318,[599,18633,18634],{"class":666},"        bare.",[599,18636,18637],{"class":609},"erase",[599,18639,679],{"class":666},[599,18641,2074],{"class":949},[599,18643,18644],{"class":666},", slash ",[599,18646,2543],{"class":605},[599,18648,973],{"class":949},[599,18650,725],{"class":666},[599,18652,18654],{"class":601,"line":18653},319,[599,18655,651],{"emptyLinePlaceholder":650},[599,18657,18659],{"class":601,"line":18658},320,[599,18660,18661],{"class":772},"    \u002F\u002F --- which account is this? ---\n",[599,18663,18665],{"class":601,"line":18664},321,[599,18666,18667],{"class":772},"    \u002F\u002F The secret belongs to a SID. We resolve COMPUTERNAME\\name exactly like\n",[599,18669,18671],{"class":601,"line":18670},322,[599,18672,18673],{"class":772},"    \u002F\u002F LSA will. On a user tile the result has to be the SID of the tile.\n",[599,18675,18677,18679,18681,18683],{"class":601,"line":18676},323,[599,18678,731],{"class":609},[599,18680,688],{"class":666},[599,18682,902],{"class":609},[599,18684,9718],{"class":666},[599,18686,18688,18690,18693,18695,18697,18699,18701],{"class":601,"line":18687},324,[599,18689,673],{"class":605},[599,18691,18692],{"class":666}," known ",[599,18694,1060],{"class":605},[599,18696,9688],{"class":609},[599,18698,688],{"class":666},[599,18700,8717],{"class":609},[599,18702,18703],{"class":666},"(bare, sid);\n",[599,18705,18707,18709,18712,18714,18717,18719,18721,18724,18726,18729,18731,18733],{"class":601,"line":18706},325,[599,18708,3514],{"class":605},[599,18710,18711],{"class":666}," (known ",[599,18713,3154],{"class":605},[599,18715,18716],{"class":666}," _pszSid ",[599,18718,3154],{"class":605},[599,18720,6571],{"class":609},[599,18722,18723],{"class":666},"(sid.",[599,18725,6513],{"class":609},[599,18727,18728],{"class":666},"(), _pszSid) ",[599,18730,2030],{"class":605},[599,18732,1286],{"class":949},[599,18734,1029],{"class":666},[599,18736,18738,18741,18743,18745],{"class":601,"line":18737},326,[599,18739,18740],{"class":666},"        known ",[599,18742,1060],{"class":605},[599,18744,1411],{"class":949},[599,18746,1066],{"class":666},[599,18748,18750],{"class":601,"line":18749},327,[599,18751,651],{"emptyLinePlaceholder":650},[599,18753,18755,18757,18759,18761,18763,18766,18768,18770,18772,18775,18777,18779,18781,18783,18785,18787,18789,18791,18793,18796,18799,18801,18804],{"class":601,"line":18754},328,[599,18756,12451],{"class":605},[599,18758,685],{"class":609},[599,18760,688],{"class":666},[599,18762,902],{"class":609},[599,18764,18765],{"class":666}," who     ",[599,18767,1060],{"class":605},[599,18769,18571],{"class":666},[599,18771,2543],{"class":605},[599,18773,18774],{"class":619}," L\" (\"",[599,18776,1201],{"class":605},[599,18778,18711],{"class":666},[599,18780,9412],{"class":605},[599,18782,13158],{"class":666},[599,18784,590],{"class":605},[599,18786,685],{"class":609},[599,18788,688],{"class":666},[599,18790,902],{"class":609},[599,18792,679],{"class":666},[599,18794,18795],{"class":619},"L\"unknown account\"",[599,18797,18798],{"class":666},")) ",[599,18800,2543],{"class":605},[599,18802,18803],{"class":619}," L\")\"",[599,18805,1066],{"class":666},[599,18807,18809,18811,18813,18815,18817,18820,18822,18824,18826,18829],{"class":601,"line":18808},329,[599,18810,12451],{"class":605},[599,18812,685],{"class":609},[599,18814,688],{"class":666},[599,18816,902],{"class":609},[599,18818,18819],{"class":666}," session ",[599,18821,1060],{"class":605},[599,18823,9688],{"class":609},[599,18825,688],{"class":666},[599,18827,18828],{"class":609},"DescribeSession",[599,18830,1313],{"class":666},[599,18832,18834],{"class":601,"line":18833},330,[599,18835,651],{"emptyLinePlaceholder":650},[599,18837,18839],{"class":601,"line":18838},331,[599,18840,18841],{"class":772},"    \u002F\u002F --- the second factor ---\n",[599,18843,18845,18847,18849,18851,18854,18856,18859,18861,18863,18865,18867],{"class":601,"line":18844},332,[599,18846,731],{"class":609},[599,18848,688],{"class":666},[599,18850,902],{"class":609},[599,18852,18853],{"class":666}," code ",[599,18855,1060],{"class":605},[599,18857,18858],{"class":666}," _rgFieldStrings[TFI_OTP] ",[599,18860,9412],{"class":605},[599,18862,18858],{"class":666},[599,18864,590],{"class":605},[599,18866,16458],{"class":619},[599,18868,1066],{"class":666},[599,18870,18872,18874,18876,18879,18882,18884],{"class":601,"line":18871},333,[599,18873,9269],{"class":609},[599,18875,688],{"class":666},[599,18877,18878],{"class":609},"OtpInfo",[599,18880,18881],{"class":666}," info ",[599,18883,1060],{"class":605},[599,18885,5921],{"class":666},[599,18887,18889,18891,18893,18896,18899,18901],{"class":601,"line":18888},334,[599,18890,9269],{"class":609},[599,18892,688],{"class":666},[599,18894,18895],{"class":609},"OtpResult",[599,18897,18898],{"class":666}," result ",[599,18900,1060],{"class":605},[599,18902,18903],{"class":666}," known\n",[599,18905,18907,18910,18912,18914,18917,18920,18923,18925,18927,18929,18931],{"class":601,"line":18906},335,[599,18908,18909],{"class":605},"        ?",[599,18911,9688],{"class":609},[599,18913,688],{"class":666},[599,18915,18916],{"class":609},"VerifyOtp",[599,18918,18919],{"class":666},"(sid, code, ",[599,18921,18922],{"class":605},"static_cast\u003Cuint64_t>",[599,18924,679],{"class":666},[599,18926,9357],{"class":609},[599,18928,679],{"class":666},[599,18930,2019],{"class":949},[599,18932,18933],{"class":666},")), info)\n",[599,18935,18937,18940,18942,18944,18946],{"class":601,"line":18936},336,[599,18938,18939],{"class":605},"        :",[599,18941,9688],{"class":609},[599,18943,688],{"class":666},[599,18945,18895],{"class":609},[599,18947,18948],{"class":666},"::NotEnrolled;\n",[599,18950,18952,18954,18956,18958,18961,18963],{"class":601,"line":18951},337,[599,18953,3514],{"class":605},[599,18955,1327],{"class":666},[599,18957,2435],{"class":605},[599,18959,18960],{"class":666},"code.",[599,18962,6322],{"class":609},[599,18964,6325],{"class":666},[599,18966,18968,18970,18972,18974,18977,18979,18982,18984,18986,18988,18990],{"class":601,"line":18967},338,[599,18969,6213],{"class":609},[599,18971,679],{"class":666},[599,18973,694],{"class":605},[599,18975,18976],{"class":666},"code[",[599,18978,2074],{"class":949},[599,18980,18981],{"class":666},"], code.",[599,18983,2108],{"class":609},[599,18985,2840],{"class":666},[599,18987,748],{"class":605},[599,18989,6453],{"class":605},[599,18991,11824],{"class":666},[599,18993,18995],{"class":601,"line":18994},339,[599,18996,651],{"emptyLinePlaceholder":650},[599,18998,19000,19002,19005,19007,19009,19011,19013],{"class":601,"line":18999},340,[599,19001,3514],{"class":605},[599,19003,19004],{"class":666}," (result ",[599,19006,2030],{"class":605},[599,19008,9688],{"class":609},[599,19010,688],{"class":666},[599,19012,18895],{"class":609},[599,19014,19015],{"class":666},"::Ok)\n",[599,19017,19019],{"class":601,"line":19018},341,[599,19020,1095],{"class":666},[599,19022,19024],{"class":601,"line":19023},342,[599,19025,19026],{"class":772},"        \u002F\u002F \"Not enrolled\", \"wrong\" and \"already used\" look the same on screen,\n",[599,19028,19030],{"class":601,"line":19029},343,[599,19031,19032],{"class":772},"        \u002F\u002F so the screen never reveals who is enrolled. Only the lock gets its\n",[599,19034,19036],{"class":601,"line":19035},344,[599,19037,19038],{"class":772},"        \u002F\u002F own message, otherwise a locked user would keep typing valid codes.\n",[599,19040,19042,19045,19048,19050,19053],{"class":601,"line":19041},345,[599,19043,19044],{"class":609},"        PCWSTR",[599,19046,19047],{"class":666}," message ",[599,19049,1060],{"class":605},[599,19051,19052],{"class":619}," L\"Invalid one-time code.\"",[599,19054,1066],{"class":666},[599,19056,19058,19061,19064,19067],{"class":601,"line":19057},346,[599,19059,19060],{"class":605},"        wchar_t",[599,19062,19063],{"class":666}," lockText[",[599,19065,19066],{"class":949},"128",[599,19068,1784],{"class":666},[599,19070,19072],{"class":601,"line":19071},347,[599,19073,651],{"emptyLinePlaceholder":650},[599,19075,19077,19080],{"class":601,"line":19076},348,[599,19078,19079],{"class":605},"        switch",[599,19081,19082],{"class":666}," (result)\n",[599,19084,19086],{"class":601,"line":19085},349,[599,19087,1338],{"class":666},[599,19089,19091,19094,19096,19098,19100],{"class":601,"line":19090},350,[599,19092,19093],{"class":605},"        case",[599,19095,9688],{"class":609},[599,19097,688],{"class":666},[599,19099,18895],{"class":609},[599,19101,19102],{"class":666},"::Wrong:\n",[599,19104,19106,19108,19110,19112,19114],{"class":601,"line":19105},351,[599,19107,19093],{"class":605},[599,19109,9688],{"class":609},[599,19111,688],{"class":666},[599,19113,18895],{"class":609},[599,19115,19116],{"class":666},"::Replayed:\n",[599,19118,19120,19123,19125,19128],{"class":601,"line":19119},352,[599,19121,19122],{"class":609},"            tac",[599,19124,688],{"class":666},[599,19126,19127],{"class":609},"LogEvent",[599,19129,19130],{"class":666},"(EVENTLOG_WARNING_TYPE,\n",[599,19132,19134,19137,19139,19141,19143,19145,19148,19150,19152,19155,19157,19159],{"class":601,"line":19133},353,[599,19135,19136],{"class":666},"                          result ",[599,19138,1349],{"class":605},[599,19140,9688],{"class":609},[599,19142,688],{"class":666},[599,19144,18895],{"class":609},[599,19146,19147],{"class":666},"::Wrong ",[599,19149,9412],{"class":605},[599,19151,9688],{"class":609},[599,19153,19154],{"class":666},"::EVT_CODE_WRONG ",[599,19156,590],{"class":605},[599,19158,9688],{"class":609},[599,19160,19161],{"class":666},"::EVT_CODE_REPLAYED,\n",[599,19163,19165,19168,19170,19172,19174,19176,19178,19180],{"class":601,"line":19164},354,[599,19166,19167],{"class":666},"                          (result ",[599,19169,1349],{"class":605},[599,19171,9688],{"class":609},[599,19173,688],{"class":666},[599,19175,18895],{"class":609},[599,19177,19147],{"class":666},[599,19179,9412],{"class":605},[599,19181,19182],{"class":619}," L\"Wrong one-time code for \"\n",[599,19184,19186,19189,19192,19194],{"class":601,"line":19185},355,[599,19187,19188],{"class":605},"                                                           :",[599,19190,19191],{"class":619}," L\"Already used one-time code for \"",[599,19193,1124],{"class":666},[599,19195,10195],{"class":605},[599,19197,19199,19202,19204,19207,19209,19211,19213,19216,19219],{"class":601,"line":19198},356,[599,19200,19201],{"class":666},"                              who ",[599,19203,2543],{"class":605},[599,19205,19206],{"class":619}," L\". Wrong codes in a row: \"",[599,19208,1201],{"class":605},[599,19210,685],{"class":609},[599,19212,688],{"class":666},[599,19214,19215],{"class":609},"to_wstring",[599,19217,19218],{"class":666},"(info.failures) ",[599,19220,10195],{"class":605},[599,19222,19224,19227,19229,19231,19233,19236],{"class":601,"line":19223},357,[599,19225,19226],{"class":619},"                              L\". \"",[599,19228,1201],{"class":605},[599,19230,18819],{"class":666},[599,19232,2543],{"class":605},[599,19234,19235],{"class":619}," L\".\"",[599,19237,725],{"class":666},[599,19239,19241,19243],{"class":601,"line":19240},358,[599,19242,1344],{"class":605},[599,19244,19245],{"class":666}," (info.minutesLeft)\n",[599,19247,19249],{"class":601,"line":19248},359,[599,19250,1480],{"class":666},[599,19252,19254,19257,19259,19261,19264,19266],{"class":601,"line":19253},360,[599,19255,19256],{"class":609},"                tac",[599,19258,688],{"class":666},[599,19260,19127],{"class":609},[599,19262,19263],{"class":666},"(EVENTLOG_ERROR_TYPE, ",[599,19265,9287],{"class":609},[599,19267,19268],{"class":666},"::EVT_LOCK_STARTED,\n",[599,19270,19272,19275,19277,19280,19282,19285,19287,19289,19291,19293,19296],{"class":601,"line":19271},361,[599,19273,19274],{"class":619},"                              L\"Account \"",[599,19276,1201],{"class":605},[599,19278,19279],{"class":666}," who ",[599,19281,2543],{"class":605},[599,19283,19284],{"class":619}," L\" locked for \"",[599,19286,1201],{"class":605},[599,19288,685],{"class":609},[599,19290,688],{"class":666},[599,19292,19215],{"class":609},[599,19294,19295],{"class":666},"(info.minutesLeft) ",[599,19297,10195],{"class":605},[599,19299,19301,19304,19306,19308,19310,19312,19314],{"class":601,"line":19300},362,[599,19302,19303],{"class":619},"                                  L\" minutes after \"",[599,19305,1201],{"class":605},[599,19307,685],{"class":609},[599,19309,688],{"class":666},[599,19311,19215],{"class":609},[599,19313,19218],{"class":666},[599,19315,10195],{"class":605},[599,19317,19319,19322,19324,19326,19328,19330],{"class":601,"line":19318},363,[599,19320,19321],{"class":619},"                                  L\" wrong codes in a row. \"",[599,19323,1201],{"class":605},[599,19325,18819],{"class":666},[599,19327,2543],{"class":605},[599,19329,19235],{"class":619},[599,19331,725],{"class":666},[599,19333,19335,19338,19341,19344,19346,19349],{"class":601,"line":19334},364,[599,19336,19337],{"class":609},"                swprintf_s",[599,19339,19340],{"class":666},"(lockText, ",[599,19342,19343],{"class":619},"L\"Too many wrong codes. Try again in ",[599,19345,9382],{"class":949},[599,19347,19348],{"class":619}," minutes.\"",[599,19350,19351],{"class":666},", info.minutesLeft);\n",[599,19353,19355,19358,19360],{"class":601,"line":19354},365,[599,19356,19357],{"class":666},"                message ",[599,19359,1060],{"class":605},[599,19361,19362],{"class":666}," lockText;\n",[599,19364,19366],{"class":601,"line":19365},366,[599,19367,1558],{"class":666},[599,19369,19371,19374],{"class":601,"line":19370},367,[599,19372,19373],{"class":605},"            break",[599,19375,1066],{"class":666},[599,19377,19379],{"class":601,"line":19378},368,[599,19380,651],{"emptyLinePlaceholder":650},[599,19382,19384,19386,19388,19390,19392],{"class":601,"line":19383},369,[599,19385,19093],{"class":605},[599,19387,9688],{"class":609},[599,19389,688],{"class":666},[599,19391,18895],{"class":609},[599,19393,19394],{"class":666},"::LockedOut:\n",[599,19396,19398,19400,19402,19404,19407,19409],{"class":601,"line":19397},370,[599,19399,19122],{"class":609},[599,19401,688],{"class":666},[599,19403,19127],{"class":609},[599,19405,19406],{"class":666},"(EVENTLOG_WARNING_TYPE, ",[599,19408,9287],{"class":609},[599,19410,19411],{"class":666},"::EVT_LOCKED_OUT,\n",[599,19413,19415,19418,19420,19422,19424,19427],{"class":601,"line":19414},371,[599,19416,19417],{"class":619},"                          L\"Logon attempt for locked account \"",[599,19419,1201],{"class":605},[599,19421,19279],{"class":666},[599,19423,2543],{"class":605},[599,19425,19426],{"class":619}," L\", \"",[599,19428,19429],{"class":605}," +\n",[599,19431,19433,19436,19438,19440,19442,19444,19447,19449,19451,19453,19455],{"class":601,"line":19432},372,[599,19434,19435],{"class":609},"                              std",[599,19437,688],{"class":666},[599,19439,19215],{"class":609},[599,19441,19295],{"class":666},[599,19443,2543],{"class":605},[599,19445,19446],{"class":619}," L\" minutes left. \"",[599,19448,1201],{"class":605},[599,19450,18819],{"class":666},[599,19452,2543],{"class":605},[599,19454,19235],{"class":619},[599,19456,725],{"class":666},[599,19458,19460,19463,19465,19467,19469,19471],{"class":601,"line":19459},373,[599,19461,19462],{"class":609},"            swprintf_s",[599,19464,19340],{"class":666},[599,19466,19343],{"class":619},[599,19468,9382],{"class":949},[599,19470,19348],{"class":619},[599,19472,19351],{"class":666},[599,19474,19476,19479,19481],{"class":601,"line":19475},374,[599,19477,19478],{"class":666},"            message ",[599,19480,1060],{"class":605},[599,19482,19362],{"class":666},[599,19484,19486,19488],{"class":601,"line":19485},375,[599,19487,19373],{"class":605},[599,19489,1066],{"class":666},[599,19491,19493],{"class":601,"line":19492},376,[599,19494,651],{"emptyLinePlaceholder":650},[599,19496,19498,19500,19502,19504,19506],{"class":601,"line":19497},377,[599,19499,19093],{"class":605},[599,19501,9688],{"class":609},[599,19503,688],{"class":666},[599,19505,18895],{"class":609},[599,19507,19508],{"class":666},"::NotEnrolled:\n",[599,19510,19512,19514,19516,19518,19520,19522],{"class":601,"line":19511},378,[599,19513,19122],{"class":609},[599,19515,688],{"class":666},[599,19517,19127],{"class":609},[599,19519,19406],{"class":666},[599,19521,9287],{"class":609},[599,19523,19524],{"class":666},"::EVT_NOT_ENROLLED,\n",[599,19526,19528,19531,19533,19535,19537,19540,19542,19544,19546,19548],{"class":601,"line":19527},379,[599,19529,19530],{"class":619},"                          L\"Logon attempt for \"",[599,19532,1201],{"class":605},[599,19534,19279],{"class":666},[599,19536,2543],{"class":605},[599,19538,19539],{"class":619}," L\", which is not enrolled. \"",[599,19541,1201],{"class":605},[599,19543,18819],{"class":666},[599,19545,2543],{"class":605},[599,19547,19235],{"class":619},[599,19549,725],{"class":666},[599,19551,19553,19555],{"class":601,"line":19552},380,[599,19554,19373],{"class":605},[599,19556,1066],{"class":666},[599,19558,19560],{"class":601,"line":19559},381,[599,19561,651],{"emptyLinePlaceholder":650},[599,19563,19565,19568],{"class":601,"line":19564},382,[599,19566,19567],{"class":605},"        default",[599,19569,3457],{"class":666},[599,19571,19573,19575,19577,19579,19581,19583],{"class":601,"line":19572},383,[599,19574,19122],{"class":609},[599,19576,688],{"class":666},[599,19578,19127],{"class":609},[599,19580,19263],{"class":666},[599,19582,9287],{"class":609},[599,19584,19585],{"class":666},"::EVT_ERROR,\n",[599,19587,19589,19592,19594,19596],{"class":601,"line":19588},384,[599,19590,19591],{"class":619},"                          L\"Could not read or write the 2FA state of \"",[599,19593,1201],{"class":605},[599,19595,19279],{"class":666},[599,19597,10195],{"class":605},[599,19599,19601,19604,19606,19608,19610,19612],{"class":601,"line":19600},385,[599,19602,19603],{"class":619},"                              L\". The logon was refused. \"",[599,19605,1201],{"class":605},[599,19607,18819],{"class":666},[599,19609,2543],{"class":605},[599,19611,19235],{"class":619},[599,19613,725],{"class":666},[599,19615,19617,19619],{"class":601,"line":19616},386,[599,19618,19373],{"class":605},[599,19620,1066],{"class":666},[599,19622,19624],{"class":601,"line":19623},387,[599,19625,1564],{"class":666},[599,19627,19629],{"class":601,"line":19628},388,[599,19630,651],{"emptyLinePlaceholder":650},[599,19632,19634,19637],{"class":601,"line":19633},389,[599,19635,19636],{"class":609},"        SHStrDupW",[599,19638,19639],{"class":666},"(message, ppwszOptionalStatusText);\n",[599,19641,19643,19645,19648,19650],{"class":601,"line":19642},390,[599,19644,12141],{"class":605},[599,19646,19647],{"class":666},"pcpsiOptionalStatusIcon ",[599,19649,1060],{"class":605},[599,19651,19652],{"class":666}," CPSI_ERROR;\n",[599,19654,19656,19658,19661],{"class":601,"line":19655},391,[599,19657,1211],{"class":605},[599,19659,19660],{"class":666}," S_OK;",[599,19662,19663],{"class":772},"   \u002F\u002F S_OK keeps the tile alive; a failing HRESULT would kill it\n",[599,19665,19667],{"class":601,"line":19666},392,[599,19668,1224],{"class":666},[599,19670,19672],{"class":601,"line":19671},393,[599,19673,651],{"emptyLinePlaceholder":650},[599,19675,19677,19679,19681,19683,19686,19688],{"class":601,"line":19676},394,[599,19678,9269],{"class":609},[599,19680,688],{"class":666},[599,19682,19127],{"class":609},[599,19684,19685],{"class":666},"(EVENTLOG_INFORMATION_TYPE, ",[599,19687,9287],{"class":609},[599,19689,19690],{"class":666},"::EVT_CODE_OK,\n",[599,19692,19694,19697,19699,19701,19703,19706,19708,19710,19712,19714,19717],{"class":601,"line":19693},395,[599,19695,19696],{"class":619},"                  L\"Valid one-time code for \"",[599,19698,1201],{"class":605},[599,19700,19279],{"class":666},[599,19702,2543],{"class":605},[599,19704,19705],{"class":619}," L\" (time step \"",[599,19707,1201],{"class":605},[599,19709,685],{"class":609},[599,19711,688],{"class":666},[599,19713,19215],{"class":609},[599,19715,19716],{"class":666},"(info.step) ",[599,19718,10195],{"class":605},[599,19720,19722,19725,19727,19729,19731,19733],{"class":601,"line":19721},396,[599,19723,19724],{"class":619},"                      L\"). The password goes to LSA now. \"",[599,19726,1201],{"class":605},[599,19728,18819],{"class":666},[599,19730,2543],{"class":605},[599,19732,19235],{"class":619},[599,19734,725],{"class":666},[599,19736,19738],{"class":601,"line":19737},397,[599,19739,651],{"emptyLinePlaceholder":650},[599,19741,19743],{"class":601,"line":19742},398,[599,19744,19745],{"class":772},"    \u002F\u002F --- the ordinary password logon, once the code is valid ---\n",[599,19747,19749,19751,19753,19755,19757],{"class":601,"line":19748},399,[599,19750,15449],{"class":609},[599,19752,16245],{"class":666},[599,19754,1060],{"class":605},[599,19756,1962],{"class":949},[599,19758,1066],{"class":666},[599,19760,19762,19764,19766,19768,19771,19774,19776],{"class":601,"line":19761},400,[599,19763,11344],{"class":609},[599,19765,12703],{"class":666},[599,19767,1060],{"class":605},[599,19769,19770],{"class":609}," ProtectIfNecessaryAndCopyPassword",[599,19772,19773],{"class":666},"(_rgFieldStrings[TFI_PASSWORD], _cpus, ",[599,19775,694],{"class":605},[599,19777,19778],{"class":666},"pwzPassword);\n",[599,19780,19782],{"class":601,"line":19781},401,[599,19783,651],{"emptyLinePlaceholder":650},[599,19785,19787],{"class":601,"line":19786},402,[599,19788,19789],{"class":772},"    \u002F\u002F Always log on as COMPUTERNAME\\user. This is a local-account demo, so we\n",[599,19791,19793],{"class":601,"line":19792},403,[599,19794,19795],{"class":772},"    \u002F\u002F never authenticate a domain the user might have typed.\n",[599,19797,19799,19801,19803,19805,19807,19809],{"class":601,"line":19798},404,[599,19800,12510],{"class":666},[599,19802,2543],{"class":605},[599,19804,973],{"class":949},[599,19806,2491],{"class":666},[599,19808,1060],{"class":605},[599,19810,5921],{"class":666},[599,19812,19814,19816,19818,19820,19822],{"class":601,"line":19813},405,[599,19815,11440],{"class":609},[599,19817,6360],{"class":666},[599,19819,1060],{"class":605},[599,19821,6365],{"class":609},[599,19823,6368],{"class":666},[599,19825,19827,19829,19831,19833,19836,19838,19840,19842,19844,19846],{"class":601,"line":19826},406,[599,19828,3514],{"class":605},[599,19830,1327],{"class":666},[599,19832,12847],{"class":609},[599,19834,19835],{"class":666},"(hr) ",[599,19837,3154],{"class":605},[599,19839,9609],{"class":605},[599,19841,6379],{"class":609},[599,19843,6382],{"class":666},[599,19845,694],{"class":605},[599,19847,6387],{"class":666},[599,19849,19851,19853,19855,19858,19860,19862],{"class":601,"line":19850},407,[599,19852,13507],{"class":666},[599,19854,1060],{"class":605},[599,19856,19857],{"class":609}," HRESULT_FROM_WIN32",[599,19859,679],{"class":666},[599,19861,6861],{"class":609},[599,19863,6864],{"class":666},[599,19865,19867],{"class":601,"line":19866},408,[599,19868,651],{"emptyLinePlaceholder":650},[599,19870,19872,19874,19876,19878,19880,19882,19884,19886,19888,19890,19892,19894,19896,19898,19900],{"class":601,"line":19871},409,[599,19873,731],{"class":609},[599,19875,688],{"class":666},[599,19877,902],{"class":609},[599,19879,6410],{"class":666},[599,19881,1060],{"class":605},[599,19883,685],{"class":609},[599,19885,688],{"class":666},[599,19887,902],{"class":609},[599,19889,6421],{"class":666},[599,19891,2543],{"class":605},[599,19893,6426],{"class":619},[599,19895,5576],{"class":949},[599,19897,4362],{"class":619},[599,19899,1201],{"class":605},[599,19901,19902],{"class":666}," bare;\n",[599,19904,19906],{"class":601,"line":19905},410,[599,19907,651],{"emptyLinePlaceholder":650},[599,19909,19911,19914,19917,19919,19921],{"class":601,"line":19910},411,[599,19912,19913],{"class":666},"    WCHAR domain[",[599,19915,19916],{"class":949},"64",[599,19918,2491],{"class":666},[599,19920,1060],{"class":605},[599,19922,5921],{"class":666},[599,19924,19926,19929,19931,19934,19936],{"class":601,"line":19925},412,[599,19927,19928],{"class":666},"    WCHAR user[",[599,19930,6464],{"class":949},[599,19932,19933],{"class":666},"]  ",[599,19935,1060],{"class":605},[599,19937,5921],{"class":666},[599,19939,19941,19943,19945,19947],{"class":601,"line":19940},413,[599,19942,3514],{"class":605},[599,19944,1327],{"class":666},[599,19946,12847],{"class":609},[599,19948,12731],{"class":666},[599,19950,19952,19954,19956,19959,19962,19964,19967,19970],{"class":601,"line":19951},414,[599,19953,13507],{"class":666},[599,19955,1060],{"class":605},[599,19957,19958],{"class":609}," SplitDomainAndUsername",[599,19960,19961],{"class":666},"(qualified.",[599,19963,6513],{"class":609},[599,19965,19966],{"class":666},"(), domain, ",[599,19968,19969],{"class":609},"ARRAYSIZE",[599,19971,19972],{"class":666},"(domain),\n",[599,19974,19976,19979,19981],{"class":601,"line":19975},415,[599,19977,19978],{"class":666},"                                    user, ",[599,19980,19969],{"class":609},[599,19982,19983],{"class":666},"(user));\n",[599,19985,19987],{"class":601,"line":19986},416,[599,19988,651],{"emptyLinePlaceholder":650},[599,19990,19992,19994],{"class":601,"line":19991},417,[599,19993,13403],{"class":609},[599,19995,19996],{"class":666}," kiul;\n",[599,19998,20000,20002,20004,20006],{"class":601,"line":19999},418,[599,20001,3514],{"class":605},[599,20003,1327],{"class":666},[599,20005,12847],{"class":609},[599,20007,12731],{"class":666},[599,20009,20011,20013,20015,20018,20021,20023],{"class":601,"line":20010},419,[599,20012,13507],{"class":666},[599,20014,1060],{"class":605},[599,20016,20017],{"class":609}," KerbInteractiveUnlockLogonInit",[599,20019,20020],{"class":666},"(domain, user, pwzPassword, _cpus, ",[599,20022,694],{"class":605},[599,20024,20025],{"class":666},"kiul);\n",[599,20027,20029,20031,20033,20035],{"class":601,"line":20028},420,[599,20030,3514],{"class":605},[599,20032,1327],{"class":666},[599,20034,12847],{"class":609},[599,20036,12731],{"class":666},[599,20038,20040,20042,20044,20047,20050,20052,20055,20057],{"class":601,"line":20039},421,[599,20041,13507],{"class":666},[599,20043,1060],{"class":605},[599,20045,20046],{"class":609}," KerbInteractiveUnlockLogonPack",[599,20048,20049],{"class":666},"(kiul, ",[599,20051,694],{"class":605},[599,20053,20054],{"class":666},"pcpcs->rgbSerialization, ",[599,20056,694],{"class":605},[599,20058,20059],{"class":666},"pcpcs->cbSerialization);\n",[599,20061,20063,20065,20067,20069],{"class":601,"line":20062},422,[599,20064,3514],{"class":605},[599,20066,1327],{"class":666},[599,20068,12847],{"class":609},[599,20070,12731],{"class":666},[599,20072,20074],{"class":601,"line":20073},423,[599,20075,1095],{"class":666},[599,20077,20079,20082,20085,20087,20089],{"class":601,"line":20078},424,[599,20080,20081],{"class":609},"        ULONG",[599,20083,20084],{"class":666}," ulAuthPackage ",[599,20086,1060],{"class":605},[599,20088,1286],{"class":949},[599,20090,1066],{"class":666},[599,20092,20094,20096,20098,20101,20103,20105],{"class":601,"line":20093},425,[599,20095,13507],{"class":666},[599,20097,1060],{"class":605},[599,20099,20100],{"class":609}," RetrieveNegotiateAuthPackage",[599,20102,679],{"class":666},[599,20104,694],{"class":605},[599,20106,20107],{"class":666},"ulAuthPackage);\n",[599,20109,20111,20113,20115,20117],{"class":601,"line":20110},426,[599,20112,1100],{"class":605},[599,20114,1327],{"class":666},[599,20116,12847],{"class":609},[599,20118,12731],{"class":666},[599,20120,20122],{"class":601,"line":20121},427,[599,20123,1338],{"class":666},[599,20125,20127,20130,20132],{"class":601,"line":20126},428,[599,20128,20129],{"class":666},"            pcpcs->ulAuthenticationPackage ",[599,20131,1060],{"class":605},[599,20133,20134],{"class":666}," ulAuthPackage;\n",[599,20136,20138,20141,20143],{"class":601,"line":20137},429,[599,20139,20140],{"class":666},"            pcpcs->clsidCredentialProvider ",[599,20142,1060],{"class":605},[599,20144,20145],{"class":666}," CLSID_CTacProvider;\n",[599,20147,20149,20152,20154,20156],{"class":601,"line":20148},430,[599,20150,20151],{"class":605},"            *",[599,20153,18509],{"class":666},[599,20155,1060],{"class":605},[599,20157,20158],{"class":666}," CPGSR_RETURN_CREDENTIAL_FINISHED;\n",[599,20160,20162],{"class":601,"line":20161},431,[599,20163,1564],{"class":666},[599,20165,20167],{"class":601,"line":20166},432,[599,20168,1224],{"class":666},[599,20170,20172],{"class":601,"line":20171},433,[599,20173,651],{"emptyLinePlaceholder":650},[599,20175,20177,20179,20181,20183,20185,20187],{"class":601,"line":20176},434,[599,20178,3514],{"class":605},[599,20180,1327],{"class":666},[599,20182,12728],{"class":609},[599,20184,19835],{"class":666},[599,20186,3154],{"class":605},[599,20188,20189],{"class":666}," pcpcs->rgbSerialization)\n",[599,20191,20193],{"class":601,"line":20192},435,[599,20194,1095],{"class":666},[599,20196,20198,20200],{"class":601,"line":20197},436,[599,20199,6213],{"class":609},[599,20201,20202],{"class":666},"(pcpcs->rgbSerialization, pcpcs->cbSerialization);\n",[599,20204,20206,20208],{"class":601,"line":20205},437,[599,20207,13187],{"class":609},[599,20209,20210],{"class":666},"(pcpcs->rgbSerialization);\n",[599,20212,20214,20217,20219,20221],{"class":601,"line":20213},438,[599,20215,20216],{"class":666},"        pcpcs->rgbSerialization ",[599,20218,1060],{"class":605},[599,20220,1962],{"class":949},[599,20222,1066],{"class":666},[599,20224,20226,20229,20231,20233],{"class":601,"line":20225},439,[599,20227,20228],{"class":666},"        pcpcs->cbSerialization  ",[599,20230,1060],{"class":605},[599,20232,1286],{"class":949},[599,20234,1066],{"class":666},[599,20236,20238],{"class":601,"line":20237},440,[599,20239,1224],{"class":666},[599,20241,20243,20245],{"class":601,"line":20242},441,[599,20244,3514],{"class":605},[599,20246,20247],{"class":666}," (pwzPassword)\n",[599,20249,20251],{"class":601,"line":20250},442,[599,20252,1095],{"class":666},[599,20254,20256,20258,20261,20264,20267,20269,20271],{"class":601,"line":20255},443,[599,20257,6213],{"class":609},[599,20259,20260],{"class":666},"(pwzPassword, ",[599,20262,20263],{"class":609},"wcslen",[599,20265,20266],{"class":666},"(pwzPassword) ",[599,20268,748],{"class":605},[599,20270,6453],{"class":605},[599,20272,11824],{"class":666},[599,20274,20276,20278],{"class":601,"line":20275},444,[599,20277,13187],{"class":609},[599,20279,20280],{"class":666},"(pwzPassword);\n",[599,20282,20284],{"class":601,"line":20283},445,[599,20285,1224],{"class":666},[599,20287,20289,20291],{"class":601,"line":20288},446,[599,20290,3551],{"class":605},[599,20292,12751],{"class":666},[599,20294,20296],{"class":601,"line":20295},447,[599,20297,981],{"class":666},[599,20299,20301],{"class":601,"line":20300},448,[599,20302,651],{"emptyLinePlaceholder":650},[599,20304,20306],{"class":601,"line":20305},449,[599,20307,20308],{"class":772},"\u002F\u002F LSA reports the result of the logon here. If it failed, clear password and\n",[599,20310,20312],{"class":601,"line":20311},450,[599,20313,20314],{"class":772},"\u002F\u002F code like the built-in tile does (the code is used up anyway), and turn a\n",[599,20316,20318],{"class":601,"line":20317},451,[599,20319,20320],{"class":772},"\u002F\u002F wrong password into a readable message.\n",[599,20322,20324,20326,20328,20330,20333,20335,20337,20339,20341,20343],{"class":601,"line":20323},452,[599,20325,12063],{"class":609},[599,20327,14735],{"class":609},[599,20329,688],{"class":666},[599,20331,20332],{"class":609},"ReportResult",[599,20334,679],{"class":666},[599,20336,15298],{"class":609},[599,20338,15301],{"class":697},[599,20340,212],{"class":666},[599,20342,15298],{"class":609},[599,20344,813],{"class":666},[599,20346,20348,20351,20353,20355],{"class":601,"line":20347},453,[599,20349,20350],{"class":609},"                                            PWSTR",[599,20352,748],{"class":605},[599,20354,15272],{"class":697},[599,20356,813],{"class":666},[599,20358,20360,20363,20365,20367],{"class":601,"line":20359},454,[599,20361,20362],{"class":609},"                                            CREDENTIAL_PROVIDER_STATUS_ICON",[599,20364,748],{"class":605},[599,20366,15284],{"class":697},[599,20368,1029],{"class":666},[599,20370,20372],{"class":601,"line":20371},455,[599,20373,667],{"class":666},[599,20375,20377,20379,20382,20384,20386],{"class":601,"line":20376},456,[599,20378,12236],{"class":605},[599,20380,20381],{"class":666},"ppwszOptionalStatusText ",[599,20383,1060],{"class":605},[599,20385,1962],{"class":949},[599,20387,1066],{"class":666},[599,20389,20391,20393,20395,20397],{"class":601,"line":20390},457,[599,20392,12236],{"class":605},[599,20394,19647],{"class":666},[599,20396,1060],{"class":605},[599,20398,20399],{"class":666}," CPSI_NONE;\n",[599,20401,20403],{"class":601,"line":20402},458,[599,20404,651],{"emptyLinePlaceholder":650},[599,20406,20408,20410,20413,20415,20417],{"class":601,"line":20407},459,[599,20409,3514],{"class":605},[599,20411,20412],{"class":666}," (ntsStatus ",[599,20414,2030],{"class":605},[599,20416,1286],{"class":949},[599,20418,1029],{"class":666},[599,20420,20422],{"class":601,"line":20421},460,[599,20423,1095],{"class":666},[599,20425,20427,20430],{"class":601,"line":20426},461,[599,20428,20429],{"class":609},"        _ResetField",[599,20431,17037],{"class":666},[599,20433,20435,20437],{"class":601,"line":20434},462,[599,20436,20429],{"class":609},[599,20438,17044],{"class":666},[599,20440,20442],{"class":601,"line":20441},463,[599,20443,1224],{"class":666},[599,20445,20447],{"class":601,"line":20446},464,[599,20448,651],{"emptyLinePlaceholder":650},[599,20450,20452,20454,20456,20458],{"class":601,"line":20451},465,[599,20453,3514],{"class":605},[599,20455,20412],{"class":666},[599,20457,1349],{"class":605},[599,20459,20460],{"class":666}," STATUS_LOGON_FAILURE)\n",[599,20462,20464],{"class":601,"line":20463},466,[599,20465,1095],{"class":666},[599,20467,20469,20471,20473,20476],{"class":601,"line":20468},467,[599,20470,19636],{"class":609},[599,20472,679],{"class":666},[599,20474,20475],{"class":619},"L\"Incorrect password.\"",[599,20477,20478],{"class":666},", ppwszOptionalStatusText);\n",[599,20480,20482,20484,20486,20488],{"class":601,"line":20481},468,[599,20483,12141],{"class":605},[599,20485,19647],{"class":666},[599,20487,1060],{"class":605},[599,20489,19652],{"class":666},[599,20491,20493],{"class":601,"line":20492},469,[599,20494,1224],{"class":666},[599,20496,20498,20500],{"class":601,"line":20497},470,[599,20499,3551],{"class":605},[599,20501,12172],{"class":666},[599,20503,20505],{"class":601,"line":20504},471,[599,20506,981],{"class":666},[15,20508,20509,20511],{},[69,20510,237],{}," is the most important function of the whole project. LogonUI calls it when the user clicks submit. This is the only place where we can stop the logon.",[15,20513,20514],{},"I made some decisions here that I want to explain.",[15,20516,20517,20520,20521,20524,20525,20528],{},[47,20518,20519],{},"The code is checked first."," If it is wrong, the function returns ",[69,20522,20523],{},"S_OK"," with ",[69,20526,20527],{},"CPGSR_NO_CREDENTIAL_NOT_FINISHED"," and a message. The tile stays and the user can try again. If I returned an error instead, the tile would just show a generic error.",[15,20530,20531],{},"This has an advantage and a disadvantage. The advantage is that without a valid code the password is never sent. Someone at the logon screen cannot test passwords with our tile. The disadvantage is that a wrong code never reaches LSA. The lockout policy does not count it. That's why the demo has its own counter: after 5 wrong codes in a row the account is locked. This is the next chapter.",[15,20533,20534,20537],{},[47,20535,20536],{},"Users without a secret cannot log in."," Together with the filter this means that users who are not enrolled cannot log in interactively at all. So enroll every account you need before you enable the filter. Including a break-glass admin.",[15,20539,20540,20543],{},[47,20541,20542],{},"Same message for almost all errors."," \"Not enrolled\", \"wrong code\" and \"code already used\" show the same text. Otherwise anyone at the logon screen could find out which accounts have 2FA. The only exception is the lock. If the account is locked, the tile says so and how many minutes are left. Without this message a user would keep typing correct codes and wonder why nothing works. The price: someone who types 5 wrong codes for an account learns that it is enrolled. On a user tile the account is visible anyway, so I think this is okay.",[15,20545,20546,20549,20550,20552,20553,20555,20556,20558,20559,20561],{},[47,20547,20548],{},"The account is always a local account."," On user tiles the name comes from Windows (",[69,20551,14583],{},"), on the fallback tile it is typed. In both cases the provider takes only the bare name, resolves ",[69,20554,8724],{}," to a SID, checks the code for this SID and logs in as ",[69,20557,8724],{},". So the account that is checked is always the same local account that is logged in. In my first version of the user tiles I forgot the check for local accounts. On a domain joined machine the tile for ",[69,20560,14601],{}," would have accepted the code of the local alice. That's why there are two checks now: only local accounts get a tile, and the logon always uses the computer name.",[15,20563,20564,20567,20568,20570],{},[47,20565,20566],{},"Tile and account have to match."," A user tile knows its SID (",[69,20569,15714],{},"). Before the code is checked, the name from the tile is resolved to a SID and both are compared. If they are not the same, the code is not checked at all. Normally this can't happen, because the name comes from Windows. But it costs one line and closes the door if something ever puts a different name into the field.",[15,20572,20573,20576],{},[47,20574,20575],{},"Every attempt is logged."," Wrong code, used code, lock, unknown account and success. Each event has the account, the SID and where the attempt came from: console or RDP with the IP address. The code itself is never logged. More about this in the chapter about logging.",[15,20578,20579,20582,20583,20585,20586,20588],{},[47,20580,20581],{},"The rest is a normal logon."," When the code is correct, the provider does the same as the normal password tile. It fills a ",[69,20584,13418],{}," with domain, username and password, packs it into one buffer and sends it to the Negotiate package. For a local account this ends up in ",[69,20587,166],{}," and the local SAM. I don't change the actual authentication. I just don't start it until the code is correct. How the packing works is explained in the chapter about the helper functions.",[15,20590,20591,20594,20595,20597],{},[47,20592,20593],{},"Cleanup."," Password and code are deleted from memory when the tile loses focus. After a failed logon (",[69,20596,20332],{},") both fields are emptied, like on the normal Windows tile. If something goes wrong after the password was packed, the buffer is overwritten and freed. For RDP the provider deletes its copy of the password as soon as the tile has its own.",[10,20599,20601],{"id":20600},"rate-limiting-and-replay-protection","Rate limiting and replay protection",[15,20603,20604,20605,20607],{},"The code check itself is in ",[69,20606,3225],{},". But a check alone is not enough. Two things were missing in my first version: a code could be used again within 90 seconds, and there was no limit for wrong codes.",[15,20609,20610,20611,20614],{},"The second one sounds harmless, so let's do the math. With a window of one step before and after, 3 of the 1'000'000 possible codes are valid at any time. One guess hits with a probability of 3 in a million. After ",[69,20612,20613],{},"n"," guesses the chance for at least one hit is:",[148,20616,20619],{"className":20617,"code":20618,"language":153,"meta":154},[151],"P(n) = 1 - (1 - 3\u002F1'000'000)^n\n\nP = 50%  after about 231'000 guesses\nP = 90%  after about 768'000 guesses\n",[69,20620,20618],{"__ignoreMap":154},[15,20622,20623],{},"That sounds like a lot. But nobody types them by hand. A cheap USB device that acts as a keyboard types around 2 codes per second into the logon screen. Over RDP it's even easier to automate. 231'000 guesses at 2 per second are about 32 hours. That's one weekend. And remember: the Windows lockout policy never sees any of these guesses, because a wrong code never reaches LSA. There isn't even an event in the Security log.",[15,20625,20626],{},"Of course the attacker needs the password for this. But that is exactly the situation 2FA is built for.",[126,20628,20630],{"id":20629},"the-state-per-account","The state per account",[15,20632,20633,20634,20636],{},"For both problems the provider has to remember something per account. I store three values in one small structure (it's in ",[69,20635,5046],{},"):",[148,20638,20640],{"className":593,"code":20639,"language":595,"meta":154,"style":154},"struct UserState\n{\n    uint64_t lastStep;      \u002F\u002F last accepted TOTP time step, 0 = none yet\n    uint32_t failures;      \u002F\u002F wrong codes in a row\n    uint32_t reserved;\n    uint64_t lockedUntil;   \u002F\u002F unix time, 0 = not locked\n};\n",[69,20641,20642,20648,20652,20660,20669,20675,20683],{"__ignoreMap":154},[599,20643,20644,20646],{"class":601,"line":602},[599,20645,10621],{"class":605},[599,20647,5288],{"class":609},[599,20649,20650],{"class":601,"line":613},[599,20651,667],{"class":666},[599,20653,20654,20656,20658],{"class":601,"line":623},[599,20655,9346],{"class":605},[599,20657,5299],{"class":666},[599,20659,5302],{"class":772},[599,20661,20662,20665,20667],{"class":601,"line":631},[599,20663,20664],{"class":605},"    uint32_t",[599,20666,5309],{"class":666},[599,20668,5312],{"class":772},[599,20670,20671,20673],{"class":601,"line":639},[599,20672,20664],{"class":605},[599,20674,5319],{"class":666},[599,20676,20677,20679,20681],{"class":601,"line":647},[599,20678,9346],{"class":605},[599,20680,5326],{"class":666},[599,20682,5329],{"class":772},[599,20684,20685],{"class":601,"line":654},[599,20686,10612],{"class":666},[15,20688,20689,20690,20693,20694,20697,20698,20701],{},"It is stored as ",[69,20691,20692],{},"REG_BINARY"," under ",[69,20695,20696],{},"HKLM\\SOFTWARE\\TheAdminCafe\\2FA\\State\\\u003CSID>",", with the same ACL as the secrets: only SYSTEM and administrators. LogonUI runs as SYSTEM, so it can write there. A normal user can't reset their own counter. The ",[69,20699,20700],{},"static_assert"," makes sure that the structure has exactly 24 bytes, because it goes into the registry as it is.",[126,20703,20705],{"id":20704},"the-lock","The lock",[15,20707,20708],{},"After 5 wrong codes in a row the account is locked. Every further wrong code doubles the time: 5, 10, 20, 40 and then always 60 minutes. A correct code resets the counter to zero.",[15,20710,20711],{},"What does this do to the attack? The first 5 guesses are free. The next 4 need 75 minutes, after that there is one guess per hour. That's about 24 guesses per day. For 231'000 guesses the attacker needs about 26 years.",[15,20713,20714],{},"Why doubling and not a fixed lock? With a fixed 5 minutes it would be 288 guesses per day, and 50% after about 800 days. That's long, but there is no reason to be generous. A normal user who mistypes twice never sees the lock anyway.",[15,20716,20717,590],{},[69,20718,20719],{},"verify.h",[148,20721,20723],{"className":593,"code":20722,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccstdint>\n#include \u003Cstring>\n\nnamespace tac\n{\n    \u002F\u002F After this many wrong codes in a row the account is locked.\n    const uint32_t kFreeFailures = 5;\n\n    enum class OtpResult\n    {\n        Ok,           \u002F\u002F code correct, time step recorded\n        Wrong,        \u002F\u002F wrong code (counted)\n        Replayed,     \u002F\u002F correct code, but its time step was already used (counted)\n        LockedOut,    \u002F\u002F too many wrong codes, the code was not even checked\n        NotEnrolled,  \u002F\u002F no secret for this SID\n        Error,        \u002F\u002F state could not be read or written, fail closed\n    };\n\n    struct OtpInfo\n    {\n        uint32_t failures;      \u002F\u002F wrong codes in a row, after this attempt\n        uint32_t minutesLeft;   \u002F\u002F lock time left, if locked\n        uint64_t step;          \u002F\u002F the accepted time step, if Ok\n    };\n\n    \u002F\u002F Lock time after the n-th wrong code in a row: 0 up to kFreeFailures - 1,\n    \u002F\u002F then 5, 10, 20, 40 and at most 60 minutes.\n    uint32_t LockMinutesFor(uint32_t failures);\n\n    \u002F\u002F Checks the code for the account and updates its state (replay\n    \u002F\u002F protection and rate limiting). `now` is the unix time.\n    OtpResult VerifyOtp(const std::wstring& sid, const std::wstring& code,\n                        uint64_t now, OtpInfo& info);\n}\n",[69,20724,20725,20731,20737,20743,20749,20753,20759,20763,20768,20784,20788,20799,20803,20813,20823,20833,20843,20853,20863,20867,20871,20878,20882,20891,20901,20911,20915,20919,20924,20929,20946,20950,20955,20960,20998,21016],{"__ignoreMap":154},[599,20726,20727,20729],{"class":601,"line":602},[599,20728,606],{"class":605},[599,20730,610],{"class":609},[599,20732,20733,20735],{"class":601,"line":613},[599,20734,616],{"class":605},[599,20736,620],{"class":619},[599,20738,20739,20741],{"class":601,"line":623},[599,20740,616],{"class":605},[599,20742,628],{"class":619},[599,20744,20745,20747],{"class":601,"line":631},[599,20746,616],{"class":605},[599,20748,636],{"class":619},[599,20750,20751],{"class":601,"line":639},[599,20752,651],{"emptyLinePlaceholder":650},[599,20754,20755,20757],{"class":601,"line":647},[599,20756,657],{"class":605},[599,20758,660],{"class":609},[599,20760,20761],{"class":601,"line":654},[599,20762,667],{"class":666},[599,20764,20765],{"class":601,"line":663},[599,20766,20767],{"class":772},"    \u002F\u002F After this many wrong codes in a row the account is locked.\n",[599,20769,20770,20772,20775,20778,20780,20782],{"class":601,"line":670},[599,20771,12451],{"class":605},[599,20773,20774],{"class":605}," uint32_t",[599,20776,20777],{"class":666}," kFreeFailures ",[599,20779,1060],{"class":605},[599,20781,1435],{"class":949},[599,20783,1066],{"class":666},[599,20785,20786],{"class":601,"line":728},[599,20787,651],{"emptyLinePlaceholder":650},[599,20789,20790,20793,20796],{"class":601,"line":764},[599,20791,20792],{"class":605},"    enum",[599,20794,20795],{"class":605}," class",[599,20797,20798],{"class":609}," OtpResult\n",[599,20800,20801],{"class":601,"line":769},[599,20802,1095],{"class":666},[599,20804,20805,20808,20810],{"class":601,"line":776},[599,20806,20807],{"class":949},"        Ok",[599,20809,10558],{"class":666},[599,20811,20812],{"class":772},"           \u002F\u002F code correct, time step recorded\n",[599,20814,20815,20818,20820],{"class":601,"line":816},[599,20816,20817],{"class":949},"        Wrong",[599,20819,10558],{"class":666},[599,20821,20822],{"class":772},"        \u002F\u002F wrong code (counted)\n",[599,20824,20825,20828,20830],{"class":601,"line":843},[599,20826,20827],{"class":949},"        Replayed",[599,20829,10558],{"class":666},[599,20831,20832],{"class":772},"     \u002F\u002F correct code, but its time step was already used (counted)\n",[599,20834,20835,20838,20840],{"class":601,"line":848},[599,20836,20837],{"class":949},"        LockedOut",[599,20839,10558],{"class":666},[599,20841,20842],{"class":772},"    \u002F\u002F too many wrong codes, the code was not even checked\n",[599,20844,20845,20848,20850],{"class":601,"line":854},[599,20846,20847],{"class":949},"        NotEnrolled",[599,20849,10558],{"class":666},[599,20851,20852],{"class":772},"  \u002F\u002F no secret for this SID\n",[599,20854,20855,20858,20860],{"class":601,"line":860},[599,20856,20857],{"class":949},"        Error",[599,20859,10558],{"class":666},[599,20861,20862],{"class":772},"        \u002F\u002F state could not be read or written, fail closed\n",[599,20864,20865],{"class":601,"line":866},[599,20866,5334],{"class":666},[599,20868,20869],{"class":601,"line":912},[599,20870,651],{"emptyLinePlaceholder":650},[599,20872,20873,20875],{"class":601,"line":938},[599,20874,5285],{"class":605},[599,20876,20877],{"class":609}," OtpInfo\n",[599,20879,20880],{"class":601,"line":978},[599,20881,1095],{"class":666},[599,20883,20884,20886,20888],{"class":601,"line":1316},[599,20885,1278],{"class":605},[599,20887,5309],{"class":666},[599,20889,20890],{"class":772},"      \u002F\u002F wrong codes in a row, after this attempt\n",[599,20892,20893,20895,20898],{"class":601,"line":1321},[599,20894,1278],{"class":605},[599,20896,20897],{"class":666}," minutesLeft;",[599,20899,20900],{"class":772},"   \u002F\u002F lock time left, if locked\n",[599,20902,20903,20905,20908],{"class":601,"line":1335},[599,20904,2300],{"class":605},[599,20906,20907],{"class":666}," step;",[599,20909,20910],{"class":772},"          \u002F\u002F the accepted time step, if Ok\n",[599,20912,20913],{"class":601,"line":1341},[599,20914,5334],{"class":666},[599,20916,20917],{"class":601,"line":1367},[599,20918,651],{"emptyLinePlaceholder":650},[599,20920,20921],{"class":601,"line":1375},[599,20922,20923],{"class":772},"    \u002F\u002F Lock time after the n-th wrong code in a row: 0 up to kFreeFailures - 1,\n",[599,20925,20926],{"class":601,"line":1391},[599,20927,20928],{"class":772},"    \u002F\u002F then 5, 10, 20, 40 and at most 60 minutes.\n",[599,20930,20931,20933,20936,20938,20941,20944],{"class":601,"line":1405},[599,20932,20664],{"class":605},[599,20934,20935],{"class":609}," LockMinutesFor",[599,20937,679],{"class":666},[599,20939,20940],{"class":605},"uint32_t",[599,20942,20943],{"class":697}," failures",[599,20945,725],{"class":666},[599,20947,20948],{"class":601,"line":1416},[599,20949,651],{"emptyLinePlaceholder":650},[599,20951,20952],{"class":601,"line":1421},[599,20953,20954],{"class":772},"    \u002F\u002F Checks the code for the account and updates its state (replay\n",[599,20956,20957],{"class":601,"line":1449},[599,20958,20959],{"class":772},"    \u002F\u002F protection and rate limiting). `now` is the unix time.\n",[599,20961,20962,20965,20968,20970,20972,20974,20976,20978,20980,20982,20984,20986,20988,20990,20992,20994,20996],{"class":601,"line":1462},[599,20963,20964],{"class":609},"    OtpResult",[599,20966,20967],{"class":609}," VerifyOtp",[599,20969,679],{"class":666},[599,20971,682],{"class":605},[599,20973,685],{"class":609},[599,20975,688],{"class":666},[599,20977,902],{"class":609},[599,20979,694],{"class":605},[599,20981,5176],{"class":697},[599,20983,212],{"class":666},[599,20985,682],{"class":605},[599,20987,685],{"class":609},[599,20989,688],{"class":666},[599,20991,902],{"class":609},[599,20993,694],{"class":605},[599,20995,838],{"class":697},[599,20997,813],{"class":666},[599,20999,21000,21003,21005,21007,21009,21011,21014],{"class":601,"line":1477},[599,21001,21002],{"class":605},"                        uint64_t",[599,21004,918],{"class":697},[599,21006,212],{"class":666},[599,21008,18878],{"class":609},[599,21010,694],{"class":605},[599,21012,21013],{"class":697}," info",[599,21015,725],{"class":666},[599,21017,21018],{"class":601,"line":1483},[599,21019,981],{"class":666},[15,21021,21022,590],{},[69,21023,21024],{},"verify.cpp",[148,21026,21028],{"className":593,"code":21027,"language":595,"meta":154,"style":154},"#include \"verify.h\"\n#include \"store.h\"\n#include \"totp.h\"\n#include \u003Cvector>\n\nnamespace tac\n{\n    uint32_t LockMinutesFor(uint32_t failures)\n    {\n        if (failures \u003C kFreeFailures)\n            return 0;\n        uint32_t doublings = failures - kFreeFailures;   \u002F\u002F 0, 1, 2, ...\n        if (doublings > 4)\n            doublings = 4;                               \u002F\u002F 5 \u003C\u003C 4 = 80, capped below\n        uint32_t minutes = 5u \u003C\u003C doublings;\n        return minutes > 60 ? 60 : minutes;\n    }\n\n    static uint32_t MinutesLeft(uint64_t lockedUntil, uint64_t now)\n    {\n        uint64_t seconds = lockedUntil > now ? lockedUntil - now : 0;\n        return static_cast\u003Cuint32_t>((seconds + 59) \u002F 60);   \u002F\u002F round up\n    }\n\n    OtpResult VerifyOtp(const std::wstring& sid, const std::wstring& code,\n                        uint64_t now, OtpInfo& info)\n    {\n        info = {};\n\n        std::vector\u003CBYTE> key;\n        if (!LoadSecretKey(sid, key))\n            return OtpResult::NotEnrolled;\n\n        UserState state;\n        if (!LoadState(sid, state))\n        {\n            SecureZeroMemory(key.data(), key.size());\n            return OtpResult::Error;\n        }\n        info.failures = state.failures;\n\n        \u002F\u002F While the account is locked, the code is not checked at all.\n        \u002F\u002F Otherwise the lock would only hide the result, not stop the guessing.\n        if (state.lockedUntil > now)\n        {\n            SecureZeroMemory(key.data(), key.size());\n            info.minutesLeft = MinutesLeft(state.lockedUntil, now);\n            return OtpResult::LockedOut;\n        }\n\n        uint64_t matched = 0;\n        bool ok = ValidateTotp(key, code, now, state.lastStep, matched);\n\n        \u002F\u002F Only to write the right event: was it a correct code that was\n        \u002F\u002F already used? It still counts as a failure.\n        uint64_t ignored = 0;\n        bool replayed = !ok && state.lastStep != 0 && ValidateTotp(key, code, now, 0, ignored);\n        SecureZeroMemory(key.data(), key.size());\n\n        if (ok)\n        {\n            state.lastStep    = matched;\n            state.failures    = 0;\n            state.lockedUntil = 0;\n            info.step         = matched;\n\n            \u002F\u002F If the step cannot be saved, the same code would work again.\n            \u002F\u002F So this is an error and not a success.\n            return SaveState(sid, state) ? OtpResult::Ok : OtpResult::Error;\n        }\n\n        if (state.failures \u003C 0xFFFFFFFFu)\n            ++state.failures;\n        uint32_t minutes = LockMinutesFor(state.failures);\n        state.lockedUntil = minutes ? now + static_cast\u003Cuint64_t>(minutes) * 60 : 0;\n\n        info.failures    = state.failures;\n        info.minutesLeft = minutes;\n\n        if (!SaveState(sid, state))\n            return OtpResult::Error;\n        return replayed ? OtpResult::Replayed : OtpResult::Wrong;\n    }\n}\n",[69,21029,21030,21036,21042,21048,21054,21058,21064,21068,21082,21086,21098,21106,21126,21139,21153,21171,21191,21195,21199,21223,21227,21257,21283,21287,21291,21327,21343,21347,21356,21360,21375,21388,21397,21401,21408,21420,21424,21438,21447,21451,21461,21465,21470,21475,21487,21491,21505,21517,21526,21530,21534,21547,21560,21564,21569,21574,21587,21621,21635,21639,21646,21650,21660,21671,21681,21690,21694,21699,21704,21726,21730,21734,21752,21760,21773,21803,21807,21816,21825,21829,21841,21849,21869,21873],{"__ignoreMap":154},[599,21031,21032,21034],{"class":601,"line":602},[599,21033,616],{"class":605},[599,21035,15517],{"class":619},[599,21037,21038,21040],{"class":601,"line":613},[599,21039,616],{"class":605},[599,21041,5477],{"class":619},[599,21043,21044,21046],{"class":601,"line":623},[599,21045,616],{"class":605},[599,21047,998],{"class":619},[599,21049,21050,21052],{"class":601,"line":631},[599,21051,616],{"class":605},[599,21053,644],{"class":619},[599,21055,21056],{"class":601,"line":639},[599,21057,651],{"emptyLinePlaceholder":650},[599,21059,21060,21062],{"class":601,"line":647},[599,21061,657],{"class":605},[599,21063,660],{"class":609},[599,21065,21066],{"class":601,"line":654},[599,21067,667],{"class":666},[599,21069,21070,21072,21074,21076,21078,21080],{"class":601,"line":663},[599,21071,20664],{"class":605},[599,21073,20935],{"class":609},[599,21075,679],{"class":666},[599,21077,20940],{"class":605},[599,21079,20943],{"class":697},[599,21081,1029],{"class":666},[599,21083,21084],{"class":601,"line":670},[599,21085,1095],{"class":666},[599,21087,21088,21090,21093,21095],{"class":601,"line":728},[599,21089,1100],{"class":605},[599,21091,21092],{"class":666}," (failures ",[599,21094,711],{"class":605},[599,21096,21097],{"class":666}," kFreeFailures)\n",[599,21099,21100,21102,21104],{"class":601,"line":764},[599,21101,2040],{"class":605},[599,21103,1286],{"class":949},[599,21105,1066],{"class":666},[599,21107,21108,21110,21113,21115,21118,21120,21123],{"class":601,"line":769},[599,21109,1278],{"class":605},[599,21111,21112],{"class":666}," doublings ",[599,21114,1060],{"class":605},[599,21116,21117],{"class":666}," failures ",[599,21119,1132],{"class":605},[599,21121,21122],{"class":666}," kFreeFailures;",[599,21124,21125],{"class":772},"   \u002F\u002F 0, 1, 2, ...\n",[599,21127,21128,21130,21133,21135,21137],{"class":601,"line":776},[599,21129,1100],{"class":605},[599,21131,21132],{"class":666}," (doublings ",[599,21134,717],{"class":605},[599,21136,6716],{"class":949},[599,21138,1029],{"class":666},[599,21140,21141,21144,21146,21148,21150],{"class":601,"line":816},[599,21142,21143],{"class":666},"            doublings ",[599,21145,1060],{"class":605},[599,21147,6716],{"class":949},[599,21149,1549],{"class":666},[599,21151,21152],{"class":772},"                               \u002F\u002F 5 \u003C\u003C 4 = 80, capped below\n",[599,21154,21155,21157,21160,21162,21164,21166,21168],{"class":601,"line":843},[599,21156,1278],{"class":605},[599,21158,21159],{"class":666}," minutes ",[599,21161,1060],{"class":605},[599,21163,1435],{"class":949},[599,21165,1536],{"class":605},[599,21167,1539],{"class":605},[599,21169,21170],{"class":666}," doublings;\n",[599,21172,21173,21175,21177,21179,21182,21184,21186,21188],{"class":601,"line":848},[599,21174,1211],{"class":605},[599,21176,21159],{"class":666},[599,21178,717],{"class":605},[599,21180,21181],{"class":949}," 60",[599,21183,8953],{"class":605},[599,21185,21181],{"class":949},[599,21187,8962],{"class":605},[599,21189,21190],{"class":666}," minutes;\n",[599,21192,21193],{"class":601,"line":854},[599,21194,1224],{"class":666},[599,21196,21197],{"class":601,"line":860},[599,21198,651],{"emptyLinePlaceholder":650},[599,21200,21201,21203,21205,21208,21210,21212,21215,21217,21219,21221],{"class":601,"line":866},[599,21202,1048],{"class":605},[599,21204,20774],{"class":605},[599,21206,21207],{"class":609}," MinutesLeft",[599,21209,679],{"class":666},[599,21211,807],{"class":605},[599,21213,21214],{"class":697}," lockedUntil",[599,21216,212],{"class":666},[599,21218,807],{"class":605},[599,21220,918],{"class":697},[599,21222,1029],{"class":666},[599,21224,21225],{"class":601,"line":912},[599,21226,1095],{"class":666},[599,21228,21229,21231,21234,21236,21239,21241,21243,21245,21247,21249,21251,21253,21255],{"class":601,"line":938},[599,21230,2300],{"class":605},[599,21232,21233],{"class":666}," seconds ",[599,21235,1060],{"class":605},[599,21237,21238],{"class":666}," lockedUntil ",[599,21240,717],{"class":605},[599,21242,2975],{"class":666},[599,21244,9412],{"class":605},[599,21246,21238],{"class":666},[599,21248,1132],{"class":605},[599,21250,2975],{"class":666},[599,21252,590],{"class":605},[599,21254,1286],{"class":949},[599,21256,1066],{"class":666},[599,21258,21259,21261,21263,21266,21268,21271,21273,21275,21277,21280],{"class":601,"line":978},[599,21260,1211],{"class":605},[599,21262,1443],{"class":605},[599,21264,21265],{"class":666},"((seconds ",[599,21267,2543],{"class":605},[599,21269,21270],{"class":949}," 59",[599,21272,1124],{"class":666},[599,21274,2311],{"class":605},[599,21276,21181],{"class":949},[599,21278,21279],{"class":666},");",[599,21281,21282],{"class":772},"   \u002F\u002F round up\n",[599,21284,21285],{"class":601,"line":1316},[599,21286,1224],{"class":666},[599,21288,21289],{"class":601,"line":1321},[599,21290,651],{"emptyLinePlaceholder":650},[599,21292,21293,21295,21297,21299,21301,21303,21305,21307,21309,21311,21313,21315,21317,21319,21321,21323,21325],{"class":601,"line":1335},[599,21294,20964],{"class":609},[599,21296,20967],{"class":609},[599,21298,679],{"class":666},[599,21300,682],{"class":605},[599,21302,685],{"class":609},[599,21304,688],{"class":666},[599,21306,902],{"class":609},[599,21308,694],{"class":605},[599,21310,5176],{"class":697},[599,21312,212],{"class":666},[599,21314,682],{"class":605},[599,21316,685],{"class":609},[599,21318,688],{"class":666},[599,21320,902],{"class":609},[599,21322,694],{"class":605},[599,21324,838],{"class":697},[599,21326,813],{"class":666},[599,21328,21329,21331,21333,21335,21337,21339,21341],{"class":601,"line":1341},[599,21330,21002],{"class":605},[599,21332,918],{"class":697},[599,21334,212],{"class":666},[599,21336,18878],{"class":609},[599,21338,694],{"class":605},[599,21340,21013],{"class":697},[599,21342,1029],{"class":666},[599,21344,21345],{"class":601,"line":1367},[599,21346,1095],{"class":666},[599,21348,21349,21352,21354],{"class":601,"line":1375},[599,21350,21351],{"class":666},"        info ",[599,21353,1060],{"class":605},[599,21355,5921],{"class":666},[599,21357,21358],{"class":601,"line":1391},[599,21359,651],{"emptyLinePlaceholder":650},[599,21361,21362,21364,21366,21368,21370,21372],{"class":601,"line":1405},[599,21363,1624],{"class":609},[599,21365,688],{"class":666},[599,21367,708],{"class":609},[599,21369,711],{"class":666},[599,21371,714],{"class":609},[599,21373,21374],{"class":666},"> key;\n",[599,21376,21377,21379,21381,21383,21385],{"class":601,"line":1416},[599,21378,1100],{"class":605},[599,21380,1327],{"class":666},[599,21382,2435],{"class":605},[599,21384,9826],{"class":609},[599,21386,21387],{"class":666},"(sid, key))\n",[599,21389,21390,21392,21395],{"class":601,"line":1421},[599,21391,2040],{"class":605},[599,21393,21394],{"class":609}," OtpResult",[599,21396,18948],{"class":666},[599,21398,21399],{"class":601,"line":1449},[599,21400,651],{"emptyLinePlaceholder":650},[599,21402,21403,21406],{"class":601,"line":1462},[599,21404,21405],{"class":609},"        UserState",[599,21407,9276],{"class":666},[599,21409,21410,21412,21414,21416,21418],{"class":601,"line":1477},[599,21411,1100],{"class":605},[599,21413,1327],{"class":666},[599,21415,2435],{"class":605},[599,21417,8658],{"class":609},[599,21419,9294],{"class":666},[599,21421,21422],{"class":601,"line":1483},[599,21423,1338],{"class":666},[599,21425,21426,21428,21430,21432,21434,21436],{"class":601,"line":1496},[599,21427,12911],{"class":609},[599,21429,2087],{"class":666},[599,21431,2090],{"class":609},[599,21433,7791],{"class":666},[599,21435,2108],{"class":609},[599,21437,6864],{"class":666},[599,21439,21440,21442,21444],{"class":601,"line":1523},[599,21441,2040],{"class":605},[599,21443,21394],{"class":609},[599,21445,21446],{"class":666},"::Error;\n",[599,21448,21449],{"class":601,"line":1555},[599,21450,1564],{"class":666},[599,21452,21453,21456,21458],{"class":601,"line":1561},[599,21454,21455],{"class":666},"        info.failures ",[599,21457,1060],{"class":605},[599,21459,21460],{"class":666}," state.failures;\n",[599,21462,21463],{"class":601,"line":1567},[599,21464,651],{"emptyLinePlaceholder":650},[599,21466,21467],{"class":601,"line":1577},[599,21468,21469],{"class":772},"        \u002F\u002F While the account is locked, the code is not checked at all.\n",[599,21471,21472],{"class":601,"line":1582},[599,21473,21474],{"class":772},"        \u002F\u002F Otherwise the lock would only hide the result, not stop the guessing.\n",[599,21476,21477,21479,21482,21484],{"class":601,"line":1587},[599,21478,1100],{"class":605},[599,21480,21481],{"class":666}," (state.lockedUntil ",[599,21483,717],{"class":605},[599,21485,21486],{"class":666}," now)\n",[599,21488,21489],{"class":601,"line":1616},[599,21490,1338],{"class":666},[599,21492,21493,21495,21497,21499,21501,21503],{"class":601,"line":1621},[599,21494,12911],{"class":609},[599,21496,2087],{"class":666},[599,21498,2090],{"class":609},[599,21500,7791],{"class":666},[599,21502,2108],{"class":609},[599,21504,6864],{"class":666},[599,21506,21507,21510,21512,21514],{"class":601,"line":1634},[599,21508,21509],{"class":666},"            info.minutesLeft ",[599,21511,1060],{"class":605},[599,21513,21207],{"class":609},[599,21515,21516],{"class":666},"(state.lockedUntil, now);\n",[599,21518,21519,21521,21523],{"class":601,"line":1647},[599,21520,2040],{"class":605},[599,21522,21394],{"class":609},[599,21524,21525],{"class":666},"::LockedOut;\n",[599,21527,21528],{"class":601,"line":1660},[599,21529,1564],{"class":666},[599,21531,21532],{"class":601,"line":1665},[599,21533,651],{"emptyLinePlaceholder":650},[599,21535,21536,21538,21541,21543,21545],{"class":601,"line":1695},[599,21537,2300],{"class":605},[599,21539,21540],{"class":666}," matched ",[599,21542,1060],{"class":605},[599,21544,1286],{"class":949},[599,21546,1066],{"class":666},[599,21548,21549,21551,21553,21555,21557],{"class":601,"line":1700},[599,21550,1985],{"class":605},[599,21552,1988],{"class":666},[599,21554,1060],{"class":605},[599,21556,871],{"class":609},[599,21558,21559],{"class":666},"(key, code, now, state.lastStep, matched);\n",[599,21561,21562],{"class":601,"line":1720},[599,21563,651],{"emptyLinePlaceholder":650},[599,21565,21566],{"class":601,"line":1731},[599,21567,21568],{"class":772},"        \u002F\u002F Only to write the right event: was it a correct code that was\n",[599,21570,21571],{"class":601,"line":1745},[599,21572,21573],{"class":772},"        \u002F\u002F already used? It still counts as a failure.\n",[599,21575,21576,21578,21581,21583,21585],{"class":601,"line":1750},[599,21577,2300],{"class":605},[599,21579,21580],{"class":666}," ignored ",[599,21582,1060],{"class":605},[599,21584,1286],{"class":949},[599,21586,1066],{"class":666},[599,21588,21589,21591,21594,21596,21598,21600,21602,21605,21607,21609,21611,21613,21616,21618],{"class":601,"line":1761},[599,21590,1985],{"class":605},[599,21592,21593],{"class":666}," replayed ",[599,21595,1060],{"class":605},[599,21597,9609],{"class":605},[599,21599,7742],{"class":666},[599,21601,3154],{"class":605},[599,21603,21604],{"class":666}," state.lastStep ",[599,21606,2030],{"class":605},[599,21608,1286],{"class":949},[599,21610,1112],{"class":605},[599,21612,871],{"class":609},[599,21614,21615],{"class":666},"(key, code, now, ",[599,21617,2074],{"class":949},[599,21619,21620],{"class":666},", ignored);\n",[599,21622,21623,21625,21627,21629,21631,21633],{"class":601,"line":1787},[599,21624,6213],{"class":609},[599,21626,2087],{"class":666},[599,21628,2090],{"class":609},[599,21630,7791],{"class":666},[599,21632,2108],{"class":609},[599,21634,6864],{"class":666},[599,21636,21637],{"class":601,"line":1792},[599,21638,651],{"emptyLinePlaceholder":650},[599,21640,21641,21643],{"class":601,"line":1815},[599,21642,1100],{"class":605},[599,21644,21645],{"class":666}," (ok)\n",[599,21647,21648],{"class":601,"line":1820},[599,21649,1338],{"class":666},[599,21651,21652,21655,21657],{"class":601,"line":1833},[599,21653,21654],{"class":666},"            state.lastStep    ",[599,21656,1060],{"class":605},[599,21658,21659],{"class":666}," matched;\n",[599,21661,21662,21665,21667,21669],{"class":601,"line":1863},[599,21663,21664],{"class":666},"            state.failures    ",[599,21666,1060],{"class":605},[599,21668,1286],{"class":949},[599,21670,1066],{"class":666},[599,21672,21673,21675,21677,21679],{"class":601,"line":1870},[599,21674,9405],{"class":666},[599,21676,1060],{"class":605},[599,21678,1286],{"class":949},[599,21680,1066],{"class":666},[599,21682,21683,21686,21688],{"class":601,"line":1875},[599,21684,21685],{"class":666},"            info.step         ",[599,21687,1060],{"class":605},[599,21689,21659],{"class":666},[599,21691,21692],{"class":601,"line":1880},[599,21693,651],{"emptyLinePlaceholder":650},[599,21695,21696],{"class":601,"line":1946},[599,21697,21698],{"class":772},"            \u002F\u002F If the step cannot be saved, the same code would work again.\n",[599,21700,21701],{"class":601,"line":1951},[599,21702,21703],{"class":772},"            \u002F\u002F So this is an error and not a success.\n",[599,21705,21706,21708,21710,21713,21715,21717,21720,21722,21724],{"class":601,"line":1967},[599,21707,2040],{"class":605},[599,21709,5406],{"class":609},[599,21711,21712],{"class":666},"(sid, state) ",[599,21714,9412],{"class":605},[599,21716,21394],{"class":609},[599,21718,21719],{"class":666},"::Ok ",[599,21721,590],{"class":605},[599,21723,21394],{"class":609},[599,21725,21446],{"class":666},[599,21727,21728],{"class":601,"line":1982},[599,21729,1564],{"class":666},[599,21731,21732],{"class":601,"line":1997},[599,21733,651],{"emptyLinePlaceholder":650},[599,21735,21736,21738,21741,21743,21745,21748,21750],{"class":601,"line":2002},[599,21737,1100],{"class":605},[599,21739,21740],{"class":666}," (state.failures ",[599,21742,711],{"class":605},[599,21744,1778],{"class":605},[599,21746,21747],{"class":949},"FFFFFFFF",[599,21749,1536],{"class":605},[599,21751,1029],{"class":666},[599,21753,21754,21757],{"class":601,"line":2024},[599,21755,21756],{"class":605},"            ++",[599,21758,21759],{"class":666},"state.failures;\n",[599,21761,21762,21764,21766,21768,21770],{"class":601,"line":2037},[599,21763,1278],{"class":605},[599,21765,21159],{"class":666},[599,21767,1060],{"class":605},[599,21769,20935],{"class":609},[599,21771,21772],{"class":666},"(state.failures);\n",[599,21774,21775,21778,21780,21782,21784,21786,21788,21790,21793,21795,21797,21799,21801],{"class":601,"line":2047},[599,21776,21777],{"class":666},"        state.lockedUntil ",[599,21779,1060],{"class":605},[599,21781,21159],{"class":666},[599,21783,9412],{"class":605},[599,21785,2975],{"class":666},[599,21787,2543],{"class":605},[599,21789,3034],{"class":605},[599,21791,21792],{"class":666},"(minutes) ",[599,21794,748],{"class":605},[599,21796,21181],{"class":949},[599,21798,8962],{"class":605},[599,21800,1286],{"class":949},[599,21802,1066],{"class":666},[599,21804,21805],{"class":601,"line":2052},[599,21806,651],{"emptyLinePlaceholder":650},[599,21808,21809,21812,21814],{"class":601,"line":2096},[599,21810,21811],{"class":666},"        info.failures    ",[599,21813,1060],{"class":605},[599,21815,21460],{"class":666},[599,21817,21818,21821,21823],{"class":601,"line":2124},[599,21819,21820],{"class":666},"        info.minutesLeft ",[599,21822,1060],{"class":605},[599,21824,21190],{"class":666},[599,21826,21827],{"class":601,"line":2129},[599,21828,651],{"emptyLinePlaceholder":650},[599,21830,21831,21833,21835,21837,21839],{"class":601,"line":2163},[599,21832,1100],{"class":605},[599,21834,1327],{"class":666},[599,21836,2435],{"class":605},[599,21838,8664],{"class":609},[599,21840,9294],{"class":666},[599,21842,21843,21845,21847],{"class":601,"line":2186},[599,21844,2040],{"class":605},[599,21846,21394],{"class":609},[599,21848,21446],{"class":666},[599,21850,21851,21853,21855,21857,21859,21862,21864,21866],{"class":601,"line":2195},[599,21852,1211],{"class":605},[599,21854,21593],{"class":666},[599,21856,9412],{"class":605},[599,21858,21394],{"class":609},[599,21860,21861],{"class":666},"::Replayed ",[599,21863,590],{"class":605},[599,21865,21394],{"class":609},[599,21867,21868],{"class":666},"::Wrong;\n",[599,21870,21871],{"class":601,"line":2200},[599,21872,1224],{"class":666},[599,21874,21875],{"class":601,"line":2212},[599,21876,981],{"class":666},[15,21878,21879],{},"Some decisions I want to explain.",[15,21881,21882,21885,21886,21888],{},[47,21883,21884],{},"While the account is locked, the code is not checked at all."," This is the most important part. If you check the code and only hide the result, the attacker can still guess. He just doesn't see the answer until the lock is over, and then he tries the codes again that are still valid. Here a locked account never gets to ",[69,21887,3225],{},". Attempts during the lock are not counted either. Otherwise every attempt would make the lock longer and the user would never get back in.",[15,21890,21891,21894,21895,21897],{},[47,21892,21893],{},"An already used code counts as a wrong code."," It is a correct code, but someone tries to use it a second time. That is exactly what should not happen. To write the right event I check a second time without ",[69,21896,3272],{},". This only decides between \"wrong\" and \"already used\" in the log. It never lets anything through.",[15,21899,21900,21903],{},[47,21901,21902],{},"Fail closed."," If the state can't be read or written, the logon is refused. On success this is critical: if the used step can't be saved, the same code would work again. On failure it's just as important, otherwise an attacker who makes the write fail would have unlimited guesses. The only thing that breaks the write is a broken registry, and then you have other problems.",[15,21905,21906,21909,21910,21912,21913,21915],{},[47,21907,21908],{},"The step is burned before the password is checked."," The state is saved in ",[69,21911,237],{},", before the password goes to LSA. If the password is wrong, the code is gone and the user has to wait for the next one. That's a bit annoying. But the other way around is worse: the provider only learns the result in ",[69,21914,20332],{},", and between these two calls a second session could use the same code.",[15,21917,21918,21921,21922,21925],{},[47,21919,21920],{},"Denial of service."," Anyone who can reach the tile can lock an account with 5 wrong codes. This is the same with the normal Windows lockout policy. At the console someone has to be in front of the machine. For RDP it depends on NLA: with NLA the attacker needs the password to even see our tile. Without NLA anybody who reaches port 3389 can lock your users. So leave NLA on. Unlike the Windows lockout, my lock also hits the built-in Administrator. If your break-glass account is locked, another admin runs ",[69,21923,21924],{},"enroll.exe \u002Funlock",", or you wait at most 60 minutes.",[15,21927,21928,21931],{},[47,21929,21930],{},"The clock."," The lock uses the unix time, just like TOTP. Someone who sets the clock forward in the BIOS skips the lock. But that is someone with physical access, and for them there are easier ways. See \"Attacks that never touch the tile\".",[15,21933,21934,21937],{},[47,21935,21936],{},"Parallel sessions."," On a server with RDP there can be several LogonUI processes at the same time, one per session. Reading and writing the state is not atomic across these processes. If an attacker sends guesses in several sessions in exactly the same millisecond, each of them can get one extra guess past the lock. It doesn't get worse than that, because the lock is written after every guess. A real product does the check in one central Windows service. I didn't want an extra service for the demo. A named mutex looks like the easy fix, but a normal user can create a mutex with the same name first and then block every logon. Named objects shared across sessions are only safe in a private namespace, and that is more code than the problem is worth here.",[10,21939,21941],{"id":21940},"logging","Logging",[15,21943,21944],{},"The counter stops a brute-force attack, but you still want to know that it happened. A wrong code never reaches LSA, so there is no event 4625 in the Security log. The provider has to write its own events.",[15,21946,21947,21948,590],{},"I write them into the Application log with the source ",[69,21949,21950],{},"TheAdminCafe 2FA",[277,21952,21953,21965],{},[280,21954,21955],{},[283,21956,21957,21960,21963],{},[286,21958,21959],{},"ID",[286,21961,21962],{},"Type",[286,21964,291],{},[293,21966,21967,21977,21988,21998,22008,22019,22029],{},[283,21968,21969,21971,21974],{},[298,21970,11665],{},[298,21972,21973],{},"Information",[298,21975,21976],{},"Valid code, the password goes to LSA",[283,21978,21979,21982,21985],{},[298,21980,21981],{},"101",[298,21983,21984],{},"Warning",[298,21986,21987],{},"Wrong code",[283,21989,21990,21993,21995],{},[298,21991,21992],{},"102",[298,21994,21984],{},[298,21996,21997],{},"Code was already used",[283,21999,22000,22003,22005],{},[298,22001,22002],{},"103",[298,22004,21984],{},[298,22006,22007],{},"Attempt while the account is locked",[283,22009,22010,22013,22016],{},[298,22011,22012],{},"104",[298,22014,22015],{},"Error",[298,22017,22018],{},"This wrong code locked the account",[283,22020,22021,22024,22026],{},[298,22022,22023],{},"105",[298,22025,21984],{},[298,22027,22028],{},"Account unknown or not enrolled",[283,22030,22031,22034,22036],{},[298,22032,22033],{},"106",[298,22035,22015],{},[298,22037,22038],{},"State could not be read or written, logon refused",[15,22040,22041],{},"Every event has the account, the SID, the number of wrong codes in a row and where the attempt came from. For RDP this is the IP address of the client. The code itself is never logged, not even a wrong one. A wrong code is often just a typo of the right one.",[15,22043,22044,590],{},[69,22045,22046],{},"eventlog.h",[148,22048,22050],{"className":593,"code":22049,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Cstring>\n\nnamespace tac\n{\n    \u002F\u002F Event IDs in the Application log, source \"TheAdminCafe 2FA\".\n    enum : DWORD\n    {\n        EVT_CODE_OK       = 100,\n        EVT_CODE_WRONG    = 101,\n        EVT_CODE_REPLAYED = 102,\n        EVT_LOCKED_OUT    = 103,   \u002F\u002F attempt while the account was locked\n        EVT_LOCK_STARTED  = 104,   \u002F\u002F this attempt locked the account\n        EVT_NOT_ENROLLED  = 105,\n        EVT_ERROR         = 106,\n    };\n\n    \u002F\u002F Writes one line of text. Never throws, never shows UI. If the event log\n    \u002F\u002F is not reachable, the event is lost and the logon goes on.\n    void LogEvent(WORD type, DWORD id, const std::wstring& text);\n\n    \u002F\u002F \"console, session 1\" or \"remote from 192.168.1.50, session 3\".\n    std::wstring DescribeSession();\n}\n",[69,22051,22052,22058,22064,22070,22074,22080,22084,22089,22098,22102,22115,22128,22140,22155,22170,22182,22195,22199,22203,22208,22213,22251,22255,22260,22273],{"__ignoreMap":154},[599,22053,22054,22056],{"class":601,"line":602},[599,22055,606],{"class":605},[599,22057,610],{"class":609},[599,22059,22060,22062],{"class":601,"line":613},[599,22061,616],{"class":605},[599,22063,620],{"class":619},[599,22065,22066,22068],{"class":601,"line":623},[599,22067,616],{"class":605},[599,22069,636],{"class":619},[599,22071,22072],{"class":601,"line":631},[599,22073,651],{"emptyLinePlaceholder":650},[599,22075,22076,22078],{"class":601,"line":639},[599,22077,657],{"class":605},[599,22079,660],{"class":609},[599,22081,22082],{"class":601,"line":647},[599,22083,667],{"class":666},[599,22085,22086],{"class":601,"line":654},[599,22087,22088],{"class":772},"    \u002F\u002F Event IDs in the Application log, source \"TheAdminCafe 2FA\".\n",[599,22090,22091,22093,22095],{"class":601,"line":663},[599,22092,20792],{"class":605},[599,22094,10957],{"class":666},[599,22096,22097],{"class":605},"DWORD\n",[599,22099,22100],{"class":601,"line":670},[599,22101,1095],{"class":666},[599,22103,22104,22107,22110,22113],{"class":601,"line":728},[599,22105,22106],{"class":949},"        EVT_CODE_OK",[599,22108,22109],{"class":605},"       =",[599,22111,22112],{"class":949}," 100",[599,22114,813],{"class":666},[599,22116,22117,22120,22123,22126],{"class":601,"line":764},[599,22118,22119],{"class":949},"        EVT_CODE_WRONG",[599,22121,22122],{"class":605},"    =",[599,22124,22125],{"class":949}," 101",[599,22127,813],{"class":666},[599,22129,22130,22133,22135,22138],{"class":601,"line":769},[599,22131,22132],{"class":949},"        EVT_CODE_REPLAYED",[599,22134,946],{"class":605},[599,22136,22137],{"class":949}," 102",[599,22139,813],{"class":666},[599,22141,22142,22145,22147,22150,22152],{"class":601,"line":776},[599,22143,22144],{"class":949},"        EVT_LOCKED_OUT",[599,22146,22122],{"class":605},[599,22148,22149],{"class":949}," 103",[599,22151,10558],{"class":666},[599,22153,22154],{"class":772},"   \u002F\u002F attempt while the account was locked\n",[599,22156,22157,22160,22162,22165,22167],{"class":601,"line":816},[599,22158,22159],{"class":949},"        EVT_LOCK_STARTED",[599,22161,10529],{"class":605},[599,22163,22164],{"class":949}," 104",[599,22166,10558],{"class":666},[599,22168,22169],{"class":772},"   \u002F\u002F this attempt locked the account\n",[599,22171,22172,22175,22177,22180],{"class":601,"line":843},[599,22173,22174],{"class":949},"        EVT_NOT_ENROLLED",[599,22176,10529],{"class":605},[599,22178,22179],{"class":949}," 105",[599,22181,813],{"class":666},[599,22183,22184,22187,22190,22193],{"class":601,"line":848},[599,22185,22186],{"class":949},"        EVT_ERROR",[599,22188,22189],{"class":605},"         =",[599,22191,22192],{"class":949}," 106",[599,22194,813],{"class":666},[599,22196,22197],{"class":601,"line":854},[599,22198,5334],{"class":666},[599,22200,22201],{"class":601,"line":860},[599,22202,651],{"emptyLinePlaceholder":650},[599,22204,22205],{"class":601,"line":866},[599,22206,22207],{"class":772},"    \u002F\u002F Writes one line of text. Never throws, never shows UI. If the event log\n",[599,22209,22210],{"class":601,"line":912},[599,22211,22212],{"class":772},"    \u002F\u002F is not reachable, the event is lost and the logon goes on.\n",[599,22214,22215,22217,22220,22222,22225,22228,22230,22232,22235,22237,22239,22241,22243,22245,22247,22249],{"class":601,"line":938},[599,22216,11334],{"class":605},[599,22218,22219],{"class":609}," LogEvent",[599,22221,679],{"class":666},[599,22223,22224],{"class":609},"WORD",[599,22226,22227],{"class":697}," type",[599,22229,212],{"class":666},[599,22231,5878],{"class":609},[599,22233,22234],{"class":697}," id",[599,22236,212],{"class":666},[599,22238,682],{"class":605},[599,22240,685],{"class":609},[599,22242,688],{"class":666},[599,22244,902],{"class":609},[599,22246,694],{"class":605},[599,22248,8880],{"class":697},[599,22250,725],{"class":666},[599,22252,22253],{"class":601,"line":978},[599,22254,651],{"emptyLinePlaceholder":650},[599,22256,22257],{"class":601,"line":1316},[599,22258,22259],{"class":772},"    \u002F\u002F \"console, session 1\" or \"remote from 192.168.1.50, session 3\".\n",[599,22261,22262,22264,22266,22268,22271],{"class":601,"line":1321},[599,22263,731],{"class":609},[599,22265,688],{"class":666},[599,22267,902],{"class":609},[599,22269,22270],{"class":609}," DescribeSession",[599,22272,1313],{"class":666},[599,22274,22275],{"class":601,"line":1335},[599,22276,981],{"class":666},[15,22278,22279,590],{},[69,22280,22281],{},"eventlog.cpp",[148,22283,22285],{"className":593,"code":22284,"language":595,"meta":154,"style":154},"#include \"eventlog.h\"\n#include \u003Cwtsapi32.h>\n#include \u003Ccstdio>\n\n#pragma comment(lib, \"advapi32.lib\")\n#pragma comment(lib, \"user32.lib\")\n#pragma comment(lib, \"wtsapi32.lib\")\n\nnamespace tac\n{\n    static const wchar_t kSource[] = L\"TheAdminCafe 2FA\";\n\n    void LogEvent(WORD type, DWORD id, const std::wstring& text)\n    {\n        HANDLE hLog = RegisterEventSourceW(nullptr, kSource);\n        if (!hLog)\n            return;\n\n        LPCWSTR strings[1] = { text.c_str() };\n        ReportEventW(hLog, type, 0, id, nullptr, 1, 0, strings, nullptr);\n        DeregisterEventSource(hLog);\n    }\n\n    std::wstring DescribeSession()\n    {\n        DWORD sessionId = 0;\n        ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);\n\n        wchar_t buf[96];\n        if (!GetSystemMetrics(SM_REMOTESESSION))\n        {\n            swprintf_s(buf, L\"console, session %lu\", sessionId);\n            return buf;\n        }\n\n        \u002F\u002F For RDP, add the client address. LogonUI runs in the session of the\n        \u002F\u002F connection, so WTS_CURRENT_SESSION is the right one.\n        std::wstring from = L\"unknown address\";\n        WTS_CLIENT_ADDRESS* addr = nullptr;\n        DWORD cb = 0;\n        if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,\n                                        WTSClientAddress, reinterpret_cast\u003CLPWSTR*>(&addr), &cb) &&\n            addr && cb >= sizeof(*addr))\n        {\n            if (addr->AddressFamily == AF_INET)\n            {\n                \u002F\u002F For IPv4 the address starts at offset 2 of the byte array.\n                wchar_t ip[16];\n                swprintf_s(ip, L\"%u.%u.%u.%u\", addr->Address[2], addr->Address[3],\n                           addr->Address[4], addr->Address[5]);\n                from = ip;\n            }\n            else\n            {\n                from = L\"non-IPv4 address\";\n            }\n        }\n        if (addr)\n            WTSFreeMemory(addr);\n\n        swprintf_s(buf, L\"remote from %s, session %lu\", from.c_str(), sessionId);\n        return buf;\n    }\n}\n",[69,22286,22287,22293,22300,22306,22310,22326,22342,22359,22363,22369,22373,22391,22395,22429,22433,22453,22464,22470,22474,22493,22523,22531,22535,22539,22551,22555,22568,22585,22589,22601,22615,22619,22637,22644,22648,22652,22657,22662,22680,22696,22708,22720,22747,22767,22771,22783,22787,22792,22804,22842,22855,22865,22869,22874,22878,22889,22893,22897,22904,22912,22916,22943,22949,22953],{"__ignoreMap":154},[599,22288,22289,22291],{"class":601,"line":602},[599,22290,616],{"class":605},[599,22292,15524],{"class":619},[599,22294,22295,22297],{"class":601,"line":613},[599,22296,616],{"class":605},[599,22298,22299],{"class":619}," \u003Cwtsapi32.h>\n",[599,22301,22302,22304],{"class":601,"line":623},[599,22303,616],{"class":605},[599,22305,8787],{"class":619},[599,22307,22308],{"class":601,"line":631},[599,22309,651],{"emptyLinePlaceholder":650},[599,22311,22312,22314,22316,22318,22320,22322,22324],{"class":601,"line":639},[599,22313,606],{"class":605},[599,22315,1016],{"class":609},[599,22317,679],{"class":666},[599,22319,1021],{"class":609},[599,22321,212],{"class":666},[599,22323,5540],{"class":619},[599,22325,1029],{"class":666},[599,22327,22328,22330,22332,22334,22336,22338,22340],{"class":601,"line":647},[599,22329,606],{"class":605},[599,22331,1016],{"class":609},[599,22333,679],{"class":666},[599,22335,1021],{"class":609},[599,22337,212],{"class":666},[599,22339,15631],{"class":619},[599,22341,1029],{"class":666},[599,22343,22344,22346,22348,22350,22352,22354,22357],{"class":601,"line":654},[599,22345,606],{"class":605},[599,22347,1016],{"class":609},[599,22349,679],{"class":666},[599,22351,1021],{"class":609},[599,22353,212],{"class":666},[599,22355,22356],{"class":619},"\"wtsapi32.lib\"",[599,22358,1029],{"class":666},[599,22360,22361],{"class":601,"line":663},[599,22362,651],{"emptyLinePlaceholder":650},[599,22364,22365,22367],{"class":601,"line":670},[599,22366,657],{"class":605},[599,22368,660],{"class":609},[599,22370,22371],{"class":601,"line":728},[599,22372,667],{"class":666},[599,22374,22375,22377,22379,22381,22384,22386,22389],{"class":601,"line":764},[599,22376,1048],{"class":605},[599,22378,1051],{"class":605},[599,22380,5565],{"class":605},[599,22382,22383],{"class":666}," kSource[] ",[599,22385,1060],{"class":605},[599,22387,22388],{"class":619}," L\"TheAdminCafe 2FA\"",[599,22390,1066],{"class":666},[599,22392,22393],{"class":601,"line":769},[599,22394,651],{"emptyLinePlaceholder":650},[599,22396,22397,22399,22401,22403,22405,22407,22409,22411,22413,22415,22417,22419,22421,22423,22425,22427],{"class":601,"line":776},[599,22398,11334],{"class":605},[599,22400,22219],{"class":609},[599,22402,679],{"class":666},[599,22404,22224],{"class":609},[599,22406,22227],{"class":697},[599,22408,212],{"class":666},[599,22410,5878],{"class":609},[599,22412,22234],{"class":697},[599,22414,212],{"class":666},[599,22416,682],{"class":605},[599,22418,685],{"class":609},[599,22420,688],{"class":666},[599,22422,902],{"class":609},[599,22424,694],{"class":605},[599,22426,8880],{"class":697},[599,22428,1029],{"class":666},[599,22430,22431],{"class":601,"line":816},[599,22432,1095],{"class":666},[599,22434,22435,22438,22441,22443,22446,22448,22450],{"class":601,"line":843},[599,22436,22437],{"class":609},"        HANDLE",[599,22439,22440],{"class":666}," hLog ",[599,22442,1060],{"class":605},[599,22444,22445],{"class":609}," RegisterEventSourceW",[599,22447,679],{"class":666},[599,22449,2019],{"class":949},[599,22451,22452],{"class":666},", kSource);\n",[599,22454,22455,22457,22459,22461],{"class":601,"line":848},[599,22456,1100],{"class":605},[599,22458,1327],{"class":666},[599,22460,2435],{"class":605},[599,22462,22463],{"class":666},"hLog)\n",[599,22465,22466,22468],{"class":601,"line":854},[599,22467,2040],{"class":605},[599,22469,1066],{"class":666},[599,22471,22472],{"class":601,"line":860},[599,22473,651],{"emptyLinePlaceholder":650},[599,22475,22476,22479,22481,22483,22485,22488,22490],{"class":601,"line":866},[599,22477,22478],{"class":666},"        LPCWSTR strings[",[599,22480,1217],{"class":949},[599,22482,2491],{"class":666},[599,22484,1060],{"class":605},[599,22486,22487],{"class":666}," { text.",[599,22489,6513],{"class":609},[599,22491,22492],{"class":666},"() };\n",[599,22494,22495,22498,22501,22503,22506,22508,22510,22512,22514,22516,22519,22521],{"class":601,"line":912},[599,22496,22497],{"class":609},"        ReportEventW",[599,22499,22500],{"class":666},"(hLog, type, ",[599,22502,2074],{"class":949},[599,22504,22505],{"class":666},", id, ",[599,22507,2019],{"class":949},[599,22509,212],{"class":666},[599,22511,1217],{"class":949},[599,22513,212],{"class":666},[599,22515,2074],{"class":949},[599,22517,22518],{"class":666},", strings, ",[599,22520,2019],{"class":949},[599,22522,725],{"class":666},[599,22524,22525,22528],{"class":601,"line":938},[599,22526,22527],{"class":609},"        DeregisterEventSource",[599,22529,22530],{"class":666},"(hLog);\n",[599,22532,22533],{"class":601,"line":978},[599,22534,1224],{"class":666},[599,22536,22537],{"class":601,"line":1316},[599,22538,651],{"emptyLinePlaceholder":650},[599,22540,22541,22543,22545,22547,22549],{"class":601,"line":1321},[599,22542,731],{"class":609},[599,22544,688],{"class":666},[599,22546,902],{"class":609},[599,22548,22270],{"class":609},[599,22550,3717],{"class":666},[599,22552,22553],{"class":601,"line":1335},[599,22554,1095],{"class":666},[599,22556,22557,22559,22562,22564,22566],{"class":601,"line":1341},[599,22558,6357],{"class":609},[599,22560,22561],{"class":666}," sessionId ",[599,22563,1060],{"class":605},[599,22565,1286],{"class":949},[599,22567,1066],{"class":666},[599,22569,22570,22573,22575,22578,22580,22582],{"class":601,"line":1367},[599,22571,22572],{"class":609},"        ProcessIdToSessionId",[599,22574,679],{"class":666},[599,22576,22577],{"class":609},"GetCurrentProcessId",[599,22579,7241],{"class":666},[599,22581,694],{"class":605},[599,22583,22584],{"class":666},"sessionId);\n",[599,22586,22587],{"class":601,"line":1375},[599,22588,651],{"emptyLinePlaceholder":650},[599,22590,22591,22593,22596,22599],{"class":601,"line":1391},[599,22592,19060],{"class":605},[599,22594,22595],{"class":666}," buf[",[599,22597,22598],{"class":949},"96",[599,22600,1784],{"class":666},[599,22602,22603,22605,22607,22609,22612],{"class":601,"line":1405},[599,22604,1100],{"class":605},[599,22606,1327],{"class":666},[599,22608,2435],{"class":605},[599,22610,22611],{"class":609},"GetSystemMetrics",[599,22613,22614],{"class":666},"(SM_REMOTESESSION))\n",[599,22616,22617],{"class":601,"line":1416},[599,22618,1338],{"class":666},[599,22620,22621,22623,22626,22629,22632,22634],{"class":601,"line":1421},[599,22622,19462],{"class":609},[599,22624,22625],{"class":666},"(buf, ",[599,22627,22628],{"class":619},"L\"console, session ",[599,22630,22631],{"class":949},"%lu",[599,22633,4362],{"class":619},[599,22635,22636],{"class":666},", sessionId);\n",[599,22638,22639,22641],{"class":601,"line":1449},[599,22640,2040],{"class":605},[599,22642,22643],{"class":666}," buf;\n",[599,22645,22646],{"class":601,"line":1462},[599,22647,1564],{"class":666},[599,22649,22650],{"class":601,"line":1477},[599,22651,651],{"emptyLinePlaceholder":650},[599,22653,22654],{"class":601,"line":1483},[599,22655,22656],{"class":772},"        \u002F\u002F For RDP, add the client address. LogonUI runs in the session of the\n",[599,22658,22659],{"class":601,"line":1496},[599,22660,22661],{"class":772},"        \u002F\u002F connection, so WTS_CURRENT_SESSION is the right one.\n",[599,22663,22664,22666,22668,22670,22673,22675,22678],{"class":601,"line":1523},[599,22665,1624],{"class":609},[599,22667,688],{"class":666},[599,22669,902],{"class":609},[599,22671,22672],{"class":666}," from ",[599,22674,1060],{"class":605},[599,22676,22677],{"class":619}," L\"unknown address\"",[599,22679,1066],{"class":666},[599,22681,22682,22685,22687,22690,22692,22694],{"class":601,"line":1555},[599,22683,22684],{"class":609},"        WTS_CLIENT_ADDRESS",[599,22686,748],{"class":605},[599,22688,22689],{"class":666}," addr ",[599,22691,1060],{"class":605},[599,22693,1962],{"class":949},[599,22695,1066],{"class":666},[599,22697,22698,22700,22702,22704,22706],{"class":601,"line":1561},[599,22699,6357],{"class":609},[599,22701,7454],{"class":666},[599,22703,1060],{"class":605},[599,22705,1286],{"class":949},[599,22707,1066],{"class":666},[599,22709,22710,22712,22714,22717],{"class":601,"line":1567},[599,22711,1100],{"class":605},[599,22713,1327],{"class":666},[599,22715,22716],{"class":609},"WTSQuerySessionInformationW",[599,22718,22719],{"class":666},"(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,\n",[599,22721,22722,22725,22728,22731,22733,22735,22737,22740,22742,22745],{"class":601,"line":1577},[599,22723,22724],{"class":666},"                                        WTSClientAddress, ",[599,22726,22727],{"class":605},"reinterpret_cast\u003C",[599,22729,22730],{"class":666},"LPWSTR",[599,22732,5897],{"class":605},[599,22734,679],{"class":666},[599,22736,694],{"class":605},[599,22738,22739],{"class":666},"addr), ",[599,22741,694],{"class":605},[599,22743,22744],{"class":666},"cb) ",[599,22746,13492],{"class":605},[599,22748,22749,22752,22754,22756,22758,22760,22762,22764],{"class":601,"line":1582},[599,22750,22751],{"class":666},"            addr ",[599,22753,3154],{"class":605},[599,22755,7454],{"class":666},[599,22757,1106],{"class":605},[599,22759,6453],{"class":605},[599,22761,679],{"class":666},[599,22763,748],{"class":605},[599,22765,22766],{"class":666},"addr))\n",[599,22768,22769],{"class":601,"line":1587},[599,22770,1338],{"class":666},[599,22772,22773,22775,22778,22780],{"class":601,"line":1616},[599,22774,1344],{"class":605},[599,22776,22777],{"class":666}," (addr->AddressFamily ",[599,22779,1349],{"class":605},[599,22781,22782],{"class":666}," AF_INET)\n",[599,22784,22785],{"class":601,"line":1621},[599,22786,1480],{"class":666},[599,22788,22789],{"class":601,"line":1634},[599,22790,22791],{"class":772},"                \u002F\u002F For IPv4 the address starts at offset 2 of the byte array.\n",[599,22793,22794,22797,22800,22802],{"class":601,"line":1647},[599,22795,22796],{"class":605},"                wchar_t",[599,22798,22799],{"class":666}," ip[",[599,22801,4001],{"class":949},[599,22803,1784],{"class":666},[599,22805,22806,22808,22811,22813,22815,22817,22819,22821,22823,22825,22827,22829,22832,22834,22837,22839],{"class":601,"line":1660},[599,22807,19337],{"class":609},[599,22809,22810],{"class":666},"(ip, ",[599,22812,9891],{"class":619},[599,22814,9382],{"class":949},[599,22816,3242],{"class":619},[599,22818,9382],{"class":949},[599,22820,3242],{"class":619},[599,22822,9382],{"class":949},[599,22824,3242],{"class":619},[599,22826,9382],{"class":949},[599,22828,4362],{"class":619},[599,22830,22831],{"class":666},", addr->Address[",[599,22833,4012],{"class":949},[599,22835,22836],{"class":666},"], addr->Address[",[599,22838,4036],{"class":949},[599,22840,22841],{"class":666},"],\n",[599,22843,22844,22847,22849,22851,22853],{"class":601,"line":1665},[599,22845,22846],{"class":666},"                           addr->Address[",[599,22848,6732],{"class":949},[599,22850,22836],{"class":666},[599,22852,1847],{"class":949},[599,22854,9707],{"class":666},[599,22856,22857,22860,22862],{"class":601,"line":1695},[599,22858,22859],{"class":666},"                from ",[599,22861,1060],{"class":605},[599,22863,22864],{"class":666}," ip;\n",[599,22866,22867],{"class":601,"line":1700},[599,22868,1558],{"class":666},[599,22870,22871],{"class":601,"line":1720},[599,22872,22873],{"class":605},"            else\n",[599,22875,22876],{"class":601,"line":1731},[599,22877,1480],{"class":666},[599,22879,22880,22882,22884,22887],{"class":601,"line":1745},[599,22881,22859],{"class":666},[599,22883,1060],{"class":605},[599,22885,22886],{"class":619}," L\"non-IPv4 address\"",[599,22888,1066],{"class":666},[599,22890,22891],{"class":601,"line":1750},[599,22892,1558],{"class":666},[599,22894,22895],{"class":601,"line":1761},[599,22896,1564],{"class":666},[599,22898,22899,22901],{"class":601,"line":1787},[599,22900,1100],{"class":605},[599,22902,22903],{"class":666}," (addr)\n",[599,22905,22906,22909],{"class":601,"line":1792},[599,22907,22908],{"class":609},"            WTSFreeMemory",[599,22910,22911],{"class":666},"(addr);\n",[599,22913,22914],{"class":601,"line":1815},[599,22915,651],{"emptyLinePlaceholder":650},[599,22917,22918,22921,22923,22926,22928,22931,22933,22935,22938,22940],{"class":601,"line":1820},[599,22919,22920],{"class":609},"        swprintf_s",[599,22922,22625],{"class":666},[599,22924,22925],{"class":619},"L\"remote from ",[599,22927,9311],{"class":949},[599,22929,22930],{"class":619},", session ",[599,22932,22631],{"class":949},[599,22934,4362],{"class":619},[599,22936,22937],{"class":666},", from.",[599,22939,6513],{"class":609},[599,22941,22942],{"class":666},"(), sessionId);\n",[599,22944,22945,22947],{"class":601,"line":1833},[599,22946,1211],{"class":605},[599,22948,22643],{"class":666},[599,22950,22951],{"class":601,"line":1863},[599,22952,1224],{"class":666},[599,22954,22955],{"class":601,"line":1870},[599,22956,981],{"class":666},[15,22958,22959],{},"Some details:",[56,22961,22962,22972,22978],{},[59,22963,22964,22967,22968,22971],{},[69,22965,22966],{},"RegisterEventSourceW"," opens the log for every event and ",[69,22969,22970],{},"DeregisterEventSource"," closes it again. That is a bit slower, but LogonUI loads and unloads our DLL whenever it wants. A handle that stays open is one more thing that can go wrong.",[59,22973,22974,22975,22977],{},"Logging must never block the logon. If the event log isn't reachable, the event is simply lost. ",[69,22976,19127],{}," doesn't return an error, on purpose.",[59,22979,22980,22983,22984,22987,22988,22991],{},[69,22981,22982],{},"SM_REMOTESESSION"," tells me if LogonUI runs in an RDP session. LogonUI runs in the session of the connection, so ",[69,22985,22986],{},"WTS_CURRENT_SESSION"," is the right session to ask for the client address. For IPv4 the address starts at byte 2 of the array. That's how ",[69,22989,22990],{},"WTS_CLIENT_ADDRESS"," is defined.",[15,22993,22994,22995,22998,22999,23002,23003,23005,23006,23008],{},"Windows wants a message file for every event source. Without it Event Viewer shows \"The description for Event ID 101 from source TheAdminCafe 2FA cannot be found\" and our text only appears further down. I didn't want to build a message DLL just for this. Windows comes with ",[69,22996,22997],{},"EventCreate.exe",", and it has a message table that simply prints the text (",[69,23000,23001],{},"%1",") for the IDs 1 to 1000. So ",[69,23004,543],{}," registers our source with ",[69,23007,22997],{}," as the message file. That's why my IDs are between 100 and 106.",[15,23010,23011],{},"To see the events:",[148,23013,23017],{"className":23014,"code":23015,"language":23016,"meta":154,"style":154},"language-powershell shiki shiki-themes github-dark","Get-WinEvent -FilterHashtable @{ LogName = 'Application'; ProviderName = 'TheAdminCafe 2FA' } -MaxEvents 20 |\n    Format-Table TimeCreated, Id, LevelDisplayName, Message -Wrap\n","powershell",[69,23018,23019,23061],{"__ignoreMap":154},[599,23020,23021,23024,23026,23029,23032,23035,23037,23040,23043,23045,23048,23051,23053,23056,23058],{"class":601,"line":602},[599,23022,23023],{"class":949},"Get-WinEvent",[599,23025,1214],{"class":605},[599,23027,23028],{"class":666},"FilterHashtable ",[599,23030,23031],{"class":605},"@",[599,23033,23034],{"class":666},"{ LogName ",[599,23036,1060],{"class":605},[599,23038,23039],{"class":619}," 'Application'",[599,23041,23042],{"class":666},"; ProviderName ",[599,23044,1060],{"class":605},[599,23046,23047],{"class":619}," 'TheAdminCafe 2FA'",[599,23049,23050],{"class":666}," } ",[599,23052,1132],{"class":605},[599,23054,23055],{"class":666},"MaxEvents ",[599,23057,1940],{"class":949},[599,23059,23060],{"class":605}," |\n",[599,23062,23063,23066,23069,23071,23074,23076,23079,23081,23084,23086],{"class":601,"line":613},[599,23064,23065],{"class":949},"    Format-Table",[599,23067,23068],{"class":666}," TimeCreated",[599,23070,10558],{"class":605},[599,23072,23073],{"class":666}," Id",[599,23075,10558],{"class":605},[599,23077,23078],{"class":666}," LevelDisplayName",[599,23080,10558],{"class":605},[599,23082,23083],{"class":666}," Message ",[599,23085,1132],{"class":605},[599,23087,23088],{"class":666},"Wrap\n",[15,23090,23091],{},"If you forward your logs to a SIEM, alert on ID 104. A locked account is either a user who has a bad day, or somebody who knows the password.",[10,23093,23095],{"id":23094},"the-filter","The filter",[15,23097,23098],{},"This is the mistake that I see in most 2FA tutorials. If you register a Credential Provider, it only adds a tile. The password tile, the PIN tile and Windows Hello are still there. Anyone with the password just chooses the normal tile and never sees the code field.",[15,23100,23101],{},"So we have to hide all other providers on the logon and unlock screen. This is what the filter does.",[15,23103,23104,590],{},[69,23105,23106],{},"CTacFilter.h",[148,23108,23110],{"className":593,"code":23109,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccredentialprovider.h>\n#include \"dll.h\"\n\n\u002F\u002F Hides every credential provider except ours on the logon and unlock screens.\n\u002F\u002F A provider only adds a tile; the filter is what makes the second factor\n\u002F\u002F unavoidable, by removing the password, PIN and Windows Hello tiles.\nclass CTacFilter : public ICredentialProviderFilter\n{\npublic:\n    CTacFilter() : _cRef(1) { DllAddRef(); }\n\n    IFACEMETHODIMP_(ULONG) AddRef();\n    IFACEMETHODIMP_(ULONG) Release();\n    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv);\n\n    IFACEMETHODIMP Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD dwFlags,\n                          GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders);\n    IFACEMETHODIMP UpdateRemoteCredential(\n        const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsIn,\n        CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsOut);\n\n    friend HRESULT CTacFilter_CreateInstance(REFIID riid, void** ppv);\n\nprivate:\n    virtual ~CTacFilter() { DllRelease(); }\n    LONG _cRef;\n};\n",[69,23111,23112,23118,23124,23130,23136,23140,23145,23150,23155,23169,23173,23177,23199,23203,23217,23231,23251,23255,23276,23304,23313,23326,23338,23342,23365,23369,23373,23387,23394],{"__ignoreMap":154},[599,23113,23114,23116],{"class":601,"line":602},[599,23115,606],{"class":605},[599,23117,610],{"class":609},[599,23119,23120,23122],{"class":601,"line":613},[599,23121,616],{"class":605},[599,23123,620],{"class":619},[599,23125,23126,23128],{"class":601,"line":623},[599,23127,616],{"class":605},[599,23129,10483],{"class":619},[599,23131,23132,23134],{"class":601,"line":631},[599,23133,616],{"class":605},[599,23135,11523],{"class":619},[599,23137,23138],{"class":601,"line":639},[599,23139,651],{"emptyLinePlaceholder":650},[599,23141,23142],{"class":601,"line":647},[599,23143,23144],{"class":772},"\u002F\u002F Hides every credential provider except ours on the logon and unlock screens.\n",[599,23146,23147],{"class":601,"line":654},[599,23148,23149],{"class":772},"\u002F\u002F A provider only adds a tile; the filter is what makes the second factor\n",[599,23151,23152],{"class":601,"line":663},[599,23153,23154],{"class":772},"\u002F\u002F unavoidable, by removing the password, PIN and Windows Hello tiles.\n",[599,23156,23157,23159,23162,23164,23166],{"class":601,"line":670},[599,23158,10951],{"class":605},[599,23160,23161],{"class":609}," CTacFilter",[599,23163,10957],{"class":666},[599,23165,10960],{"class":605},[599,23167,23168],{"class":609}," ICredentialProviderFilter\n",[599,23170,23171],{"class":601,"line":728},[599,23172,667],{"class":666},[599,23174,23175],{"class":601,"line":764},[599,23176,10982],{"class":605},[599,23178,23179,23182,23185,23187,23189,23191,23193,23196],{"class":601,"line":769},[599,23180,23181],{"class":609},"    CTacFilter",[599,23183,23184],{"class":666},"() : ",[599,23186,11691],{"class":609},[599,23188,679],{"class":666},[599,23190,1217],{"class":949},[599,23192,13949],{"class":666},[599,23194,23195],{"class":609},"DllAddRef",[599,23197,23198],{"class":666},"(); }\n",[599,23200,23201],{"class":601,"line":776},[599,23202,651],{"emptyLinePlaceholder":650},[599,23204,23205,23207,23209,23211,23213,23215],{"class":601,"line":816},[599,23206,11003],{"class":609},[599,23208,679],{"class":666},[599,23210,1924],{"class":609},[599,23212,1124],{"class":666},[599,23214,11012],{"class":609},[599,23216,1313],{"class":666},[599,23218,23219,23221,23223,23225,23227,23229],{"class":601,"line":843},[599,23220,11003],{"class":609},[599,23222,679],{"class":666},[599,23224,1924],{"class":609},[599,23226,1124],{"class":666},[599,23228,11027],{"class":609},[599,23230,1313],{"class":666},[599,23232,23233,23235,23237,23239,23241,23243,23245,23247,23249],{"class":601,"line":848},[599,23234,11034],{"class":609},[599,23236,11037],{"class":609},[599,23238,679],{"class":666},[599,23240,11042],{"class":609},[599,23242,11045],{"class":697},[599,23244,212],{"class":666},[599,23246,11050],{"class":605},[599,23248,11053],{"class":697},[599,23250,725],{"class":666},[599,23252,23253],{"class":601,"line":854},[599,23254,651],{"emptyLinePlaceholder":650},[599,23256,23257,23259,23262,23264,23266,23268,23270,23272,23274],{"class":601,"line":860},[599,23258,11034],{"class":609},[599,23260,23261],{"class":609}," Filter",[599,23263,679],{"class":666},[599,23265,11076],{"class":609},[599,23267,11079],{"class":697},[599,23269,212],{"class":666},[599,23271,5878],{"class":609},[599,23273,11086],{"class":697},[599,23275,813],{"class":666},[599,23277,23278,23281,23283,23286,23288,23290,23292,23295,23297,23299,23302],{"class":601,"line":866},[599,23279,23280],{"class":609},"                          GUID",[599,23282,748],{"class":605},[599,23284,23285],{"class":697}," rgclsidProviders",[599,23287,212],{"class":666},[599,23289,11218],{"class":609},[599,23291,748],{"class":605},[599,23293,23294],{"class":697}," rgbAllow",[599,23296,212],{"class":666},[599,23298,5878],{"class":609},[599,23300,23301],{"class":697}," cProviders",[599,23303,725],{"class":666},[599,23305,23306,23308,23311],{"class":601,"line":912},[599,23307,11034],{"class":609},[599,23309,23310],{"class":609}," UpdateRemoteCredential",[599,23312,13310],{"class":666},[599,23314,23315,23317,23319,23321,23324],{"class":601,"line":938},[599,23316,2964],{"class":605},[599,23318,11102],{"class":609},[599,23320,748],{"class":605},[599,23322,23323],{"class":697}," pcpcsIn",[599,23325,813],{"class":666},[599,23327,23328,23331,23333,23336],{"class":601,"line":978},[599,23329,23330],{"class":609},"        CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION",[599,23332,748],{"class":605},[599,23334,23335],{"class":697}," pcpcsOut",[599,23337,725],{"class":666},[599,23339,23340],{"class":601,"line":1316},[599,23341,651],{"emptyLinePlaceholder":650},[599,23343,23344,23346,23348,23351,23353,23355,23357,23359,23361,23363],{"class":601,"line":1321},[599,23345,11286],{"class":605},[599,23347,11289],{"class":609},[599,23349,23350],{"class":609}," CTacFilter_CreateInstance",[599,23352,679],{"class":666},[599,23354,11042],{"class":609},[599,23356,11045],{"class":697},[599,23358,212],{"class":666},[599,23360,11050],{"class":605},[599,23362,11053],{"class":697},[599,23364,725],{"class":666},[599,23366,23367],{"class":601,"line":1335},[599,23368,651],{"emptyLinePlaceholder":650},[599,23370,23371],{"class":601,"line":1341},[599,23372,11315],{"class":605},[599,23374,23375,23377,23380,23382,23385],{"class":601,"line":1367},[599,23376,11320],{"class":605},[599,23378,23379],{"class":609}," ~CTacFilter",[599,23381,13968],{"class":666},[599,23383,23384],{"class":609},"DllRelease",[599,23386,23198],{"class":666},[599,23388,23389,23391],{"class":601,"line":1375},[599,23390,11389],{"class":609},[599,23392,23393],{"class":666}," _cRef;\n",[599,23395,23396],{"class":601,"line":1391},[599,23397,10612],{"class":666},[15,23399,23400,590],{},[69,23401,23402],{},"CTacFilter.cpp",[148,23404,23406],{"className":593,"code":23405,"language":595,"meta":154,"style":154},"#include \"CTacFilter.h\"\n#include \"guid.h\"\n#include \"dll.h\"\n#include \u003Cnew>\n\nIFACEMETHODIMP_(ULONG) CTacFilter::AddRef()\n{\n    return InterlockedIncrement(&_cRef);\n}\n\nIFACEMETHODIMP_(ULONG) CTacFilter::Release()\n{\n    LONG cRef = InterlockedDecrement(&_cRef);\n    if (cRef == 0)\n        delete this;\n    return cRef;\n}\n\nIFACEMETHODIMP CTacFilter::QueryInterface(REFIID riid, void** ppv)\n{\n    if (!ppv)\n        return E_POINTER;\n    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, __uuidof(ICredentialProviderFilter)))\n    {\n        *ppv = static_cast\u003CICredentialProviderFilter*>(this);\n        AddRef();\n        return S_OK;\n    }\n    *ppv = nullptr;\n    return E_NOINTERFACE;\n}\n\n\u002F\u002F Allow only our provider on the logon and unlock screens. Leave the other\n\u002F\u002F scenarios (CredUI, change password, PLAP) alone, or we break unrelated prompts.\nIFACEMETHODIMP CTacFilter::Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD,\n                                  GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders)\n{\n    if (cpus != CPUS_LOGON && cpus != CPUS_UNLOCK_WORKSTATION)\n        return S_OK;\n\n    for (DWORD i = 0; i \u003C cProviders; ++i)\n        rgbAllow[i] = IsEqualGUID(rgclsidProviders[i], CLSID_CTacProvider);\n    return S_OK;\n}\n\n\u002F\u002F RDP with NLA delivers the credential before a tile exists. We forward it and\n\u002F\u002F set the target provider to ourselves; copying the incoming CLSID would send\n\u002F\u002F it to a provider we just filtered out, and remote logon would break.\nIFACEMETHODIMP CTacFilter::UpdateRemoteCredential(\n    const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsIn,\n    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcsOut)\n{\n    if (!pcpcsIn || pcpcsIn->cbSerialization == 0 || !pcpcsIn->rgbSerialization)\n        return E_NOTIMPL;\n\n    pcpcsOut->rgbSerialization =\n        static_cast\u003CBYTE*>(CoTaskMemAlloc(pcpcsIn->cbSerialization));\n    if (!pcpcsOut->rgbSerialization)\n        return E_OUTOFMEMORY;\n\n    CopyMemory(pcpcsOut->rgbSerialization, pcpcsIn->rgbSerialization, pcpcsIn->cbSerialization);\n    pcpcsOut->cbSerialization         = pcpcsIn->cbSerialization;\n    pcpcsOut->ulAuthenticationPackage = pcpcsIn->ulAuthenticationPackage;\n    pcpcsOut->clsidCredentialProvider = CLSID_CTacProvider;\n    return S_OK;\n}\n\nHRESULT CTacFilter_CreateInstance(REFIID riid, void** ppv)\n{\n    CTacFilter* filter = new (std::nothrow) CTacFilter();\n    if (!filter)\n        return E_OUTOFMEMORY;\n    HRESULT hr = filter->QueryInterface(riid, ppv);\n    filter->Release();\n    return hr;\n}\n",[69,23407,23408,23415,23421,23427,23433,23437,23452,23456,23468,23472,23476,23490,23494,23510,23522,23530,23536,23540,23544,23568,23572,23582,23588,23609,23613,23633,23639,23645,23649,23661,23667,23671,23675,23680,23685,23708,23733,23737,23759,23765,23769,23790,23803,23809,23813,23817,23822,23827,23832,23845,23857,23867,23871,23898,23904,23908,23915,23930,23941,23947,23951,23958,23968,23978,23987,23993,23997,24001,24021,24025,24048,24059,24065,24080,24089,24095],{"__ignoreMap":154},[599,23409,23410,23412],{"class":601,"line":602},[599,23411,616],{"class":605},[599,23413,23414],{"class":619}," \"CTacFilter.h\"\n",[599,23416,23417,23419],{"class":601,"line":613},[599,23418,616],{"class":605},[599,23420,11530],{"class":619},[599,23422,23423,23425],{"class":601,"line":623},[599,23424,616],{"class":605},[599,23426,11523],{"class":619},[599,23428,23429,23431],{"class":601,"line":631},[599,23430,616],{"class":605},[599,23432,11548],{"class":619},[599,23434,23435],{"class":601,"line":639},[599,23436,651],{"emptyLinePlaceholder":650},[599,23438,23439,23441,23443,23446,23448,23450],{"class":601,"line":647},[599,23440,11947],{"class":609},[599,23442,11950],{"class":666},[599,23444,23445],{"class":609},"CTacFilter",[599,23447,688],{"class":666},[599,23449,11012],{"class":609},[599,23451,3717],{"class":666},[599,23453,23454],{"class":601,"line":654},[599,23455,667],{"class":666},[599,23457,23458,23460,23462,23464,23466],{"class":601,"line":663},[599,23459,3551],{"class":605},[599,23461,11969],{"class":609},[599,23463,679],{"class":666},[599,23465,694],{"class":605},[599,23467,11976],{"class":666},[599,23469,23470],{"class":601,"line":670},[599,23471,981],{"class":666},[599,23473,23474],{"class":601,"line":728},[599,23475,651],{"emptyLinePlaceholder":650},[599,23477,23478,23480,23482,23484,23486,23488],{"class":601,"line":764},[599,23479,11947],{"class":609},[599,23481,11950],{"class":666},[599,23483,23445],{"class":609},[599,23485,688],{"class":666},[599,23487,11027],{"class":609},[599,23489,3717],{"class":666},[599,23491,23492],{"class":601,"line":769},[599,23493,667],{"class":666},[599,23495,23496,23498,23500,23502,23504,23506,23508],{"class":601,"line":776},[599,23497,11389],{"class":609},[599,23499,12009],{"class":666},[599,23501,1060],{"class":605},[599,23503,12014],{"class":609},[599,23505,679],{"class":666},[599,23507,694],{"class":605},[599,23509,11976],{"class":666},[599,23511,23512,23514,23516,23518,23520],{"class":601,"line":816},[599,23513,3514],{"class":605},[599,23515,12027],{"class":666},[599,23517,1349],{"class":605},[599,23519,1286],{"class":949},[599,23521,1029],{"class":666},[599,23523,23524,23526,23528],{"class":601,"line":843},[599,23525,12038],{"class":605},[599,23527,12041],{"class":949},[599,23529,1066],{"class":666},[599,23531,23532,23534],{"class":601,"line":848},[599,23533,3551],{"class":605},[599,23535,12050],{"class":666},[599,23537,23538],{"class":601,"line":854},[599,23539,981],{"class":666},[599,23541,23542],{"class":601,"line":860},[599,23543,651],{"emptyLinePlaceholder":650},[599,23545,23546,23548,23550,23552,23554,23556,23558,23560,23562,23564,23566],{"class":601,"line":866},[599,23547,12063],{"class":609},[599,23549,23161],{"class":609},[599,23551,688],{"class":666},[599,23553,12070],{"class":609},[599,23555,679],{"class":666},[599,23557,11042],{"class":609},[599,23559,11045],{"class":697},[599,23561,212],{"class":666},[599,23563,11050],{"class":605},[599,23565,11053],{"class":697},[599,23567,1029],{"class":666},[599,23569,23570],{"class":601,"line":912},[599,23571,667],{"class":666},[599,23573,23574,23576,23578,23580],{"class":601,"line":938},[599,23575,3514],{"class":605},[599,23577,1327],{"class":666},[599,23579,2435],{"class":605},[599,23581,12099],{"class":666},[599,23583,23584,23586],{"class":601,"line":978},[599,23585,1211],{"class":605},[599,23587,12106],{"class":666},[599,23589,23590,23592,23594,23596,23598,23600,23602,23604,23606],{"class":601,"line":1316},[599,23591,3514],{"class":605},[599,23593,1327],{"class":666},[599,23595,12115],{"class":609},[599,23597,12118],{"class":666},[599,23599,6568],{"class":605},[599,23601,12123],{"class":609},[599,23603,12126],{"class":666},[599,23605,12129],{"class":609},[599,23607,23608],{"class":666},"(ICredentialProviderFilter)))\n",[599,23610,23611],{"class":601,"line":1321},[599,23612,1095],{"class":666},[599,23614,23615,23617,23619,23621,23623,23625,23627,23629,23631],{"class":601,"line":1335},[599,23616,12141],{"class":605},[599,23618,12144],{"class":666},[599,23620,1060],{"class":605},[599,23622,2374],{"class":605},[599,23624,267],{"class":666},[599,23626,5897],{"class":605},[599,23628,679],{"class":666},[599,23630,8593],{"class":949},[599,23632,725],{"class":666},[599,23634,23635,23637],{"class":601,"line":1341},[599,23636,12163],{"class":609},[599,23638,1313],{"class":666},[599,23640,23641,23643],{"class":601,"line":1367},[599,23642,1211],{"class":605},[599,23644,12172],{"class":666},[599,23646,23647],{"class":601,"line":1375},[599,23648,1224],{"class":666},[599,23650,23651,23653,23655,23657,23659],{"class":601,"line":1391},[599,23652,12236],{"class":605},[599,23654,12144],{"class":666},[599,23656,1060],{"class":605},[599,23658,1962],{"class":949},[599,23660,1066],{"class":666},[599,23662,23663,23665],{"class":601,"line":1405},[599,23664,3551],{"class":605},[599,23666,12251],{"class":666},[599,23668,23669],{"class":601,"line":1416},[599,23670,981],{"class":666},[599,23672,23673],{"class":601,"line":1421},[599,23674,651],{"emptyLinePlaceholder":650},[599,23676,23677],{"class":601,"line":1449},[599,23678,23679],{"class":772},"\u002F\u002F Allow only our provider on the logon and unlock screens. Leave the other\n",[599,23681,23682],{"class":601,"line":1462},[599,23683,23684],{"class":772},"\u002F\u002F scenarios (CredUI, change password, PLAP) alone, or we break unrelated prompts.\n",[599,23686,23687,23689,23691,23693,23696,23698,23700,23702,23704,23706],{"class":601,"line":1477},[599,23688,12063],{"class":609},[599,23690,23161],{"class":609},[599,23692,688],{"class":666},[599,23694,23695],{"class":609},"Filter",[599,23697,679],{"class":666},[599,23699,11076],{"class":609},[599,23701,11079],{"class":697},[599,23703,212],{"class":666},[599,23705,5878],{"class":609},[599,23707,813],{"class":666},[599,23709,23710,23713,23715,23717,23719,23721,23723,23725,23727,23729,23731],{"class":601,"line":1483},[599,23711,23712],{"class":609},"                                  GUID",[599,23714,748],{"class":605},[599,23716,23285],{"class":697},[599,23718,212],{"class":666},[599,23720,11218],{"class":609},[599,23722,748],{"class":605},[599,23724,23294],{"class":697},[599,23726,212],{"class":666},[599,23728,5878],{"class":609},[599,23730,23301],{"class":697},[599,23732,1029],{"class":666},[599,23734,23735],{"class":601,"line":1496},[599,23736,667],{"class":666},[599,23738,23739,23741,23744,23746,23749,23751,23754,23756],{"class":601,"line":1523},[599,23740,3514],{"class":605},[599,23742,23743],{"class":666}," (cpus ",[599,23745,2030],{"class":605},[599,23747,23748],{"class":666}," CPUS_LOGON ",[599,23750,3154],{"class":605},[599,23752,23753],{"class":666}," cpus ",[599,23755,2030],{"class":605},[599,23757,23758],{"class":666}," CPUS_UNLOCK_WORKSTATION)\n",[599,23760,23761,23763],{"class":601,"line":1555},[599,23762,1211],{"class":605},[599,23764,12172],{"class":666},[599,23766,23767],{"class":601,"line":1561},[599,23768,651],{"emptyLinePlaceholder":650},[599,23770,23771,23773,23775,23777,23779,23781,23783,23786,23788],{"class":601,"line":1567},[599,23772,3407],{"class":605},[599,23774,13013],{"class":666},[599,23776,1060],{"class":605},[599,23778,1286],{"class":949},[599,23780,1681],{"class":666},[599,23782,711],{"class":605},[599,23784,23785],{"class":666}," cProviders; ",[599,23787,1689],{"class":605},[599,23789,1692],{"class":666},[599,23791,23792,23795,23797,23800],{"class":601,"line":1577},[599,23793,23794],{"class":666},"        rgbAllow[i] ",[599,23796,1060],{"class":605},[599,23798,23799],{"class":609}," IsEqualGUID",[599,23801,23802],{"class":666},"(rgclsidProviders[i], CLSID_CTacProvider);\n",[599,23804,23805,23807],{"class":601,"line":1582},[599,23806,3551],{"class":605},[599,23808,12172],{"class":666},[599,23810,23811],{"class":601,"line":1587},[599,23812,981],{"class":666},[599,23814,23815],{"class":601,"line":1616},[599,23816,651],{"emptyLinePlaceholder":650},[599,23818,23819],{"class":601,"line":1621},[599,23820,23821],{"class":772},"\u002F\u002F RDP with NLA delivers the credential before a tile exists. We forward it and\n",[599,23823,23824],{"class":601,"line":1634},[599,23825,23826],{"class":772},"\u002F\u002F set the target provider to ourselves; copying the incoming CLSID would send\n",[599,23828,23829],{"class":601,"line":1647},[599,23830,23831],{"class":772},"\u002F\u002F it to a provider we just filtered out, and remote logon would break.\n",[599,23833,23834,23836,23838,23840,23843],{"class":601,"line":1660},[599,23835,12063],{"class":609},[599,23837,23161],{"class":609},[599,23839,688],{"class":666},[599,23841,23842],{"class":609},"UpdateRemoteCredential",[599,23844,13310],{"class":666},[599,23846,23847,23849,23851,23853,23855],{"class":601,"line":1665},[599,23848,12451],{"class":605},[599,23850,11102],{"class":609},[599,23852,748],{"class":605},[599,23854,23323],{"class":697},[599,23856,813],{"class":666},[599,23858,23859,23861,23863,23865],{"class":601,"line":1695},[599,23860,18471],{"class":609},[599,23862,748],{"class":605},[599,23864,23335],{"class":697},[599,23866,1029],{"class":666},[599,23868,23869],{"class":601,"line":1700},[599,23870,667],{"class":666},[599,23872,23873,23875,23877,23879,23882,23884,23887,23889,23891,23893,23895],{"class":601,"line":1720},[599,23874,3514],{"class":605},[599,23876,1327],{"class":666},[599,23878,2435],{"class":605},[599,23880,23881],{"class":666},"pcpcsIn ",[599,23883,6568],{"class":605},[599,23885,23886],{"class":666}," pcpcsIn->cbSerialization ",[599,23888,1349],{"class":605},[599,23890,1286],{"class":949},[599,23892,1355],{"class":605},[599,23894,9609],{"class":605},[599,23896,23897],{"class":666},"pcpcsIn->rgbSerialization)\n",[599,23899,23900,23902],{"class":601,"line":1731},[599,23901,1211],{"class":605},[599,23903,12379],{"class":666},[599,23905,23906],{"class":601,"line":1745},[599,23907,651],{"emptyLinePlaceholder":650},[599,23909,23910,23913],{"class":601,"line":1750},[599,23911,23912],{"class":666},"    pcpcsOut->rgbSerialization ",[599,23914,10667],{"class":605},[599,23916,23917,23919,23921,23923,23925,23927],{"class":601,"line":1761},[599,23918,13415],{"class":605},[599,23920,714],{"class":666},[599,23922,5897],{"class":605},[599,23924,679],{"class":666},[599,23926,13425],{"class":609},[599,23928,23929],{"class":666},"(pcpcsIn->cbSerialization));\n",[599,23931,23932,23934,23936,23938],{"class":601,"line":1787},[599,23933,3514],{"class":605},[599,23935,1327],{"class":666},[599,23937,2435],{"class":605},[599,23939,23940],{"class":666},"pcpcsOut->rgbSerialization)\n",[599,23942,23943,23945],{"class":601,"line":1792},[599,23944,1211],{"class":605},[599,23946,12692],{"class":666},[599,23948,23949],{"class":601,"line":1815},[599,23950,651],{"emptyLinePlaceholder":650},[599,23952,23953,23955],{"class":601,"line":1820},[599,23954,13450],{"class":609},[599,23956,23957],{"class":666},"(pcpcsOut->rgbSerialization, pcpcsIn->rgbSerialization, pcpcsIn->cbSerialization);\n",[599,23959,23960,23963,23965],{"class":601,"line":1833},[599,23961,23962],{"class":666},"    pcpcsOut->cbSerialization         ",[599,23964,1060],{"class":605},[599,23966,23967],{"class":666}," pcpcsIn->cbSerialization;\n",[599,23969,23970,23973,23975],{"class":601,"line":1863},[599,23971,23972],{"class":666},"    pcpcsOut->ulAuthenticationPackage ",[599,23974,1060],{"class":605},[599,23976,23977],{"class":666}," pcpcsIn->ulAuthenticationPackage;\n",[599,23979,23980,23983,23985],{"class":601,"line":1870},[599,23981,23982],{"class":666},"    pcpcsOut->clsidCredentialProvider ",[599,23984,1060],{"class":605},[599,23986,20145],{"class":666},[599,23988,23989,23991],{"class":601,"line":1875},[599,23990,3551],{"class":605},[599,23992,12172],{"class":666},[599,23994,23995],{"class":601,"line":1880},[599,23996,981],{"class":666},[599,23998,23999],{"class":601,"line":1946},[599,24000,651],{"emptyLinePlaceholder":650},[599,24002,24003,24005,24007,24009,24011,24013,24015,24017,24019],{"class":601,"line":1951},[599,24004,12617],{"class":609},[599,24006,23350],{"class":609},[599,24008,679],{"class":666},[599,24010,11042],{"class":609},[599,24012,11045],{"class":697},[599,24014,212],{"class":666},[599,24016,11050],{"class":605},[599,24018,11053],{"class":697},[599,24020,1029],{"class":666},[599,24022,24023],{"class":601,"line":1967},[599,24024,667],{"class":666},[599,24026,24027,24029,24031,24034,24036,24038,24040,24042,24044,24046],{"class":601,"line":1982},[599,24028,23181],{"class":609},[599,24030,748],{"class":605},[599,24032,24033],{"class":666}," filter ",[599,24035,1060],{"class":605},[599,24037,12663],{"class":605},[599,24039,1327],{"class":666},[599,24041,703],{"class":609},[599,24043,12670],{"class":666},[599,24045,23445],{"class":609},[599,24047,1313],{"class":666},[599,24049,24050,24052,24054,24056],{"class":601,"line":1997},[599,24051,3514],{"class":605},[599,24053,1327],{"class":666},[599,24055,2435],{"class":605},[599,24057,24058],{"class":666},"filter)\n",[599,24060,24061,24063],{"class":601,"line":2002},[599,24062,1211],{"class":605},[599,24064,12692],{"class":666},[599,24066,24067,24069,24071,24073,24076,24078],{"class":601,"line":2024},[599,24068,11344],{"class":609},[599,24070,12703],{"class":666},[599,24072,1060],{"class":605},[599,24074,24075],{"class":666}," filter->",[599,24077,12070],{"class":609},[599,24079,14537],{"class":666},[599,24081,24082,24085,24087],{"class":601,"line":2037},[599,24083,24084],{"class":666},"    filter->",[599,24086,11027],{"class":609},[599,24088,1313],{"class":666},[599,24090,24091,24093],{"class":601,"line":2047},[599,24092,3551],{"class":605},[599,24094,12751],{"class":666},[599,24096,24097],{"class":601,"line":2052},[599,24098,981],{"class":666},[15,24100,24101,24103,24104,24106],{},[69,24102,23695],{}," only hides providers during logon and unlock. If I also hid them for ",[69,24105,332],{},", UAC prompts would stop working because our provider does not support that scenario.",[15,24108,24109,24111],{},[69,24110,23842],{}," is for RDP. With Network Level Authentication (NLA) the RDP client sends the credentials via CredSSP before any tile is shown. The filter forwards them. The CLSID in the output decides which provider gets them, so I set it to our provider. If you just copy the CLSID from the input, the credentials go to a provider that is hidden by the filter and RDP no longer works.",[15,24113,24114],{},"Some things about RDP you should know:",[56,24116,24117,24120,24127],{},[59,24118,24119],{},"NLA checks the password before our tile. An attacker who knows the password can find out via RDP that it is correct. But without the code they don't get a session.",[59,24121,24122,24123,24126],{},"Depending on the RDP client the password can arrive encrypted (",[69,24124,24125],{},"CredProtect","). Then it has to be decrypted first. I have not tested this part as much as the rest, so please test it in your environment.",[59,24128,24129,24130,24132],{},"The filled in password is deleted when the tile loses focus (",[69,24131,17018],{},"), like every other password. If you click somewhere else and back, you have to type it again.",[10,24134,24136],{"id":24135},"helper-functions-and-com","Helper functions and COM",[15,24138,24139],{},"The rest is infrastructure.",[15,24141,24142,24145,24146,10240],{},[69,24143,24144],{},"helpers.cpp"," is a shortened version of the helper functions from the Microsoft Credential Provider sample (Windows-classic-samples, ",[69,24147,24148],{},"Security\u002FCredentialProvider",[15,24150,24151,24152,24155,24156,24158,24159,24162],{},"The most important function is ",[69,24153,24154],{},"KerbInteractiveUnlockLogonPack",". LSA runs in another process (",[69,24157,162],{},") and can't use pointers from LogonUI. So the blob has to contain everything itself. The function copies the three strings (domain, user, password) directly behind the structure and replaces every pointer with an offset from the start of the buffer. ",[69,24160,24161],{},"KerbInteractiveUnlockLogonUnpackInPlace"," does the opposite for RDP. It also checks the offsets, because this data comes from outside.",[15,24164,24165,590],{},[69,24166,24167],{},"helpers.h",[148,24169,24171],{"className":593,"code":24170,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n#include \u003Ccredentialprovider.h>\n#include \u003Cntsecapi.h>\n\n\u002F\u002F Trimmed versions of the helpers from Microsoft's credential provider sample\n\u002F\u002F (Windows-classic-samples, Security\u002FCredentialProvider).\n\nHRESULT SplitDomainAndUsername(PCWSTR pszQualifiedUserName,\n                               PWSTR pszDomain, int cchDomain,\n                               PWSTR pszUsername, int cchUsername);\n\nHRESULT ProtectIfNecessaryAndCopyPassword(PCWSTR pwzPassword,\n                                          CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,\n                                          PWSTR* ppwzProtectedPassword);\n\n\u002F\u002F Fills the structure with pointers to the caller's strings (no copies).\nHRESULT KerbInteractiveUnlockLogonInit(PWSTR pwzDomain, PWSTR pwzUsername, PWSTR pwzPassword,\n                                       CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,\n                                       KERB_INTERACTIVE_UNLOCK_LOGON* pkiul);\n\n\u002F\u002F One CoTaskMem buffer: the structure, followed by the string data. The string\n\u002F\u002F pointers are replaced by offsets from the start of the buffer.\nHRESULT KerbInteractiveUnlockLogonPack(const KERB_INTERACTIVE_UNLOCK_LOGON& rkiulIn,\n                                       BYTE** prgb, DWORD* pcb);\n\n\u002F\u002F Turns the offsets back into pointers, with bounds checks. Used for\n\u002F\u002F credentials forwarded by RDP.\nHRESULT KerbInteractiveUnlockLogonUnpackInPlace(KERB_INTERACTIVE_UNLOCK_LOGON* pkiul, DWORD cb);\n\nHRESULT RetrieveNegotiateAuthPackage(ULONG* pulAuthPackage);\n\nHRESULT FieldDescriptorCoAllocCopy(const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd,\n                                   CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd);\n",[69,24172,24173,24179,24185,24191,24197,24201,24206,24211,24215,24230,24247,24263,24267,24281,24290,24302,24306,24311,24339,24348,24360,24364,24369,24374,24394,24415,24419,24424,24429,24452,24456,24473,24477,24496],{"__ignoreMap":154},[599,24174,24175,24177],{"class":601,"line":602},[599,24176,606],{"class":605},[599,24178,610],{"class":609},[599,24180,24181,24183],{"class":601,"line":613},[599,24182,616],{"class":605},[599,24184,620],{"class":619},[599,24186,24187,24189],{"class":601,"line":623},[599,24188,616],{"class":605},[599,24190,10483],{"class":619},[599,24192,24193,24195],{"class":601,"line":631},[599,24194,616],{"class":605},[599,24196,11541],{"class":619},[599,24198,24199],{"class":601,"line":639},[599,24200,651],{"emptyLinePlaceholder":650},[599,24202,24203],{"class":601,"line":647},[599,24204,24205],{"class":772},"\u002F\u002F Trimmed versions of the helpers from Microsoft's credential provider sample\n",[599,24207,24208],{"class":601,"line":654},[599,24209,24210],{"class":772},"\u002F\u002F (Windows-classic-samples, Security\u002FCredentialProvider).\n",[599,24212,24213],{"class":601,"line":663},[599,24214,651],{"emptyLinePlaceholder":650},[599,24216,24217,24219,24221,24223,24225,24228],{"class":601,"line":670},[599,24218,12617],{"class":609},[599,24220,19958],{"class":609},[599,24222,679],{"class":666},[599,24224,11361],{"class":609},[599,24226,24227],{"class":697}," pszQualifiedUserName",[599,24229,813],{"class":666},[599,24231,24232,24235,24238,24240,24242,24245],{"class":601,"line":728},[599,24233,24234],{"class":609},"                               PWSTR",[599,24236,24237],{"class":697}," pszDomain",[599,24239,212],{"class":666},[599,24241,827],{"class":605},[599,24243,24244],{"class":697}," cchDomain",[599,24246,813],{"class":666},[599,24248,24249,24251,24254,24256,24258,24261],{"class":601,"line":764},[599,24250,24234],{"class":609},[599,24252,24253],{"class":697}," pszUsername",[599,24255,212],{"class":666},[599,24257,827],{"class":605},[599,24259,24260],{"class":697}," cchUsername",[599,24262,725],{"class":666},[599,24264,24265],{"class":601,"line":769},[599,24266,651],{"emptyLinePlaceholder":650},[599,24268,24269,24271,24273,24275,24277,24279],{"class":601,"line":776},[599,24270,12617],{"class":609},[599,24272,19770],{"class":609},[599,24274,679],{"class":666},[599,24276,11361],{"class":609},[599,24278,11371],{"class":697},[599,24280,813],{"class":666},[599,24282,24283,24286,24288],{"class":601,"line":816},[599,24284,24285],{"class":609},"                                          CREDENTIAL_PROVIDER_USAGE_SCENARIO",[599,24287,11079],{"class":697},[599,24289,813],{"class":666},[599,24291,24292,24295,24297,24300],{"class":601,"line":843},[599,24293,24294],{"class":609},"                                          PWSTR",[599,24296,748],{"class":605},[599,24298,24299],{"class":697}," ppwzProtectedPassword",[599,24301,725],{"class":666},[599,24303,24304],{"class":601,"line":848},[599,24305,651],{"emptyLinePlaceholder":650},[599,24307,24308],{"class":601,"line":854},[599,24309,24310],{"class":772},"\u002F\u002F Fills the structure with pointers to the caller's strings (no copies).\n",[599,24312,24313,24315,24317,24319,24321,24324,24326,24328,24331,24333,24335,24337],{"class":601,"line":860},[599,24314,12617],{"class":609},[599,24316,20017],{"class":609},[599,24318,679],{"class":666},[599,24320,10681],{"class":609},[599,24322,24323],{"class":697}," pwzDomain",[599,24325,212],{"class":666},[599,24327,10681],{"class":609},[599,24329,24330],{"class":697}," pwzUsername",[599,24332,212],{"class":666},[599,24334,10681],{"class":609},[599,24336,11371],{"class":697},[599,24338,813],{"class":666},[599,24340,24341,24344,24346],{"class":601,"line":866},[599,24342,24343],{"class":609},"                                       CREDENTIAL_PROVIDER_USAGE_SCENARIO",[599,24345,11079],{"class":697},[599,24347,813],{"class":666},[599,24349,24350,24353,24355,24358],{"class":601,"line":912},[599,24351,24352],{"class":609},"                                       KERB_INTERACTIVE_UNLOCK_LOGON",[599,24354,748],{"class":605},[599,24356,24357],{"class":697}," pkiul",[599,24359,725],{"class":666},[599,24361,24362],{"class":601,"line":938},[599,24363,651],{"emptyLinePlaceholder":650},[599,24365,24366],{"class":601,"line":978},[599,24367,24368],{"class":772},"\u002F\u002F One CoTaskMem buffer: the structure, followed by the string data. The string\n",[599,24370,24371],{"class":601,"line":1316},[599,24372,24373],{"class":772},"\u002F\u002F pointers are replaced by offsets from the start of the buffer.\n",[599,24375,24376,24378,24380,24382,24384,24387,24389,24392],{"class":601,"line":1321},[599,24377,12617],{"class":609},[599,24379,20046],{"class":609},[599,24381,679],{"class":666},[599,24383,682],{"class":605},[599,24385,24386],{"class":609}," KERB_INTERACTIVE_UNLOCK_LOGON",[599,24388,694],{"class":605},[599,24390,24391],{"class":697}," rkiulIn",[599,24393,813],{"class":666},[599,24395,24396,24399,24401,24404,24406,24408,24410,24413],{"class":601,"line":1335},[599,24397,24398],{"class":609},"                                       BYTE",[599,24400,4056],{"class":605},[599,24402,24403],{"class":697}," prgb",[599,24405,212],{"class":666},[599,24407,5878],{"class":609},[599,24409,748],{"class":605},[599,24411,24412],{"class":697}," pcb",[599,24414,725],{"class":666},[599,24416,24417],{"class":601,"line":1341},[599,24418,651],{"emptyLinePlaceholder":650},[599,24420,24421],{"class":601,"line":1367},[599,24422,24423],{"class":772},"\u002F\u002F Turns the offsets back into pointers, with bounds checks. Used for\n",[599,24425,24426],{"class":601,"line":1375},[599,24427,24428],{"class":772},"\u002F\u002F credentials forwarded by RDP.\n",[599,24430,24431,24433,24435,24437,24439,24441,24443,24445,24447,24450],{"class":601,"line":1391},[599,24432,12617],{"class":609},[599,24434,13534],{"class":609},[599,24436,679],{"class":666},[599,24438,13418],{"class":609},[599,24440,748],{"class":605},[599,24442,24357],{"class":697},[599,24444,212],{"class":666},[599,24446,5878],{"class":609},[599,24448,24449],{"class":697}," cb",[599,24451,725],{"class":666},[599,24453,24454],{"class":601,"line":1405},[599,24455,651],{"emptyLinePlaceholder":650},[599,24457,24458,24460,24462,24464,24466,24468,24471],{"class":601,"line":1416},[599,24459,12617],{"class":609},[599,24461,20100],{"class":609},[599,24463,679],{"class":666},[599,24465,1924],{"class":609},[599,24467,748],{"class":605},[599,24469,24470],{"class":697}," pulAuthPackage",[599,24472,725],{"class":666},[599,24474,24475],{"class":601,"line":1421},[599,24476,651],{"emptyLinePlaceholder":650},[599,24478,24479,24481,24483,24485,24487,24489,24491,24494],{"class":601,"line":1449},[599,24480,12617],{"class":609},[599,24482,14098],{"class":609},[599,24484,679],{"class":666},[599,24486,682],{"class":605},[599,24488,10661],{"class":609},[599,24490,694],{"class":605},[599,24492,24493],{"class":697}," rcpfd",[599,24495,813],{"class":666},[599,24497,24498,24501,24503,24505],{"class":601,"line":1462},[599,24499,24500],{"class":609},"                                   CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR",[599,24502,4056],{"class":605},[599,24504,11187],{"class":697},[599,24506,725],{"class":666},[15,24508,24509,590],{},[69,24510,24144],{},[148,24512,24514],{"className":593,"code":24513,"language":595,"meta":154,"style":154},"#include \"helpers.h\"\n#include \u003Cshlwapi.h>\n#include \u003Cstrsafe.h>\n\n#define SECURITY_WIN32\n#include \u003Csecurity.h>\n\n#pragma comment(lib, \"secur32.lib\")\n#pragma comment(lib, \"shlwapi.lib\")\n\nstatic void InitUnicodeString(UNICODE_STRING* pus, PWSTR pwz)\n{\n    \u002F\u002F A UNICODE_STRING length is a USHORT (bytes). Cap the character count so\n    \u002F\u002F len * sizeof(WCHAR) can never wrap to a small value while Buffer still\n    \u002F\u002F points at the full string. No real password comes close to this.\n    size_t len = pwz ? wcslen(pwz) : 0;\n    const size_t maxChars = (0xFFFF \u002F sizeof(WCHAR)) - 1;   \u002F\u002F 32766\n    if (len > maxChars)\n        len = maxChars;\n\n    pus->Length        = static_cast\u003CUSHORT>(len * sizeof(WCHAR));\n    pus->MaximumLength = static_cast\u003CUSHORT>((len + 1) * sizeof(WCHAR));\n    pus->Buffer        = pwz;\n}\n\n\u002F\u002F Copies the string to pbDest and stores its offset from pvBase in Buffer.\nstatic void PackUnicodeString(const UNICODE_STRING& src, UNICODE_STRING* pusDst,\n                              BYTE* pbDest, const void* pvBase)\n{\n    pusDst->Length        = src.Length;\n    pusDst->MaximumLength = src.Length;\n    if (src.Length)\n    {\n        CopyMemory(pbDest, src.Buffer, src.Length);\n        pusDst->Buffer = reinterpret_cast\u003CPWSTR>(\n            static_cast\u003CULONG_PTR>(pbDest - static_cast\u003Cconst BYTE*>(pvBase)));\n    }\n    else\n    {\n        pusDst->Buffer = nullptr;\n    }\n}\n\nstatic bool UnpackUnicodeString(void* pvBase, DWORD cb, UNICODE_STRING* pus)\n{\n    if (pus->Length == 0)\n    {\n        pus->Buffer = nullptr;\n        return true;\n    }\n\n    ULONG_PTR offset = reinterpret_cast\u003CULONG_PTR>(pus->Buffer);\n    if (offset % sizeof(WCHAR) != 0 || offset > cb || pus->Length > cb - offset)\n        return false;\n\n    pus->Buffer = reinterpret_cast\u003CPWSTR>(static_cast\u003CBYTE*>(pvBase) + offset);\n    return true;\n}\n\nHRESULT SplitDomainAndUsername(PCWSTR pszQualifiedUserName,\n                               PWSTR pszDomain, int cchDomain,\n                               PWSTR pszUsername, int cchUsername)\n{\n    const wchar_t* pchSlash = wcschr(pszQualifiedUserName, L'\\\\');\n    if (!pchSlash)\n        return E_INVALIDARG;\n\n    HRESULT hr = StringCchCopyNW(pszDomain, cchDomain, pszQualifiedUserName,\n                                 static_cast\u003Csize_t>(pchSlash - pszQualifiedUserName));\n    if (SUCCEEDED(hr))\n        hr = StringCchCopyW(pszUsername, cchUsername, pchSlash + 1);\n    return hr;\n}\n\nHRESULT ProtectIfNecessaryAndCopyPassword(PCWSTR pwzPassword,\n                                          CREDENTIAL_PROVIDER_USAGE_SCENARIO,\n                                          PWSTR* ppwzProtectedPassword)\n{\n    \u002F\u002F The Microsoft sample runs the password through CredProtect first. A plain\n    \u002F\u002F copy works for a local logon and keeps this demo small.\n    *ppwzProtectedPassword = nullptr;\n    return SHStrDupW(pwzPassword ? pwzPassword : L\"\", ppwzProtectedPassword);\n}\n\nHRESULT KerbInteractiveUnlockLogonInit(PWSTR pwzDomain, PWSTR pwzUsername, PWSTR pwzPassword,\n                                       CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,\n                                       KERB_INTERACTIVE_UNLOCK_LOGON* pkiul)\n{\n    ZeroMemory(pkiul, sizeof(*pkiul));\n    KERB_INTERACTIVE_LOGON* pkil = &pkiul->Logon;\n\n    switch (cpus)\n    {\n    case CPUS_LOGON:              pkil->MessageType = KerbInteractiveLogon;       break;\n    case CPUS_UNLOCK_WORKSTATION: pkil->MessageType = KerbWorkstationUnlockLogon; break;\n    default:                      return E_INVALIDARG;\n    }\n\n    InitUnicodeString(&pkil->LogonDomainName, pwzDomain);\n    InitUnicodeString(&pkil->UserName, pwzUsername);\n    InitUnicodeString(&pkil->Password, pwzPassword);\n    return S_OK;\n}\n\nHRESULT KerbInteractiveUnlockLogonPack(const KERB_INTERACTIVE_UNLOCK_LOGON& rkiulIn,\n                                       BYTE** prgb, DWORD* pcb)\n{\n    const KERB_INTERACTIVE_LOGON& in = rkiulIn.Logon;\n    DWORD cb = sizeof(rkiulIn) + in.LogonDomainName.Length + in.UserName.Length + in.Password.Length;\n\n    KERB_INTERACTIVE_UNLOCK_LOGON* pkiulOut =\n        static_cast\u003CKERB_INTERACTIVE_UNLOCK_LOGON*>(CoTaskMemAlloc(cb));\n    if (!pkiulOut)\n        return E_OUTOFMEMORY;\n\n    ZeroMemory(pkiulOut, sizeof(*pkiulOut));\n    pkiulOut->Logon.MessageType = in.MessageType;\n\n    BYTE* pbData = reinterpret_cast\u003CBYTE*>(pkiulOut) + sizeof(*pkiulOut);\n    PackUnicodeString(in.LogonDomainName, &pkiulOut->Logon.LogonDomainName, pbData, pkiulOut);\n    pbData += in.LogonDomainName.Length;\n    PackUnicodeString(in.UserName, &pkiulOut->Logon.UserName, pbData, pkiulOut);\n    pbData += in.UserName.Length;\n    PackUnicodeString(in.Password, &pkiulOut->Logon.Password, pbData, pkiulOut);\n\n    *prgb = reinterpret_cast\u003CBYTE*>(pkiulOut);\n    *pcb  = cb;\n    return S_OK;\n}\n\nHRESULT KerbInteractiveUnlockLogonUnpackInPlace(KERB_INTERACTIVE_UNLOCK_LOGON* pkiul, DWORD cb)\n{\n    if (cb \u003C sizeof(*pkiul))\n        return E_INVALIDARG;\n\n    KERB_INTERACTIVE_LOGON* pkil = &pkiul->Logon;\n    if (UnpackUnicodeString(pkiul, cb, &pkil->LogonDomainName) &&\n        UnpackUnicodeString(pkiul, cb, &pkil->UserName) &&\n        UnpackUnicodeString(pkiul, cb, &pkil->Password))\n        return S_OK;\n    return E_INVALIDARG;\n}\n\nHRESULT RetrieveNegotiateAuthPackage(ULONG* pulAuthPackage)\n{\n    HANDLE hLsa = nullptr;\n    NTSTATUS status = LsaConnectUntrusted(&hLsa);\n    if (status != 0)\n        return HRESULT_FROM_NT(status);\n\n    LSA_STRING name;\n    name.Buffer        = const_cast\u003CPCHAR>(NEGOSSP_NAME_A);\n    name.Length        = static_cast\u003CUSHORT>(strlen(name.Buffer));\n    name.MaximumLength = static_cast\u003CUSHORT>(name.Length + 1);\n\n    ULONG ulPackage = 0;\n    status = LsaLookupAuthenticationPackage(hLsa, &name, &ulPackage);\n    LsaDeregisterLogonProcess(hLsa);\n    if (status != 0)\n        return HRESULT_FROM_NT(status);\n\n    *pulAuthPackage = ulPackage;\n    return S_OK;\n}\n\nHRESULT FieldDescriptorCoAllocCopy(const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd,\n                                   CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd)\n{\n    *ppcpfd = nullptr;\n\n    CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd =\n        static_cast\u003CCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR*>(\n            CoTaskMemAlloc(sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)));\n    if (!pcpfd)\n        return E_OUTOFMEMORY;\n\n    pcpfd->dwFieldID     = rcpfd.dwFieldID;\n    pcpfd->cpft          = rcpfd.cpft;\n    pcpfd->guidFieldType = rcpfd.guidFieldType;\n    pcpfd->pszLabel      = nullptr;\n\n    HRESULT hr = S_OK;\n    if (rcpfd.pszLabel)\n        hr = SHStrDupW(rcpfd.pszLabel, &pcpfd->pszLabel);\n\n    if (SUCCEEDED(hr))\n        *ppcpfd = pcpfd;\n    else\n        CoTaskMemFree(pcpfd);\n    return hr;\n}\n",[69,24515,24516,24522,24528,24534,24538,24545,24552,24556,24573,24589,24593,24620,24624,24629,24634,24639,24663,24699,24711,24721,24725,24748,24776,24786,24790,24794,24799,24830,24852,24856,24866,24875,24882,24886,24894,24910,24935,24939,24944,24948,24958,24962,24966,24970,25002,25006,25019,25023,25034,25042,25046,25050,25068,25108,25116,25120,25149,25157,25161,25165,25179,25193,25207,25211,25235,25246,25252,25256,25270,25283,25293,25311,25317,25321,25325,25339,25345,25355,25359,25364,25369,25382,25402,25406,25410,25436,25444,25454,25458,25474,25492,25496,25502,25506,25523,25539,25550,25554,25558,25570,25581,25592,25598,25602,25606,25624,25642,25646,25662,25690,25694,25705,25720,25731,25737,25741,25757,25767,25771,25802,25815,25825,25837,25846,25858,25862,25880,25892,25898,25902,25906,25928,25932,25949,25955,25959,25973,25992,26006,26017,26023,26029,26033,26037,26053,26057,26071,26090,26102,26112,26116,26123,26141,26162,26184,26188,26202,26225,26233,26245,26253,26257,26269,26275,26279,26283,26301,26311,26315,26328,26332,26343,26353,26365,26376,26382,26386,26396,26406,26416,26427,26431,26441,26448,26464,26468,26478,26489,26493,26500,26506],{"__ignoreMap":154},[599,24517,24518,24520],{"class":601,"line":602},[599,24519,616],{"class":605},[599,24521,11509],{"class":619},[599,24523,24524,24526],{"class":601,"line":613},[599,24525,616],{"class":605},[599,24527,15547],{"class":619},[599,24529,24530,24532],{"class":601,"line":623},[599,24531,616],{"class":605},[599,24533,15554],{"class":619},[599,24535,24536],{"class":601,"line":631},[599,24537,651],{"emptyLinePlaceholder":650},[599,24539,24540,24542],{"class":601,"line":639},[599,24541,15660],{"class":605},[599,24543,24544],{"class":609}," SECURITY_WIN32\n",[599,24546,24547,24549],{"class":601,"line":647},[599,24548,616],{"class":605},[599,24550,24551],{"class":619}," \u003Csecurity.h>\n",[599,24553,24554],{"class":601,"line":654},[599,24555,651],{"emptyLinePlaceholder":650},[599,24557,24558,24560,24562,24564,24566,24568,24571],{"class":601,"line":663},[599,24559,606],{"class":605},[599,24561,1016],{"class":609},[599,24563,679],{"class":666},[599,24565,1021],{"class":609},[599,24567,212],{"class":666},[599,24569,24570],{"class":619},"\"secur32.lib\"",[599,24572,1029],{"class":666},[599,24574,24575,24577,24579,24581,24583,24585,24587],{"class":601,"line":670},[599,24576,606],{"class":605},[599,24578,1016],{"class":609},[599,24580,679],{"class":666},[599,24582,1021],{"class":609},[599,24584,212],{"class":666},[599,24586,15597],{"class":619},[599,24588,1029],{"class":666},[599,24590,24591],{"class":601,"line":728},[599,24592,651],{"emptyLinePlaceholder":650},[599,24594,24595,24597,24600,24603,24605,24607,24609,24612,24614,24616,24618],{"class":601,"line":764},[599,24596,8856],{"class":605},[599,24598,24599],{"class":605}," void",[599,24601,24602],{"class":609}," InitUnicodeString",[599,24604,679],{"class":666},[599,24606,14663],{"class":609},[599,24608,748],{"class":605},[599,24610,24611],{"class":697}," pus",[599,24613,212],{"class":666},[599,24615,10681],{"class":609},[599,24617,15171],{"class":697},[599,24619,1029],{"class":666},[599,24621,24622],{"class":601,"line":769},[599,24623,667],{"class":666},[599,24625,24626],{"class":601,"line":776},[599,24627,24628],{"class":772},"    \u002F\u002F A UNICODE_STRING length is a USHORT (bytes). Cap the character count so\n",[599,24630,24631],{"class":601,"line":816},[599,24632,24633],{"class":772},"    \u002F\u002F len * sizeof(WCHAR) can never wrap to a small value while Buffer still\n",[599,24635,24636],{"class":601,"line":843},[599,24637,24638],{"class":772},"    \u002F\u002F points at the full string. No real password comes close to this.\n",[599,24640,24641,24643,24645,24647,24649,24651,24654,24657,24659,24661],{"class":601,"line":848},[599,24642,12565],{"class":605},[599,24644,15926],{"class":666},[599,24646,1060],{"class":605},[599,24648,18121],{"class":666},[599,24650,9412],{"class":605},[599,24652,24653],{"class":609}," wcslen",[599,24655,24656],{"class":666},"(pwz) ",[599,24658,590],{"class":605},[599,24660,1286],{"class":949},[599,24662,1066],{"class":666},[599,24664,24665,24667,24670,24673,24675,24677,24679,24682,24685,24687,24690,24692,24694,24696],{"class":601,"line":854},[599,24666,12451],{"class":605},[599,24668,24669],{"class":605}," size_t",[599,24671,24672],{"class":666}," maxChars ",[599,24674,1060],{"class":605},[599,24676,1327],{"class":666},[599,24678,11586],{"class":605},[599,24680,24681],{"class":949},"FFFF",[599,24683,24684],{"class":605}," \u002F",[599,24686,6453],{"class":605},[599,24688,24689],{"class":666},"(WCHAR)) ",[599,24691,1132],{"class":605},[599,24693,973],{"class":949},[599,24695,1549],{"class":666},[599,24697,24698],{"class":772},"   \u002F\u002F 32766\n",[599,24700,24701,24703,24706,24708],{"class":601,"line":860},[599,24702,3514],{"class":605},[599,24704,24705],{"class":666}," (len ",[599,24707,717],{"class":605},[599,24709,24710],{"class":666}," maxChars)\n",[599,24712,24713,24716,24718],{"class":601,"line":866},[599,24714,24715],{"class":666},"        len ",[599,24717,1060],{"class":605},[599,24719,24720],{"class":666}," maxChars;\n",[599,24722,24723],{"class":601,"line":912},[599,24724,651],{"emptyLinePlaceholder":650},[599,24726,24727,24730,24732,24734,24737,24739,24742,24744,24746],{"class":601,"line":938},[599,24728,24729],{"class":666},"    pus->Length        ",[599,24731,1060],{"class":605},[599,24733,2374],{"class":605},[599,24735,24736],{"class":666},"USHORT",[599,24738,717],{"class":605},[599,24740,24741],{"class":666},"(len ",[599,24743,748],{"class":605},[599,24745,6453],{"class":605},[599,24747,11824],{"class":666},[599,24749,24750,24753,24755,24757,24759,24761,24764,24766,24768,24770,24772,24774],{"class":601,"line":978},[599,24751,24752],{"class":666},"    pus->MaximumLength ",[599,24754,1060],{"class":605},[599,24756,2374],{"class":605},[599,24758,24736],{"class":666},[599,24760,717],{"class":605},[599,24762,24763],{"class":666},"((len ",[599,24765,2543],{"class":605},[599,24767,973],{"class":949},[599,24769,1124],{"class":666},[599,24771,748],{"class":605},[599,24773,6453],{"class":605},[599,24775,11824],{"class":666},[599,24777,24778,24781,24783],{"class":601,"line":1316},[599,24779,24780],{"class":666},"    pus->Buffer        ",[599,24782,1060],{"class":605},[599,24784,24785],{"class":666}," pwz;\n",[599,24787,24788],{"class":601,"line":1321},[599,24789,981],{"class":666},[599,24791,24792],{"class":601,"line":1335},[599,24793,651],{"emptyLinePlaceholder":650},[599,24795,24796],{"class":601,"line":1341},[599,24797,24798],{"class":772},"\u002F\u002F Copies the string to pbDest and stores its offset from pvBase in Buffer.\n",[599,24800,24801,24803,24805,24808,24810,24812,24814,24816,24819,24821,24823,24825,24828],{"class":601,"line":1367},[599,24802,8856],{"class":605},[599,24804,24599],{"class":605},[599,24806,24807],{"class":609}," PackUnicodeString",[599,24809,679],{"class":666},[599,24811,682],{"class":605},[599,24813,13600],{"class":609},[599,24815,694],{"class":605},[599,24817,24818],{"class":697}," src",[599,24820,212],{"class":666},[599,24822,14663],{"class":609},[599,24824,748],{"class":605},[599,24826,24827],{"class":697}," pusDst",[599,24829,813],{"class":666},[599,24831,24832,24835,24837,24840,24842,24844,24847,24850],{"class":601,"line":1375},[599,24833,24834],{"class":609},"                              BYTE",[599,24836,748],{"class":605},[599,24838,24839],{"class":697}," pbDest",[599,24841,212],{"class":666},[599,24843,682],{"class":605},[599,24845,24846],{"class":605}," void*",[599,24848,24849],{"class":697}," pvBase",[599,24851,1029],{"class":666},[599,24853,24854],{"class":601,"line":1391},[599,24855,667],{"class":666},[599,24857,24858,24861,24863],{"class":601,"line":1405},[599,24859,24860],{"class":666},"    pusDst->Length        ",[599,24862,1060],{"class":605},[599,24864,24865],{"class":666}," src.Length;\n",[599,24867,24868,24871,24873],{"class":601,"line":1416},[599,24869,24870],{"class":666},"    pusDst->MaximumLength ",[599,24872,1060],{"class":605},[599,24874,24865],{"class":666},[599,24876,24877,24879],{"class":601,"line":1421},[599,24878,3514],{"class":605},[599,24880,24881],{"class":666}," (src.Length)\n",[599,24883,24884],{"class":601,"line":1449},[599,24885,1095],{"class":666},[599,24887,24888,24891],{"class":601,"line":1462},[599,24889,24890],{"class":609},"        CopyMemory",[599,24892,24893],{"class":666},"(pbDest, src.Buffer, src.Length);\n",[599,24895,24896,24899,24901,24904,24906,24908],{"class":601,"line":1477},[599,24897,24898],{"class":666},"        pusDst->Buffer ",[599,24900,1060],{"class":605},[599,24902,24903],{"class":605}," reinterpret_cast\u003C",[599,24905,10681],{"class":666},[599,24907,717],{"class":605},[599,24909,13310],{"class":666},[599,24911,24912,24915,24918,24920,24923,24925,24928,24930,24932],{"class":601,"line":1483},[599,24913,24914],{"class":605},"            static_cast\u003C",[599,24916,24917],{"class":666},"ULONG_PTR",[599,24919,717],{"class":605},[599,24921,24922],{"class":666},"(pbDest ",[599,24924,1132],{"class":605},[599,24926,24927],{"class":605}," static_cast\u003Cconst",[599,24929,745],{"class":666},[599,24931,5897],{"class":605},[599,24933,24934],{"class":666},"(pvBase)));\n",[599,24936,24937],{"class":601,"line":1496},[599,24938,1224],{"class":666},[599,24940,24941],{"class":601,"line":1523},[599,24942,24943],{"class":605},"    else\n",[599,24945,24946],{"class":601,"line":1555},[599,24947,1095],{"class":666},[599,24949,24950,24952,24954,24956],{"class":601,"line":1561},[599,24951,24898],{"class":666},[599,24953,1060],{"class":605},[599,24955,1962],{"class":949},[599,24957,1066],{"class":666},[599,24959,24960],{"class":601,"line":1567},[599,24961,1224],{"class":666},[599,24963,24964],{"class":601,"line":1577},[599,24965,981],{"class":666},[599,24967,24968],{"class":601,"line":1582},[599,24969,651],{"emptyLinePlaceholder":650},[599,24971,24972,24974,24976,24979,24981,24984,24986,24988,24990,24992,24994,24996,24998,25000],{"class":601,"line":1587},[599,24973,8856],{"class":605},[599,24975,1885],{"class":605},[599,24977,24978],{"class":609}," UnpackUnicodeString",[599,24980,679],{"class":666},[599,24982,24983],{"class":605},"void*",[599,24985,24849],{"class":697},[599,24987,212],{"class":666},[599,24989,5878],{"class":609},[599,24991,24449],{"class":697},[599,24993,212],{"class":666},[599,24995,14663],{"class":609},[599,24997,748],{"class":605},[599,24999,24611],{"class":697},[599,25001,1029],{"class":666},[599,25003,25004],{"class":601,"line":1616},[599,25005,667],{"class":666},[599,25007,25008,25010,25013,25015,25017],{"class":601,"line":1621},[599,25009,3514],{"class":605},[599,25011,25012],{"class":666}," (pus->Length ",[599,25014,1349],{"class":605},[599,25016,1286],{"class":949},[599,25018,1029],{"class":666},[599,25020,25021],{"class":601,"line":1634},[599,25022,1095],{"class":666},[599,25024,25025,25028,25030,25032],{"class":601,"line":1647},[599,25026,25027],{"class":666},"        pus->Buffer ",[599,25029,1060],{"class":605},[599,25031,1962],{"class":949},[599,25033,1066],{"class":666},[599,25035,25036,25038,25040],{"class":601,"line":1660},[599,25037,1211],{"class":605},[599,25039,1572],{"class":949},[599,25041,1066],{"class":666},[599,25043,25044],{"class":601,"line":1665},[599,25045,1224],{"class":666},[599,25047,25048],{"class":601,"line":1695},[599,25049,651],{"emptyLinePlaceholder":650},[599,25051,25052,25055,25057,25059,25061,25063,25065],{"class":601,"line":1700},[599,25053,25054],{"class":609},"    ULONG_PTR",[599,25056,2481],{"class":666},[599,25058,1060],{"class":605},[599,25060,24903],{"class":605},[599,25062,24917],{"class":666},[599,25064,717],{"class":605},[599,25066,25067],{"class":666},"(pus->Buffer);\n",[599,25069,25070,25072,25075,25077,25079,25082,25084,25086,25088,25090,25092,25094,25096,25099,25101,25103,25105],{"class":601,"line":1720},[599,25071,3514],{"class":605},[599,25073,25074],{"class":666}," (offset ",[599,25076,2692],{"class":605},[599,25078,6453],{"class":605},[599,25080,25081],{"class":666},"(WCHAR) ",[599,25083,2030],{"class":605},[599,25085,1286],{"class":949},[599,25087,1355],{"class":605},[599,25089,2481],{"class":666},[599,25091,717],{"class":605},[599,25093,7454],{"class":666},[599,25095,6568],{"class":605},[599,25097,25098],{"class":666}," pus->Length ",[599,25100,717],{"class":605},[599,25102,7454],{"class":666},[599,25104,1132],{"class":605},[599,25106,25107],{"class":666}," offset)\n",[599,25109,25110,25112,25114],{"class":601,"line":1731},[599,25111,1211],{"class":605},[599,25113,1411],{"class":949},[599,25115,1066],{"class":666},[599,25117,25118],{"class":601,"line":1745},[599,25119,651],{"emptyLinePlaceholder":650},[599,25121,25122,25125,25127,25129,25131,25133,25135,25137,25139,25141,25144,25146],{"class":601,"line":1750},[599,25123,25124],{"class":666},"    pus->Buffer ",[599,25126,1060],{"class":605},[599,25128,24903],{"class":605},[599,25130,10681],{"class":666},[599,25132,717],{"class":605},[599,25134,679],{"class":666},[599,25136,1507],{"class":605},[599,25138,714],{"class":666},[599,25140,5897],{"class":605},[599,25142,25143],{"class":666},"(pvBase) ",[599,25145,2543],{"class":605},[599,25147,25148],{"class":666}," offset);\n",[599,25150,25151,25153,25155],{"class":601,"line":1761},[599,25152,3551],{"class":605},[599,25154,1572],{"class":949},[599,25156,1066],{"class":666},[599,25158,25159],{"class":601,"line":1787},[599,25160,981],{"class":666},[599,25162,25163],{"class":601,"line":1792},[599,25164,651],{"emptyLinePlaceholder":650},[599,25166,25167,25169,25171,25173,25175,25177],{"class":601,"line":1815},[599,25168,12617],{"class":609},[599,25170,19958],{"class":609},[599,25172,679],{"class":666},[599,25174,11361],{"class":609},[599,25176,24227],{"class":697},[599,25178,813],{"class":666},[599,25180,25181,25183,25185,25187,25189,25191],{"class":601,"line":1820},[599,25182,24234],{"class":609},[599,25184,24237],{"class":697},[599,25186,212],{"class":666},[599,25188,827],{"class":605},[599,25190,24244],{"class":697},[599,25192,813],{"class":666},[599,25194,25195,25197,25199,25201,25203,25205],{"class":601,"line":1833},[599,25196,24234],{"class":609},[599,25198,24253],{"class":697},[599,25200,212],{"class":666},[599,25202,827],{"class":605},[599,25204,24260],{"class":697},[599,25206,1029],{"class":666},[599,25208,25209],{"class":601,"line":1863},[599,25210,667],{"class":666},[599,25212,25213,25215,25217,25220,25222,25224,25227,25229,25231,25233],{"class":601,"line":1870},[599,25214,12451],{"class":605},[599,25216,6785],{"class":605},[599,25218,25219],{"class":666}," pchSlash ",[599,25221,1060],{"class":605},[599,25223,12465],{"class":609},[599,25225,25226],{"class":666},"(pszQualifiedUserName, ",[599,25228,5720],{"class":619},[599,25230,5576],{"class":949},[599,25232,5725],{"class":619},[599,25234,725],{"class":666},[599,25236,25237,25239,25241,25243],{"class":601,"line":1875},[599,25238,3514],{"class":605},[599,25240,1327],{"class":666},[599,25242,2435],{"class":605},[599,25244,25245],{"class":666},"pchSlash)\n",[599,25247,25248,25250],{"class":601,"line":1880},[599,25249,1211],{"class":605},[599,25251,12397],{"class":666},[599,25253,25254],{"class":601,"line":1946},[599,25255,651],{"emptyLinePlaceholder":650},[599,25257,25258,25260,25262,25264,25267],{"class":601,"line":1951},[599,25259,11344],{"class":609},[599,25261,12703],{"class":666},[599,25263,1060],{"class":605},[599,25265,25266],{"class":609}," StringCchCopyNW",[599,25268,25269],{"class":666},"(pszDomain, cchDomain, pszQualifiedUserName,\n",[599,25271,25272,25275,25278,25280],{"class":601,"line":1967},[599,25273,25274],{"class":605},"                                 static_cast\u003Csize_t>",[599,25276,25277],{"class":666},"(pchSlash ",[599,25279,1132],{"class":605},[599,25281,25282],{"class":666}," pszQualifiedUserName));\n",[599,25284,25285,25287,25289,25291],{"class":601,"line":1982},[599,25286,3514],{"class":605},[599,25288,1327],{"class":666},[599,25290,12847],{"class":609},[599,25292,12731],{"class":666},[599,25294,25295,25297,25299,25302,25305,25307,25309],{"class":601,"line":1997},[599,25296,13507],{"class":666},[599,25298,1060],{"class":605},[599,25300,25301],{"class":609}," StringCchCopyW",[599,25303,25304],{"class":666},"(pszUsername, cchUsername, pchSlash ",[599,25306,2543],{"class":605},[599,25308,973],{"class":949},[599,25310,725],{"class":666},[599,25312,25313,25315],{"class":601,"line":2002},[599,25314,3551],{"class":605},[599,25316,12751],{"class":666},[599,25318,25319],{"class":601,"line":2024},[599,25320,981],{"class":666},[599,25322,25323],{"class":601,"line":2037},[599,25324,651],{"emptyLinePlaceholder":650},[599,25326,25327,25329,25331,25333,25335,25337],{"class":601,"line":2047},[599,25328,12617],{"class":609},[599,25330,19770],{"class":609},[599,25332,679],{"class":666},[599,25334,11361],{"class":609},[599,25336,11371],{"class":697},[599,25338,813],{"class":666},[599,25340,25341,25343],{"class":601,"line":2052},[599,25342,24285],{"class":609},[599,25344,813],{"class":666},[599,25346,25347,25349,25351,25353],{"class":601,"line":2096},[599,25348,24294],{"class":609},[599,25350,748],{"class":605},[599,25352,24299],{"class":697},[599,25354,1029],{"class":666},[599,25356,25357],{"class":601,"line":2124},[599,25358,667],{"class":666},[599,25360,25361],{"class":601,"line":2129},[599,25362,25363],{"class":772},"    \u002F\u002F The Microsoft sample runs the password through CredProtect first. A plain\n",[599,25365,25366],{"class":601,"line":2163},[599,25367,25368],{"class":772},"    \u002F\u002F copy works for a local logon and keeps this demo small.\n",[599,25370,25371,25373,25376,25378,25380],{"class":601,"line":2186},[599,25372,12236],{"class":605},[599,25374,25375],{"class":666},"ppwzProtectedPassword ",[599,25377,1060],{"class":605},[599,25379,1962],{"class":949},[599,25381,1066],{"class":666},[599,25383,25384,25386,25388,25391,25393,25395,25397,25399],{"class":601,"line":2195},[599,25385,3551],{"class":605},[599,25387,16387],{"class":609},[599,25389,25390],{"class":666},"(pwzPassword ",[599,25392,9412],{"class":605},[599,25394,16245],{"class":666},[599,25396,590],{"class":605},[599,25398,16458],{"class":619},[599,25400,25401],{"class":666},", ppwzProtectedPassword);\n",[599,25403,25404],{"class":601,"line":2200},[599,25405,981],{"class":666},[599,25407,25408],{"class":601,"line":2212},[599,25409,651],{"emptyLinePlaceholder":650},[599,25411,25412,25414,25416,25418,25420,25422,25424,25426,25428,25430,25432,25434],{"class":601,"line":2220},[599,25413,12617],{"class":609},[599,25415,20017],{"class":609},[599,25417,679],{"class":666},[599,25419,10681],{"class":609},[599,25421,24323],{"class":697},[599,25423,212],{"class":666},[599,25425,10681],{"class":609},[599,25427,24330],{"class":697},[599,25429,212],{"class":666},[599,25431,10681],{"class":609},[599,25433,11371],{"class":697},[599,25435,813],{"class":666},[599,25437,25438,25440,25442],{"class":601,"line":2225},[599,25439,24343],{"class":609},[599,25441,11079],{"class":697},[599,25443,813],{"class":666},[599,25445,25446,25448,25450,25452],{"class":601,"line":2230},[599,25447,24352],{"class":609},[599,25449,748],{"class":605},[599,25451,24357],{"class":697},[599,25453,1029],{"class":666},[599,25455,25456],{"class":601,"line":2265},[599,25457,667],{"class":666},[599,25459,25460,25462,25465,25467,25469,25471],{"class":601,"line":2286},[599,25461,15738],{"class":609},[599,25463,25464],{"class":666},"(pkiul, ",[599,25466,2444],{"class":605},[599,25468,679],{"class":666},[599,25470,748],{"class":605},[599,25472,25473],{"class":666},"pkiul));\n",[599,25475,25476,25479,25481,25484,25486,25489],{"class":601,"line":2291},[599,25477,25478],{"class":609},"    KERB_INTERACTIVE_LOGON",[599,25480,748],{"class":605},[599,25482,25483],{"class":666}," pkil ",[599,25485,1060],{"class":605},[599,25487,25488],{"class":605}," &",[599,25490,25491],{"class":666},"pkiul->Logon;\n",[599,25493,25494],{"class":601,"line":2297},[599,25495,651],{"emptyLinePlaceholder":650},[599,25497,25498,25500],{"class":601,"line":2317},[599,25499,12299],{"class":605},[599,25501,12302],{"class":666},[599,25503,25504],{"class":601,"line":2331},[599,25505,1095],{"class":666},[599,25507,25508,25510,25513,25515,25518,25521],{"class":601,"line":2361},[599,25509,12311],{"class":605},[599,25511,25512],{"class":666}," CPUS_LOGON:              pkil->MessageType ",[599,25514,1060],{"class":605},[599,25516,25517],{"class":666}," KerbInteractiveLogon;       ",[599,25519,25520],{"class":605},"break",[599,25522,1066],{"class":666},[599,25524,25525,25527,25530,25532,25535,25537],{"class":601,"line":2366},[599,25526,12311],{"class":605},[599,25528,25529],{"class":666}," CPUS_UNLOCK_WORKSTATION: pkil->MessageType ",[599,25531,1060],{"class":605},[599,25533,25534],{"class":666}," KerbWorkstationUnlockLogon; ",[599,25536,25520],{"class":605},[599,25538,1066],{"class":666},[599,25540,25541,25543,25546,25548],{"class":601,"line":2393},[599,25542,12388],{"class":605},[599,25544,25545],{"class":666},":                      ",[599,25547,1127],{"class":605},[599,25549,12397],{"class":666},[599,25551,25552],{"class":601,"line":2406},[599,25553,1224],{"class":666},[599,25555,25556],{"class":601,"line":2411},[599,25557,651],{"emptyLinePlaceholder":650},[599,25559,25560,25563,25565,25567],{"class":601,"line":2416},[599,25561,25562],{"class":609},"    InitUnicodeString",[599,25564,679],{"class":666},[599,25566,694],{"class":605},[599,25568,25569],{"class":666},"pkil->LogonDomainName, pwzDomain);\n",[599,25571,25572,25574,25576,25578],{"class":601,"line":2428},[599,25573,25562],{"class":609},[599,25575,679],{"class":666},[599,25577,694],{"class":605},[599,25579,25580],{"class":666},"pkil->UserName, pwzUsername);\n",[599,25582,25583,25585,25587,25589],{"class":601,"line":2450},[599,25584,25562],{"class":609},[599,25586,679],{"class":666},[599,25588,694],{"class":605},[599,25590,25591],{"class":666},"pkil->Password, pwzPassword);\n",[599,25593,25594,25596],{"class":601,"line":2459},[599,25595,3551],{"class":605},[599,25597,12172],{"class":666},[599,25599,25600],{"class":601,"line":2464},[599,25601,981],{"class":666},[599,25603,25604],{"class":601,"line":2470},[599,25605,651],{"emptyLinePlaceholder":650},[599,25607,25608,25610,25612,25614,25616,25618,25620,25622],{"class":601,"line":2476},[599,25609,12617],{"class":609},[599,25611,20046],{"class":609},[599,25613,679],{"class":666},[599,25615,682],{"class":605},[599,25617,24386],{"class":609},[599,25619,694],{"class":605},[599,25621,24391],{"class":697},[599,25623,813],{"class":666},[599,25625,25626,25628,25630,25632,25634,25636,25638,25640],{"class":601,"line":2503},[599,25627,24398],{"class":609},[599,25629,4056],{"class":605},[599,25631,24403],{"class":697},[599,25633,212],{"class":666},[599,25635,5878],{"class":609},[599,25637,748],{"class":605},[599,25639,24412],{"class":697},[599,25641,1029],{"class":666},[599,25643,25644],{"class":601,"line":2537},[599,25645,667],{"class":666},[599,25647,25648,25650,25652,25654,25657,25659],{"class":601,"line":2569},[599,25649,12451],{"class":605},[599,25651,13558],{"class":609},[599,25653,694],{"class":605},[599,25655,25656],{"class":666}," in ",[599,25658,1060],{"class":605},[599,25660,25661],{"class":666}," rkiulIn.Logon;\n",[599,25663,25664,25666,25668,25670,25672,25675,25677,25680,25682,25685,25687],{"class":601,"line":2600},[599,25665,11440],{"class":609},[599,25667,7454],{"class":666},[599,25669,1060],{"class":605},[599,25671,6453],{"class":605},[599,25673,25674],{"class":666},"(rkiulIn) ",[599,25676,2543],{"class":605},[599,25678,25679],{"class":666}," in.LogonDomainName.Length ",[599,25681,2543],{"class":605},[599,25683,25684],{"class":666}," in.UserName.Length ",[599,25686,2543],{"class":605},[599,25688,25689],{"class":666}," in.Password.Length;\n",[599,25691,25692],{"class":601,"line":2623},[599,25693,651],{"emptyLinePlaceholder":650},[599,25695,25696,25698,25700,25703],{"class":601,"line":2628},[599,25697,13403],{"class":609},[599,25699,748],{"class":605},[599,25701,25702],{"class":666}," pkiulOut ",[599,25704,10667],{"class":605},[599,25706,25707,25709,25711,25713,25715,25717],{"class":601,"line":2642},[599,25708,13415],{"class":605},[599,25710,13418],{"class":666},[599,25712,5897],{"class":605},[599,25714,679],{"class":666},[599,25716,13425],{"class":609},[599,25718,25719],{"class":666},"(cb));\n",[599,25721,25722,25724,25726,25728],{"class":601,"line":2668},[599,25723,3514],{"class":605},[599,25725,1327],{"class":666},[599,25727,2435],{"class":605},[599,25729,25730],{"class":666},"pkiulOut)\n",[599,25732,25733,25735],{"class":601,"line":2682},[599,25734,1211],{"class":605},[599,25736,12692],{"class":666},[599,25738,25739],{"class":601,"line":2698},[599,25740,651],{"emptyLinePlaceholder":650},[599,25742,25743,25745,25748,25750,25752,25754],{"class":601,"line":2707},[599,25744,15738],{"class":609},[599,25746,25747],{"class":666},"(pkiulOut, ",[599,25749,2444],{"class":605},[599,25751,679],{"class":666},[599,25753,748],{"class":605},[599,25755,25756],{"class":666},"pkiulOut));\n",[599,25758,25759,25762,25764],{"class":601,"line":2712},[599,25760,25761],{"class":666},"    pkiulOut->Logon.MessageType ",[599,25763,1060],{"class":605},[599,25765,25766],{"class":666}," in.MessageType;\n",[599,25768,25769],{"class":601,"line":2717},[599,25770,651],{"emptyLinePlaceholder":650},[599,25772,25773,25775,25777,25780,25782,25784,25786,25788,25791,25793,25795,25797,25799],{"class":601,"line":2760},[599,25774,9970],{"class":609},[599,25776,748],{"class":605},[599,25778,25779],{"class":666}," pbData ",[599,25781,1060],{"class":605},[599,25783,24903],{"class":605},[599,25785,714],{"class":666},[599,25787,5897],{"class":605},[599,25789,25790],{"class":666},"(pkiulOut) ",[599,25792,2543],{"class":605},[599,25794,6453],{"class":605},[599,25796,679],{"class":666},[599,25798,748],{"class":605},[599,25800,25801],{"class":666},"pkiulOut);\n",[599,25803,25804,25807,25810,25812],{"class":601,"line":2781},[599,25805,25806],{"class":609},"    PackUnicodeString",[599,25808,25809],{"class":666},"(in.LogonDomainName, ",[599,25811,694],{"class":605},[599,25813,25814],{"class":666},"pkiulOut->Logon.LogonDomainName, pbData, pkiulOut);\n",[599,25816,25817,25820,25822],{"class":601,"line":2802},[599,25818,25819],{"class":666},"    pbData ",[599,25821,1455],{"class":605},[599,25823,25824],{"class":666}," in.LogonDomainName.Length;\n",[599,25826,25827,25829,25832,25834],{"class":601,"line":2807},[599,25828,25806],{"class":609},[599,25830,25831],{"class":666},"(in.UserName, ",[599,25833,694],{"class":605},[599,25835,25836],{"class":666},"pkiulOut->Logon.UserName, pbData, pkiulOut);\n",[599,25838,25839,25841,25843],{"class":601,"line":2819},[599,25840,25819],{"class":666},[599,25842,1455],{"class":605},[599,25844,25845],{"class":666}," in.UserName.Length;\n",[599,25847,25848,25850,25853,25855],{"class":601,"line":2824},[599,25849,25806],{"class":609},[599,25851,25852],{"class":666},"(in.Password, ",[599,25854,694],{"class":605},[599,25856,25857],{"class":666},"pkiulOut->Logon.Password, pbData, pkiulOut);\n",[599,25859,25860],{"class":601,"line":2830},[599,25861,651],{"emptyLinePlaceholder":650},[599,25863,25864,25866,25869,25871,25873,25875,25877],{"class":601,"line":2851},[599,25865,12236],{"class":605},[599,25867,25868],{"class":666},"prgb ",[599,25870,1060],{"class":605},[599,25872,24903],{"class":605},[599,25874,714],{"class":666},[599,25876,5897],{"class":605},[599,25878,25879],{"class":666},"(pkiulOut);\n",[599,25881,25882,25884,25887,25889],{"class":601,"line":2860},[599,25883,12236],{"class":605},[599,25885,25886],{"class":666},"pcb  ",[599,25888,1060],{"class":605},[599,25890,25891],{"class":666}," cb;\n",[599,25893,25894,25896],{"class":601,"line":2874},[599,25895,3551],{"class":605},[599,25897,12172],{"class":666},[599,25899,25900],{"class":601,"line":2887},[599,25901,981],{"class":666},[599,25903,25904],{"class":601,"line":2892},[599,25905,651],{"emptyLinePlaceholder":650},[599,25907,25908,25910,25912,25914,25916,25918,25920,25922,25924,25926],{"class":601,"line":2915},[599,25909,12617],{"class":609},[599,25911,13534],{"class":609},[599,25913,679],{"class":666},[599,25915,13418],{"class":609},[599,25917,748],{"class":605},[599,25919,24357],{"class":697},[599,25921,212],{"class":666},[599,25923,5878],{"class":609},[599,25925,24449],{"class":697},[599,25927,1029],{"class":666},[599,25929,25930],{"class":601,"line":2924},[599,25931,667],{"class":666},[599,25933,25934,25936,25938,25940,25942,25944,25946],{"class":601,"line":2951},[599,25935,3514],{"class":605},[599,25937,8982],{"class":666},[599,25939,711],{"class":605},[599,25941,6453],{"class":605},[599,25943,679],{"class":666},[599,25945,748],{"class":605},[599,25947,25948],{"class":666},"pkiul))\n",[599,25950,25951,25953],{"class":601,"line":2956},[599,25952,1211],{"class":605},[599,25954,12397],{"class":666},[599,25956,25957],{"class":601,"line":2961},[599,25958,651],{"emptyLinePlaceholder":650},[599,25960,25961,25963,25965,25967,25969,25971],{"class":601,"line":2982},[599,25962,25478],{"class":609},[599,25964,748],{"class":605},[599,25966,25483],{"class":666},[599,25968,1060],{"class":605},[599,25970,25488],{"class":605},[599,25972,25491],{"class":666},[599,25974,25975,25977,25979,25982,25985,25987,25990],{"class":601,"line":3011},[599,25976,3514],{"class":605},[599,25978,1327],{"class":666},[599,25980,25981],{"class":609},"UnpackUnicodeString",[599,25983,25984],{"class":666},"(pkiul, cb, ",[599,25986,694],{"class":605},[599,25988,25989],{"class":666},"pkil->LogonDomainName) ",[599,25991,13492],{"class":605},[599,25993,25994,25997,25999,26001,26004],{"class":601,"line":3016},[599,25995,25996],{"class":609},"        UnpackUnicodeString",[599,25998,25984],{"class":666},[599,26000,694],{"class":605},[599,26002,26003],{"class":666},"pkil->UserName) ",[599,26005,13492],{"class":605},[599,26007,26008,26010,26012,26014],{"class":601,"line":3044},[599,26009,25996],{"class":609},[599,26011,25984],{"class":666},[599,26013,694],{"class":605},[599,26015,26016],{"class":666},"pkil->Password))\n",[599,26018,26019,26021],{"class":601,"line":3051},[599,26020,1211],{"class":605},[599,26022,12172],{"class":666},[599,26024,26025,26027],{"class":601,"line":3073},[599,26026,3551],{"class":605},[599,26028,12397],{"class":666},[599,26030,26031],{"class":601,"line":3078},[599,26032,981],{"class":666},[599,26034,26035],{"class":601,"line":3084},[599,26036,651],{"emptyLinePlaceholder":650},[599,26038,26039,26041,26043,26045,26047,26049,26051],{"class":601,"line":3090},[599,26040,12617],{"class":609},[599,26042,20100],{"class":609},[599,26044,679],{"class":666},[599,26046,1924],{"class":609},[599,26048,748],{"class":605},[599,26050,24470],{"class":697},[599,26052,1029],{"class":666},[599,26054,26055],{"class":601,"line":3096},[599,26056,667],{"class":666},[599,26058,26059,26062,26065,26067,26069],{"class":601,"line":3109},[599,26060,26061],{"class":609},"    HANDLE",[599,26063,26064],{"class":666}," hLsa ",[599,26066,1060],{"class":605},[599,26068,1962],{"class":949},[599,26070,1066],{"class":666},[599,26072,26073,26076,26078,26080,26083,26085,26087],{"class":601,"line":3116},[599,26074,26075],{"class":609},"    NTSTATUS",[599,26077,6906],{"class":666},[599,26079,1060],{"class":605},[599,26081,26082],{"class":609}," LsaConnectUntrusted",[599,26084,679],{"class":666},[599,26086,694],{"class":605},[599,26088,26089],{"class":666},"hLsa);\n",[599,26091,26092,26094,26096,26098,26100],{"class":601,"line":3121},[599,26093,3514],{"class":605},[599,26095,6961],{"class":666},[599,26097,2030],{"class":605},[599,26099,1286],{"class":949},[599,26101,1029],{"class":666},[599,26103,26104,26106,26109],{"class":601,"line":3136},[599,26105,1211],{"class":605},[599,26107,26108],{"class":609}," HRESULT_FROM_NT",[599,26110,26111],{"class":666},"(status);\n",[599,26113,26114],{"class":601,"line":3164},[599,26115,651],{"emptyLinePlaceholder":650},[599,26117,26118,26121],{"class":601,"line":3169},[599,26119,26120],{"class":609},"    LSA_STRING",[599,26122,5803],{"class":666},[599,26124,26125,26128,26130,26133,26136,26138],{"class":601,"line":3180},[599,26126,26127],{"class":666},"    name.Buffer        ",[599,26129,1060],{"class":605},[599,26131,26132],{"class":605}," const_cast\u003C",[599,26134,26135],{"class":666},"PCHAR",[599,26137,717],{"class":605},[599,26139,26140],{"class":666},"(NEGOSSP_NAME_A);\n",[599,26142,26143,26146,26148,26150,26152,26154,26156,26159],{"class":601,"line":3189},[599,26144,26145],{"class":666},"    name.Length        ",[599,26147,1060],{"class":605},[599,26149,2374],{"class":605},[599,26151,24736],{"class":666},[599,26153,717],{"class":605},[599,26155,679],{"class":666},[599,26157,26158],{"class":609},"strlen",[599,26160,26161],{"class":666},"(name.Buffer));\n",[599,26163,26164,26167,26169,26171,26173,26175,26178,26180,26182],{"class":601,"line":3194},[599,26165,26166],{"class":666},"    name.MaximumLength ",[599,26168,1060],{"class":605},[599,26170,2374],{"class":605},[599,26172,24736],{"class":666},[599,26174,717],{"class":605},[599,26176,26177],{"class":666},"(name.Length ",[599,26179,2543],{"class":605},[599,26181,973],{"class":949},[599,26183,725],{"class":666},[599,26185,26186],{"class":601,"line":3199},[599,26187,651],{"emptyLinePlaceholder":650},[599,26189,26190,26193,26196,26198,26200],{"class":601,"line":3208},[599,26191,26192],{"class":609},"    ULONG",[599,26194,26195],{"class":666}," ulPackage ",[599,26197,1060],{"class":605},[599,26199,1286],{"class":949},[599,26201,1066],{"class":666},[599,26203,26204,26207,26209,26212,26215,26217,26220,26222],{"class":601,"line":3213},[599,26205,26206],{"class":666},"    status ",[599,26208,1060],{"class":605},[599,26210,26211],{"class":609}," LsaLookupAuthenticationPackage",[599,26213,26214],{"class":666},"(hLsa, ",[599,26216,694],{"class":605},[599,26218,26219],{"class":666},"name, ",[599,26221,694],{"class":605},[599,26223,26224],{"class":666},"ulPackage);\n",[599,26226,26227,26230],{"class":601,"line":7367},[599,26228,26229],{"class":609},"    LsaDeregisterLogonProcess",[599,26231,26232],{"class":666},"(hLsa);\n",[599,26234,26235,26237,26239,26241,26243],{"class":601,"line":7376},[599,26236,3514],{"class":605},[599,26238,6961],{"class":666},[599,26240,2030],{"class":605},[599,26242,1286],{"class":949},[599,26244,1029],{"class":666},[599,26246,26247,26249,26251],{"class":601,"line":7381},[599,26248,1211],{"class":605},[599,26250,26108],{"class":609},[599,26252,26111],{"class":666},[599,26254,26255],{"class":601,"line":7394},[599,26256,651],{"emptyLinePlaceholder":650},[599,26258,26259,26261,26264,26266],{"class":601,"line":7421},[599,26260,12236],{"class":605},[599,26262,26263],{"class":666},"pulAuthPackage ",[599,26265,1060],{"class":605},[599,26267,26268],{"class":666}," ulPackage;\n",[599,26270,26271,26273],{"class":601,"line":7430},[599,26272,3551],{"class":605},[599,26274,12172],{"class":666},[599,26276,26277],{"class":601,"line":7435},[599,26278,981],{"class":666},[599,26280,26281],{"class":601,"line":7449},[599,26282,651],{"emptyLinePlaceholder":650},[599,26284,26285,26287,26289,26291,26293,26295,26297,26299],{"class":601,"line":7463},[599,26286,12617],{"class":609},[599,26288,14098],{"class":609},[599,26290,679],{"class":666},[599,26292,682],{"class":605},[599,26294,10661],{"class":609},[599,26296,694],{"class":605},[599,26298,24493],{"class":697},[599,26300,813],{"class":666},[599,26302,26303,26305,26307,26309],{"class":601,"line":7478},[599,26304,24500],{"class":609},[599,26306,4056],{"class":605},[599,26308,11187],{"class":697},[599,26310,1029],{"class":666},[599,26312,26313],{"class":601,"line":7514},[599,26314,667],{"class":666},[599,26316,26317,26319,26322,26324,26326],{"class":601,"line":7544},[599,26318,12236],{"class":605},[599,26320,26321],{"class":666},"ppcpfd ",[599,26323,1060],{"class":605},[599,26325,1962],{"class":949},[599,26327,1066],{"class":666},[599,26329,26330],{"class":601,"line":7549},[599,26331,651],{"emptyLinePlaceholder":650},[599,26333,26334,26336,26338,26341],{"class":601,"line":7561},[599,26335,15433],{"class":609},[599,26337,748],{"class":605},[599,26339,26340],{"class":666}," pcpfd ",[599,26342,10667],{"class":605},[599,26344,26345,26347,26349,26351],{"class":601,"line":7593},[599,26346,13415],{"class":605},[599,26348,11182],{"class":666},[599,26350,5897],{"class":605},[599,26352,13310],{"class":666},[599,26354,26355,26358,26360,26362],{"class":601,"line":7598},[599,26356,26357],{"class":609},"            CoTaskMemAlloc",[599,26359,679],{"class":666},[599,26361,2444],{"class":605},[599,26363,26364],{"class":666},"(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)));\n",[599,26366,26367,26369,26371,26373],{"class":601,"line":7606},[599,26368,3514],{"class":605},[599,26370,1327],{"class":666},[599,26372,2435],{"class":605},[599,26374,26375],{"class":666},"pcpfd)\n",[599,26377,26378,26380],{"class":601,"line":7626},[599,26379,1211],{"class":605},[599,26381,12692],{"class":666},[599,26383,26384],{"class":601,"line":7635},[599,26385,651],{"emptyLinePlaceholder":650},[599,26387,26388,26391,26393],{"class":601,"line":7640},[599,26389,26390],{"class":666},"    pcpfd->dwFieldID     ",[599,26392,1060],{"class":605},[599,26394,26395],{"class":666}," rcpfd.dwFieldID;\n",[599,26397,26398,26401,26403],{"class":601,"line":7652},[599,26399,26400],{"class":666},"    pcpfd->cpft          ",[599,26402,1060],{"class":605},[599,26404,26405],{"class":666}," rcpfd.cpft;\n",[599,26407,26408,26411,26413],{"class":601,"line":7667},[599,26409,26410],{"class":666},"    pcpfd->guidFieldType ",[599,26412,1060],{"class":605},[599,26414,26415],{"class":666}," rcpfd.guidFieldType;\n",[599,26417,26418,26421,26423,26425],{"class":601,"line":7676},[599,26419,26420],{"class":666},"    pcpfd->pszLabel      ",[599,26422,1060],{"class":605},[599,26424,1962],{"class":949},[599,26426,1066],{"class":666},[599,26428,26429],{"class":601,"line":7681},[599,26430,651],{"emptyLinePlaceholder":650},[599,26432,26433,26435,26437,26439],{"class":601,"line":7695},[599,26434,11344],{"class":609},[599,26436,12703],{"class":666},[599,26438,1060],{"class":605},[599,26440,12172],{"class":666},[599,26442,26443,26445],{"class":601,"line":7716},[599,26444,3514],{"class":605},[599,26446,26447],{"class":666}," (rcpfd.pszLabel)\n",[599,26449,26450,26452,26454,26456,26459,26461],{"class":601,"line":7721},[599,26451,13507],{"class":666},[599,26453,1060],{"class":605},[599,26455,16387],{"class":609},[599,26457,26458],{"class":666},"(rcpfd.pszLabel, ",[599,26460,694],{"class":605},[599,26462,26463],{"class":666},"pcpfd->pszLabel);\n",[599,26465,26466],{"class":601,"line":7727},[599,26467,651],{"emptyLinePlaceholder":650},[599,26469,26470,26472,26474,26476],{"class":601,"line":7733},[599,26471,3514],{"class":605},[599,26473,1327],{"class":666},[599,26475,12847],{"class":609},[599,26477,12731],{"class":666},[599,26479,26480,26482,26484,26486],{"class":601,"line":7760},[599,26481,12141],{"class":605},[599,26483,26321],{"class":666},[599,26485,1060],{"class":605},[599,26487,26488],{"class":666}," pcpfd;\n",[599,26490,26491],{"class":601,"line":7765},[599,26492,24943],{"class":605},[599,26494,26495,26497],{"class":601,"line":7781},[599,26496,13187],{"class":609},[599,26498,26499],{"class":666},"(pcpfd);\n",[599,26501,26502,26504],{"class":601,"line":7798},[599,26503,3551],{"class":605},[599,26505,12751],{"class":666},[599,26507,26508],{"class":601,"line":7808},[599,26509,981],{"class":666},[15,26511,26512,26515,26516,26518],{},[69,26513,26514],{},"ProtectIfNecessaryAndCopyPassword"," just copies the password. The Microsoft sample encrypts it with ",[69,26517,24125],{},". For a local logon this works fine and the code stays smaller.",[15,26520,26521,26522,26525,26526,26529,26530,26533],{},"The COM part is standard. One class factory for both CLSIDs. The only thing you can easily get wrong is when the DLL is unloaded. LogonUI regularly asks ",[69,26523,26524],{},"DllCanUnloadNow"," if the DLL can be unloaded. As long as any object exists, the answer has to be no. That's why the provider, the tile and the filter call ",[69,26527,26528],{},"DllAddRef()"," in the constructor and ",[69,26531,26532],{},"DllRelease()"," in the destructor. If you forget this, the DLL can be unloaded while the tile is still in use and LogonUI crashes. And only sometimes, which makes it really hard to find.",[15,26535,26536,590],{},[69,26537,507],{},[148,26539,26541],{"className":593,"code":26540,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cguiddef.h>\n\n\u002F\u002F Generate your own GUIDs before using this anywhere and keep them in sync\n\u002F\u002F with the .reg files. dll.cpp includes initguid.h before this header, so the\n\u002F\u002F GUIDs are defined there and only declared everywhere else.\n\n\u002F\u002F {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\nDEFINE_GUID(CLSID_CTacProvider,\n    0xb1e7c9a0, 0x2f4d, 0x4c6b, 0x9a, 0x11, 0x00, 0x00, 0xc0, 0xff, 0xee, 0x01);\n\n\u002F\u002F {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\nDEFINE_GUID(CLSID_CTacFilter,\n    0xb1e7c9a0, 0x2f4d, 0x4c6b, 0x9a, 0x11, 0x00, 0x00, 0xc0, 0xff, 0xee, 0x02);\n",[69,26542,26543,26549,26556,26560,26565,26570,26575,26579,26584,26592,26671,26675,26680,26687],{"__ignoreMap":154},[599,26544,26545,26547],{"class":601,"line":602},[599,26546,606],{"class":605},[599,26548,610],{"class":609},[599,26550,26551,26553],{"class":601,"line":613},[599,26552,616],{"class":605},[599,26554,26555],{"class":619}," \u003Cguiddef.h>\n",[599,26557,26558],{"class":601,"line":623},[599,26559,651],{"emptyLinePlaceholder":650},[599,26561,26562],{"class":601,"line":631},[599,26563,26564],{"class":772},"\u002F\u002F Generate your own GUIDs before using this anywhere and keep them in sync\n",[599,26566,26567],{"class":601,"line":639},[599,26568,26569],{"class":772},"\u002F\u002F with the .reg files. dll.cpp includes initguid.h before this header, so the\n",[599,26571,26572],{"class":601,"line":647},[599,26573,26574],{"class":772},"\u002F\u002F GUIDs are defined there and only declared everywhere else.\n",[599,26576,26577],{"class":601,"line":654},[599,26578,651],{"emptyLinePlaceholder":650},[599,26580,26581],{"class":601,"line":663},[599,26582,26583],{"class":772},"\u002F\u002F {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\n",[599,26585,26586,26589],{"class":601,"line":670},[599,26587,26588],{"class":609},"DEFINE_GUID",[599,26590,26591],{"class":666},"(CLSID_CTacProvider,\n",[599,26593,26594,26597,26600,26602,26604,26607,26609,26611,26614,26616,26618,26621,26623,26625,26628,26630,26632,26635,26637,26639,26641,26643,26645,26648,26650,26652,26655,26657,26659,26662,26664,26666,26669],{"class":601,"line":728},[599,26595,26596],{"class":605},"    0x",[599,26598,26599],{"class":949},"b1e7c9a0",[599,26601,212],{"class":666},[599,26603,11586],{"class":605},[599,26605,26606],{"class":949},"2f4d",[599,26608,212],{"class":666},[599,26610,11586],{"class":605},[599,26612,26613],{"class":949},"4c6b",[599,26615,212],{"class":666},[599,26617,11586],{"class":605},[599,26619,26620],{"class":949},"9a",[599,26622,212],{"class":666},[599,26624,11586],{"class":605},[599,26626,26627],{"class":949},"11",[599,26629,212],{"class":666},[599,26631,11586],{"class":605},[599,26633,26634],{"class":949},"00",[599,26636,212],{"class":666},[599,26638,11586],{"class":605},[599,26640,26634],{"class":949},[599,26642,212],{"class":666},[599,26644,11586],{"class":605},[599,26646,26647],{"class":949},"c0",[599,26649,212],{"class":666},[599,26651,11586],{"class":605},[599,26653,26654],{"class":949},"ff",[599,26656,212],{"class":666},[599,26658,11586],{"class":605},[599,26660,26661],{"class":949},"ee",[599,26663,212],{"class":666},[599,26665,11586],{"class":605},[599,26667,26668],{"class":949},"01",[599,26670,725],{"class":666},[599,26672,26673],{"class":601,"line":764},[599,26674,651],{"emptyLinePlaceholder":650},[599,26676,26677],{"class":601,"line":769},[599,26678,26679],{"class":772},"\u002F\u002F {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\n",[599,26681,26682,26684],{"class":601,"line":776},[599,26683,26588],{"class":609},[599,26685,26686],{"class":666},"(CLSID_CTacFilter,\n",[599,26688,26689,26691,26693,26695,26697,26699,26701,26703,26705,26707,26709,26711,26713,26715,26717,26719,26721,26723,26725,26727,26729,26731,26733,26735,26737,26739,26741,26743,26745,26747,26749,26751,26753],{"class":601,"line":816},[599,26690,26596],{"class":605},[599,26692,26599],{"class":949},[599,26694,212],{"class":666},[599,26696,11586],{"class":605},[599,26698,26606],{"class":949},[599,26700,212],{"class":666},[599,26702,11586],{"class":605},[599,26704,26613],{"class":949},[599,26706,212],{"class":666},[599,26708,11586],{"class":605},[599,26710,26620],{"class":949},[599,26712,212],{"class":666},[599,26714,11586],{"class":605},[599,26716,26627],{"class":949},[599,26718,212],{"class":666},[599,26720,11586],{"class":605},[599,26722,26634],{"class":949},[599,26724,212],{"class":666},[599,26726,11586],{"class":605},[599,26728,26634],{"class":949},[599,26730,212],{"class":666},[599,26732,11586],{"class":605},[599,26734,26647],{"class":949},[599,26736,212],{"class":666},[599,26738,11586],{"class":605},[599,26740,26654],{"class":949},[599,26742,212],{"class":666},[599,26744,11586],{"class":605},[599,26746,26661],{"class":949},[599,26748,212],{"class":666},[599,26750,11586],{"class":605},[599,26752,11625],{"class":949},[599,26754,725],{"class":666},[15,26756,26757,590],{},[69,26758,26759],{},"dll.h",[148,26761,26763],{"className":593,"code":26762,"language":595,"meta":154,"style":154},"#pragma once\n#include \u003Cwindows.h>\n\nvoid DllAddRef();\nvoid DllRelease();\n\nHRESULT CTacProvider_CreateInstance(REFIID riid, void** ppv);\nHRESULT CTacFilter_CreateInstance(REFIID riid, void** ppv);\n",[69,26764,26765,26771,26777,26781,26790,26799,26803,26823],{"__ignoreMap":154},[599,26766,26767,26769],{"class":601,"line":602},[599,26768,606],{"class":605},[599,26770,610],{"class":609},[599,26772,26773,26775],{"class":601,"line":613},[599,26774,616],{"class":605},[599,26776,620],{"class":619},[599,26778,26779],{"class":601,"line":623},[599,26780,651],{"emptyLinePlaceholder":650},[599,26782,26783,26785,26788],{"class":601,"line":631},[599,26784,11860],{"class":605},[599,26786,26787],{"class":609}," DllAddRef",[599,26789,1313],{"class":666},[599,26791,26792,26794,26797],{"class":601,"line":639},[599,26793,11860],{"class":605},[599,26795,26796],{"class":609}," DllRelease",[599,26798,1313],{"class":666},[599,26800,26801],{"class":601,"line":647},[599,26802,651],{"emptyLinePlaceholder":650},[599,26804,26805,26807,26809,26811,26813,26815,26817,26819,26821],{"class":601,"line":654},[599,26806,12617],{"class":609},[599,26808,11292],{"class":609},[599,26810,679],{"class":666},[599,26812,11042],{"class":609},[599,26814,11045],{"class":697},[599,26816,212],{"class":666},[599,26818,11050],{"class":605},[599,26820,11053],{"class":697},[599,26822,725],{"class":666},[599,26824,26825,26827,26829,26831,26833,26835,26837,26839,26841],{"class":601,"line":663},[599,26826,12617],{"class":609},[599,26828,23350],{"class":609},[599,26830,679],{"class":666},[599,26832,11042],{"class":609},[599,26834,11045],{"class":697},[599,26836,212],{"class":666},[599,26838,11050],{"class":605},[599,26840,11053],{"class":697},[599,26842,725],{"class":666},[15,26844,26845,590],{},[69,26846,26847],{},"dll.cpp",[148,26849,26851],{"className":593,"code":26850,"language":595,"meta":154,"style":154},"#include \u003Cwindows.h>\n#include \u003Cnew>\n\n#include \u003Cinitguid.h>\n#include \"guid.h\"\n#include \"dll.h\"\n\n\u002F\u002F Number of live objects. LogonUI calls DllCanUnloadNow from time to time and\n\u002F\u002F must not unload the DLL while a provider, credential or filter still exists.\nstatic LONG g_cRef = 0;\n\nvoid DllAddRef()  { InterlockedIncrement(&g_cRef); }\nvoid DllRelease() { InterlockedDecrement(&g_cRef); }\n\nclass CClassFactory : public IClassFactory\n{\npublic:\n    explicit CClassFactory(REFCLSID rclsid) : _cRef(1), _clsid(rclsid) { DllAddRef(); }\n\n    IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&_cRef); }\n\n    IFACEMETHODIMP_(ULONG) Release()\n    {\n        LONG cRef = InterlockedDecrement(&_cRef);\n        if (cRef == 0)\n            delete this;\n        return cRef;\n    }\n\n    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)\n    {\n        if (!ppv)\n            return E_POINTER;\n        if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))\n        {\n            *ppv = static_cast\u003CIClassFactory*>(this);\n            AddRef();\n            return S_OK;\n        }\n        *ppv = nullptr;\n        return E_NOINTERFACE;\n    }\n\n    IFACEMETHODIMP CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv)\n    {\n        if (pUnkOuter)\n            return CLASS_E_NOAGGREGATION;\n        if (IsEqualCLSID(_clsid, CLSID_CTacProvider))\n            return CTacProvider_CreateInstance(riid, ppv);\n        if (IsEqualCLSID(_clsid, CLSID_CTacFilter))\n            return CTacFilter_CreateInstance(riid, ppv);\n        return CLASS_E_CLASSNOTAVAILABLE;\n    }\n\n    IFACEMETHODIMP LockServer(BOOL fLock)\n    {\n        if (fLock)\n            DllAddRef();\n        else\n            DllRelease();\n        return S_OK;\n    }\n\nprivate:\n    ~CClassFactory() { DllRelease(); }\n\n    LONG  _cRef;\n    CLSID _clsid;\n};\n\nSTDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)\n{\n    if (!IsEqualCLSID(rclsid, CLSID_CTacProvider) && !IsEqualCLSID(rclsid, CLSID_CTacFilter))\n        return CLASS_E_CLASSNOTAVAILABLE;\n\n    CClassFactory* pcf = new (std::nothrow) CClassFactory(rclsid);\n    if (!pcf)\n        return E_OUTOFMEMORY;\n\n    HRESULT hr = pcf->QueryInterface(riid, ppv);\n    pcf->Release();\n    return hr;\n}\n\nSTDAPI DllCanUnloadNow()\n{\n    return g_cRef == 0 ? S_OK : S_FALSE;\n}\n\nBOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID)\n{\n    if (dwReason == DLL_PROCESS_ATTACH)\n        DisableThreadLibraryCalls(hModule);\n    return TRUE;\n}\n",[69,26852,26853,26859,26865,26869,26876,26882,26888,26892,26897,26902,26915,26919,26938,26955,26959,26973,26977,26981,27017,27021,27046,27050,27064,27068,27085,27097,27106,27112,27116,27120,27140,27144,27154,27160,27177,27181,27202,27209,27215,27219,27231,27237,27241,27245,27276,27280,27287,27294,27305,27313,27324,27332,27339,27343,27347,27363,27367,27374,27381,27385,27392,27398,27402,27406,27410,27421,27425,27432,27440,27444,27448,27476,27480,27502,27508,27512,27538,27549,27555,27559,27574,27583,27589,27593,27597,27606,27610,27630,27634,27638,27652,27656,27668,27676,27683],{"__ignoreMap":154},[599,26854,26855,26857],{"class":601,"line":602},[599,26856,616],{"class":605},[599,26858,620],{"class":619},[599,26860,26861,26863],{"class":601,"line":613},[599,26862,616],{"class":605},[599,26864,11548],{"class":619},[599,26866,26867],{"class":601,"line":623},[599,26868,651],{"emptyLinePlaceholder":650},[599,26870,26871,26873],{"class":601,"line":631},[599,26872,616],{"class":605},[599,26874,26875],{"class":619}," \u003Cinitguid.h>\n",[599,26877,26878,26880],{"class":601,"line":639},[599,26879,616],{"class":605},[599,26881,11530],{"class":619},[599,26883,26884,26886],{"class":601,"line":647},[599,26885,616],{"class":605},[599,26887,11523],{"class":619},[599,26889,26890],{"class":601,"line":654},[599,26891,651],{"emptyLinePlaceholder":650},[599,26893,26894],{"class":601,"line":663},[599,26895,26896],{"class":772},"\u002F\u002F Number of live objects. LogonUI calls DllCanUnloadNow from time to time and\n",[599,26898,26899],{"class":601,"line":670},[599,26900,26901],{"class":772},"\u002F\u002F must not unload the DLL while a provider, credential or filter still exists.\n",[599,26903,26904,26906,26909,26911,26913],{"class":601,"line":728},[599,26905,8856],{"class":605},[599,26907,26908],{"class":666}," LONG g_cRef ",[599,26910,1060],{"class":605},[599,26912,1286],{"class":949},[599,26914,1066],{"class":666},[599,26916,26917],{"class":601,"line":764},[599,26918,651],{"emptyLinePlaceholder":650},[599,26920,26921,26923,26925,26928,26931,26933,26935],{"class":601,"line":769},[599,26922,11860],{"class":605},[599,26924,26787],{"class":609},[599,26926,26927],{"class":666},"()  { ",[599,26929,26930],{"class":609},"InterlockedIncrement",[599,26932,679],{"class":666},[599,26934,694],{"class":605},[599,26936,26937],{"class":666},"g_cRef); }\n",[599,26939,26940,26942,26944,26946,26949,26951,26953],{"class":601,"line":776},[599,26941,11860],{"class":605},[599,26943,26796],{"class":609},[599,26945,13968],{"class":666},[599,26947,26948],{"class":609},"InterlockedDecrement",[599,26950,679],{"class":666},[599,26952,694],{"class":605},[599,26954,26937],{"class":666},[599,26956,26957],{"class":601,"line":816},[599,26958,651],{"emptyLinePlaceholder":650},[599,26960,26961,26963,26966,26968,26970],{"class":601,"line":843},[599,26962,10951],{"class":605},[599,26964,26965],{"class":609}," CClassFactory",[599,26967,10957],{"class":666},[599,26969,10960],{"class":605},[599,26971,26972],{"class":609}," IClassFactory\n",[599,26974,26975],{"class":601,"line":848},[599,26976,667],{"class":666},[599,26978,26979],{"class":601,"line":854},[599,26980,10982],{"class":605},[599,26982,26983,26986,26988,26990,26993,26996,26999,27001,27003,27005,27007,27010,27013,27015],{"class":601,"line":860},[599,26984,26985],{"class":605},"    explicit",[599,26987,26965],{"class":609},[599,26989,679],{"class":666},[599,26991,26992],{"class":609},"REFCLSID",[599,26994,26995],{"class":697}," rclsid",[599,26997,26998],{"class":666},") : ",[599,27000,11691],{"class":609},[599,27002,679],{"class":666},[599,27004,1217],{"class":949},[599,27006,101],{"class":666},[599,27008,27009],{"class":609},"_clsid",[599,27011,27012],{"class":666},"(rclsid) { ",[599,27014,23195],{"class":609},[599,27016,23198],{"class":666},[599,27018,27019],{"class":601,"line":866},[599,27020,651],{"emptyLinePlaceholder":650},[599,27022,27023,27025,27027,27029,27031,27033,27035,27037,27039,27041,27043],{"class":601,"line":912},[599,27024,11003],{"class":609},[599,27026,679],{"class":666},[599,27028,1924],{"class":609},[599,27030,1124],{"class":666},[599,27032,11012],{"class":609},[599,27034,13968],{"class":666},[599,27036,1127],{"class":605},[599,27038,11969],{"class":609},[599,27040,679],{"class":666},[599,27042,694],{"class":605},[599,27044,27045],{"class":666},"_cRef); }\n",[599,27047,27048],{"class":601,"line":938},[599,27049,651],{"emptyLinePlaceholder":650},[599,27051,27052,27054,27056,27058,27060,27062],{"class":601,"line":978},[599,27053,11003],{"class":609},[599,27055,679],{"class":666},[599,27057,1924],{"class":609},[599,27059,1124],{"class":666},[599,27061,11027],{"class":609},[599,27063,3717],{"class":666},[599,27065,27066],{"class":601,"line":1316},[599,27067,1095],{"class":666},[599,27069,27070,27073,27075,27077,27079,27081,27083],{"class":601,"line":1321},[599,27071,27072],{"class":609},"        LONG",[599,27074,12009],{"class":666},[599,27076,1060],{"class":605},[599,27078,12014],{"class":609},[599,27080,679],{"class":666},[599,27082,694],{"class":605},[599,27084,11976],{"class":666},[599,27086,27087,27089,27091,27093,27095],{"class":601,"line":1335},[599,27088,1100],{"class":605},[599,27090,12027],{"class":666},[599,27092,1349],{"class":605},[599,27094,1286],{"class":949},[599,27096,1029],{"class":666},[599,27098,27099,27102,27104],{"class":601,"line":1341},[599,27100,27101],{"class":605},"            delete",[599,27103,12041],{"class":949},[599,27105,1066],{"class":666},[599,27107,27108,27110],{"class":601,"line":1367},[599,27109,1211],{"class":605},[599,27111,12050],{"class":666},[599,27113,27114],{"class":601,"line":1375},[599,27115,1224],{"class":666},[599,27117,27118],{"class":601,"line":1391},[599,27119,651],{"emptyLinePlaceholder":650},[599,27121,27122,27124,27126,27128,27130,27132,27134,27136,27138],{"class":601,"line":1405},[599,27123,11034],{"class":609},[599,27125,11037],{"class":609},[599,27127,679],{"class":666},[599,27129,11042],{"class":609},[599,27131,11045],{"class":697},[599,27133,212],{"class":666},[599,27135,11050],{"class":605},[599,27137,11053],{"class":697},[599,27139,1029],{"class":666},[599,27141,27142],{"class":601,"line":1416},[599,27143,1095],{"class":666},[599,27145,27146,27148,27150,27152],{"class":601,"line":1421},[599,27147,1100],{"class":605},[599,27149,1327],{"class":666},[599,27151,2435],{"class":605},[599,27153,12099],{"class":666},[599,27155,27156,27158],{"class":601,"line":1449},[599,27157,2040],{"class":605},[599,27159,12106],{"class":666},[599,27161,27162,27164,27166,27168,27170,27172,27174],{"class":601,"line":1462},[599,27163,1100],{"class":605},[599,27165,1327],{"class":666},[599,27167,12115],{"class":609},[599,27169,12118],{"class":666},[599,27171,6568],{"class":605},[599,27173,12123],{"class":609},[599,27175,27176],{"class":666},"(riid, IID_IClassFactory))\n",[599,27178,27179],{"class":601,"line":1477},[599,27180,1338],{"class":666},[599,27182,27183,27185,27187,27189,27191,27194,27196,27198,27200],{"class":601,"line":1483},[599,27184,20151],{"class":605},[599,27186,12144],{"class":666},[599,27188,1060],{"class":605},[599,27190,2374],{"class":605},[599,27192,27193],{"class":666},"IClassFactory",[599,27195,5897],{"class":605},[599,27197,679],{"class":666},[599,27199,8593],{"class":949},[599,27201,725],{"class":666},[599,27203,27204,27207],{"class":601,"line":1496},[599,27205,27206],{"class":609},"            AddRef",[599,27208,1313],{"class":666},[599,27210,27211,27213],{"class":601,"line":1523},[599,27212,2040],{"class":605},[599,27214,12172],{"class":666},[599,27216,27217],{"class":601,"line":1555},[599,27218,1564],{"class":666},[599,27220,27221,27223,27225,27227,27229],{"class":601,"line":1561},[599,27222,12141],{"class":605},[599,27224,12144],{"class":666},[599,27226,1060],{"class":605},[599,27228,1962],{"class":949},[599,27230,1066],{"class":666},[599,27232,27233,27235],{"class":601,"line":1567},[599,27234,1211],{"class":605},[599,27236,12251],{"class":666},[599,27238,27239],{"class":601,"line":1577},[599,27240,1224],{"class":666},[599,27242,27243],{"class":601,"line":1582},[599,27244,651],{"emptyLinePlaceholder":650},[599,27246,27247,27249,27252,27254,27257,27259,27262,27264,27266,27268,27270,27272,27274],{"class":601,"line":1587},[599,27248,11034],{"class":609},[599,27250,27251],{"class":609}," CreateInstance",[599,27253,679],{"class":666},[599,27255,27256],{"class":609},"IUnknown",[599,27258,748],{"class":605},[599,27260,27261],{"class":697}," pUnkOuter",[599,27263,212],{"class":666},[599,27265,11042],{"class":609},[599,27267,11045],{"class":697},[599,27269,212],{"class":666},[599,27271,11050],{"class":605},[599,27273,11053],{"class":697},[599,27275,1029],{"class":666},[599,27277,27278],{"class":601,"line":1616},[599,27279,1095],{"class":666},[599,27281,27282,27284],{"class":601,"line":1621},[599,27283,1100],{"class":605},[599,27285,27286],{"class":666}," (pUnkOuter)\n",[599,27288,27289,27291],{"class":601,"line":1634},[599,27290,2040],{"class":605},[599,27292,27293],{"class":666}," CLASS_E_NOAGGREGATION;\n",[599,27295,27296,27298,27300,27302],{"class":601,"line":1647},[599,27297,1100],{"class":605},[599,27299,1327],{"class":666},[599,27301,13376],{"class":609},[599,27303,27304],{"class":666},"(_clsid, CLSID_CTacProvider))\n",[599,27306,27307,27309,27311],{"class":601,"line":1660},[599,27308,2040],{"class":605},[599,27310,11292],{"class":609},[599,27312,14537],{"class":666},[599,27314,27315,27317,27319,27321],{"class":601,"line":1665},[599,27316,1100],{"class":605},[599,27318,1327],{"class":666},[599,27320,13376],{"class":609},[599,27322,27323],{"class":666},"(_clsid, CLSID_CTacFilter))\n",[599,27325,27326,27328,27330],{"class":601,"line":1695},[599,27327,2040],{"class":605},[599,27329,23350],{"class":609},[599,27331,14537],{"class":666},[599,27333,27334,27336],{"class":601,"line":1700},[599,27335,1211],{"class":605},[599,27337,27338],{"class":666}," CLASS_E_CLASSNOTAVAILABLE;\n",[599,27340,27341],{"class":601,"line":1720},[599,27342,1224],{"class":666},[599,27344,27345],{"class":601,"line":1731},[599,27346,651],{"emptyLinePlaceholder":650},[599,27348,27349,27351,27354,27356,27358,27361],{"class":601,"line":1745},[599,27350,11034],{"class":609},[599,27352,27353],{"class":609}," LockServer",[599,27355,679],{"class":666},[599,27357,11218],{"class":609},[599,27359,27360],{"class":697}," fLock",[599,27362,1029],{"class":666},[599,27364,27365],{"class":601,"line":1750},[599,27366,1095],{"class":666},[599,27368,27369,27371],{"class":601,"line":1761},[599,27370,1100],{"class":605},[599,27372,27373],{"class":666}," (fLock)\n",[599,27375,27376,27379],{"class":601,"line":1787},[599,27377,27378],{"class":609},"            DllAddRef",[599,27380,1313],{"class":666},[599,27382,27383],{"class":601,"line":1792},[599,27384,9143],{"class":605},[599,27386,27387,27390],{"class":601,"line":1815},[599,27388,27389],{"class":609},"            DllRelease",[599,27391,1313],{"class":666},[599,27393,27394,27396],{"class":601,"line":1820},[599,27395,1211],{"class":605},[599,27397,12172],{"class":666},[599,27399,27400],{"class":601,"line":1833},[599,27401,1224],{"class":666},[599,27403,27404],{"class":601,"line":1863},[599,27405,651],{"emptyLinePlaceholder":650},[599,27407,27408],{"class":601,"line":1870},[599,27409,11315],{"class":605},[599,27411,27412,27415,27417,27419],{"class":601,"line":1875},[599,27413,27414],{"class":609},"    ~CClassFactory",[599,27416,13968],{"class":666},[599,27418,23384],{"class":609},[599,27420,23198],{"class":666},[599,27422,27423],{"class":601,"line":1880},[599,27424,651],{"emptyLinePlaceholder":650},[599,27426,27427,27429],{"class":601,"line":1946},[599,27428,11389],{"class":609},[599,27430,27431],{"class":666},"  _cRef;\n",[599,27433,27434,27437],{"class":601,"line":1951},[599,27435,27436],{"class":609},"    CLSID",[599,27438,27439],{"class":666}," _clsid;\n",[599,27441,27442],{"class":601,"line":1967},[599,27443,10612],{"class":666},[599,27445,27446],{"class":601,"line":1982},[599,27447,651],{"emptyLinePlaceholder":650},[599,27449,27450,27453,27456,27458,27460,27462,27464,27466,27468,27470,27472,27474],{"class":601,"line":1997},[599,27451,27452],{"class":609},"STDAPI",[599,27454,27455],{"class":609}," DllGetClassObject",[599,27457,679],{"class":666},[599,27459,26992],{"class":609},[599,27461,26995],{"class":697},[599,27463,212],{"class":666},[599,27465,11042],{"class":609},[599,27467,11045],{"class":697},[599,27469,212],{"class":666},[599,27471,11050],{"class":605},[599,27473,11053],{"class":697},[599,27475,1029],{"class":666},[599,27477,27478],{"class":601,"line":2002},[599,27479,667],{"class":666},[599,27481,27482,27484,27486,27488,27490,27493,27495,27497,27499],{"class":601,"line":2024},[599,27483,3514],{"class":605},[599,27485,1327],{"class":666},[599,27487,2435],{"class":605},[599,27489,13376],{"class":609},[599,27491,27492],{"class":666},"(rclsid, CLSID_CTacProvider) ",[599,27494,3154],{"class":605},[599,27496,9609],{"class":605},[599,27498,13376],{"class":609},[599,27500,27501],{"class":666},"(rclsid, CLSID_CTacFilter))\n",[599,27503,27504,27506],{"class":601,"line":2037},[599,27505,1211],{"class":605},[599,27507,27338],{"class":666},[599,27509,27510],{"class":601,"line":2047},[599,27511,651],{"emptyLinePlaceholder":650},[599,27513,27514,27517,27519,27522,27524,27526,27528,27530,27532,27535],{"class":601,"line":2052},[599,27515,27516],{"class":609},"    CClassFactory",[599,27518,748],{"class":605},[599,27520,27521],{"class":666}," pcf ",[599,27523,1060],{"class":605},[599,27525,12663],{"class":605},[599,27527,1327],{"class":666},[599,27529,703],{"class":609},[599,27531,12670],{"class":666},[599,27533,27534],{"class":609},"CClassFactory",[599,27536,27537],{"class":666},"(rclsid);\n",[599,27539,27540,27542,27544,27546],{"class":601,"line":2096},[599,27541,3514],{"class":605},[599,27543,1327],{"class":666},[599,27545,2435],{"class":605},[599,27547,27548],{"class":666},"pcf)\n",[599,27550,27551,27553],{"class":601,"line":2124},[599,27552,1211],{"class":605},[599,27554,12692],{"class":666},[599,27556,27557],{"class":601,"line":2129},[599,27558,651],{"emptyLinePlaceholder":650},[599,27560,27561,27563,27565,27567,27570,27572],{"class":601,"line":2163},[599,27562,11344],{"class":609},[599,27564,12703],{"class":666},[599,27566,1060],{"class":605},[599,27568,27569],{"class":666}," pcf->",[599,27571,12070],{"class":609},[599,27573,14537],{"class":666},[599,27575,27576,27579,27581],{"class":601,"line":2186},[599,27577,27578],{"class":666},"    pcf->",[599,27580,11027],{"class":609},[599,27582,1313],{"class":666},[599,27584,27585,27587],{"class":601,"line":2195},[599,27586,3551],{"class":605},[599,27588,12751],{"class":666},[599,27590,27591],{"class":601,"line":2200},[599,27592,981],{"class":666},[599,27594,27595],{"class":601,"line":2212},[599,27596,651],{"emptyLinePlaceholder":650},[599,27598,27599,27601,27604],{"class":601,"line":2220},[599,27600,27452],{"class":609},[599,27602,27603],{"class":609}," DllCanUnloadNow",[599,27605,3717],{"class":666},[599,27607,27608],{"class":601,"line":2225},[599,27609,667],{"class":666},[599,27611,27612,27614,27617,27619,27621,27623,27626,27628],{"class":601,"line":2230},[599,27613,3551],{"class":605},[599,27615,27616],{"class":666}," g_cRef ",[599,27618,1349],{"class":605},[599,27620,1286],{"class":949},[599,27622,8953],{"class":605},[599,27624,27625],{"class":666}," S_OK ",[599,27627,590],{"class":605},[599,27629,18417],{"class":666},[599,27631,27632],{"class":601,"line":2265},[599,27633,981],{"class":666},[599,27635,27636],{"class":601,"line":2286},[599,27637,651],{"emptyLinePlaceholder":650},[599,27639,27640,27643,27646,27649],{"class":601,"line":2291},[599,27641,27642],{"class":666},"BOOL ",[599,27644,27645],{"class":609},"APIENTRY",[599,27647,27648],{"class":609}," DllMain",[599,27650,27651],{"class":666},"(HMODULE hModule, DWORD dwReason, LPVOID)\n",[599,27653,27654],{"class":601,"line":2297},[599,27655,667],{"class":666},[599,27657,27658,27660,27663,27665],{"class":601,"line":2317},[599,27659,3514],{"class":605},[599,27661,27662],{"class":666}," (dwReason ",[599,27664,1349],{"class":605},[599,27666,27667],{"class":666}," DLL_PROCESS_ATTACH)\n",[599,27669,27670,27673],{"class":601,"line":2331},[599,27671,27672],{"class":609},"        DisableThreadLibraryCalls",[599,27674,27675],{"class":666},"(hModule);\n",[599,27677,27678,27680],{"class":601,"line":2361},[599,27679,3551],{"class":605},[599,27681,27682],{"class":666}," TRUE;\n",[599,27684,27685],{"class":601,"line":2366},[599,27686,981],{"class":666},[15,27688,27689,590],{},[69,27690,510],{},[148,27692,27695],{"className":27693,"code":27694,"language":153,"meta":154},[151],"LIBRARY   TacProvider\nEXPORTS\n    DllGetClassObject   PRIVATE\n    DllCanUnloadNow     PRIVATE\n",[69,27696,27694],{"__ignoreMap":154},[15,27698,27699,27700,27703,27704,27707],{},"A word about the GUIDs. They are the CLSIDs of the provider and the filter. Windows uses them to find the COM class in the registry: LogonUI reads ",[69,27701,27702],{},"...\\Credential Providers\\{GUID}"," and loads the DLL from ",[69,27705,27706],{},"HKCR\\CLSID\\{GUID}",". The GUID is not a secret, it is just a name.",[15,27709,27710],{},"A problem only happens if two different DLLs register the same CLSID on the same machine. Then the second registration overwrites the first one and Windows only loads one of them. For example, if you copy this code, change it and install it on a machine where another version with the same GUIDs is already running.",[15,27712,27713,27714,27716,27717,27719,27720,27723],{},"For a test in your own VM you can keep the GUIDs from this article. If you want to use the code for something real, or run two versions side by side, create your own. You don't have to do this by hand. ",[69,27715,533],{}," creates two new GUIDs and writes them into ",[69,27718,507],{}," and all ",[69,27721,27722],{},".reg"," files:",[148,27725,27727],{"className":23014,"code":27726,"language":23016,"meta":154,"style":154},"# Creates new CLSIDs for the provider and the filter and writes them into\n# guid.h and all .reg files in this folder.\n#\n# Run it once in the project folder, then rebuild with build.bat.\n# If an older version is still registered, run unregister.reg BEFORE this\n# script. A copy with the old GUIDs is kept as unregister-old.reg anyway.\n\n$ErrorActionPreference = 'Stop'\n$root     = $PSScriptRoot\n$guidFile = Join-Path $root 'guid.h'\n$regFiles = Get-ChildItem -Path $root -Filter '*.reg' | Where-Object { $_.Name -ne 'unregister-old.reg' }\n\n# The first two {...} in guid.h are the current provider and filter GUIDs.\n$found = [regex]::Matches((Get-Content $guidFile -Raw), '\\{([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})\\}')\nif ($found.Count -lt 2) { throw 'Could not find the current GUIDs in guid.h.' }\n$oldProvider = $found[0].Groups[1].Value.ToUpper()\n$oldFilter   = $found[1].Groups[1].Value.ToUpper()\n\n$newProvider = [guid]::NewGuid().ToString().ToUpper()\n$newFilter   = [guid]::NewGuid().ToString().ToUpper()\n\n# {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01} becomes\n# 0xb1e7c9a0, 0x2f4d, 0x4c6b, 0x9a, 0x11, 0x00, 0x00, 0xc0, 0xff, 0xee, 0x01\nfunction Get-DefineGuid([string]$name, [string]$guid)\n{\n    $hex   = $guid.Replace('-', '').ToLower()\n    $bytes = @()\n    for ($i = 16; $i -lt 32; $i += 2) { $bytes += '0x' + $hex.Substring($i, 2) }\n    $parts = @('0x' + $hex.Substring(0, 8), '0x' + $hex.Substring(8, 4), '0x' + $hex.Substring(12, 4)) + $bytes\n    return \"DEFINE_GUID($name,`r`n    \" + ($parts -join ', ') + ');'\n}\n\n# Keep an unregister file with the old GUIDs, in case they are still registered.\n$unregister = Join-Path $root 'unregister.reg'\nif (Test-Path $unregister) { Copy-Item $unregister (Join-Path $root 'unregister-old.reg') -Force }\n\n$lines = @(\n    '#pragma once'\n    '#include \u003Cguiddef.h>'\n    ''\n    '\u002F\u002F Created by new-guids.ps1. Keep them in sync with the .reg files.'\n    '\u002F\u002F dll.cpp includes initguid.h before this header, so the GUIDs are defined'\n    '\u002F\u002F there and only declared everywhere else.'\n    ''\n    \"\u002F\u002F {$newProvider}\"\n    (Get-DefineGuid 'CLSID_CTacProvider' $newProvider)\n    ''\n    \"\u002F\u002F {$newFilter}\"\n    (Get-DefineGuid 'CLSID_CTacFilter' $newFilter)\n)\nSet-Content -Path $guidFile -Value ($lines -join \"`r`n\") -Encoding Ascii\n\nforeach ($file in $regFiles)\n{\n    $text = Get-Content $file.FullName -Raw\n    $text = $text -ireplace [regex]::Escape($oldProvider), $newProvider\n    $text = $text -ireplace [regex]::Escape($oldFilter),   $newFilter\n    Set-Content -Path $file.FullName -Value $text -Encoding Ascii -NoNewline\n}\n\nWrite-Host ''\nWrite-Host \"Provider: {$oldProvider} -> {$newProvider}\"\nWrite-Host \"Filter:   {$oldFilter} -> {$newFilter}\"\nWrite-Host ''\nWrite-Host 'Updated guid.h and:' ($regFiles.Name -join ', ')\nWrite-Host 'Now rebuild with build.bat and register again.'\n",[69,27728,27729,27734,27739,27744,27749,27754,27759,27763,27773,27783,27799,27845,27849,27854,27888,27911,27931,27948,27952,27967,27980,27984,27989,27994,28019,28023,28044,28056,28101,28166,28202,28206,28210,28215,28229,28262,28266,28277,28282,28287,28292,28297,28302,28307,28311,28322,28336,28340,28349,28361,28365,28396,28400,28413,28417,28435,28459,28481,28506,28510,28514,28522,28539,28555,28561,28577],{"__ignoreMap":154},[599,27730,27731],{"class":601,"line":602},[599,27732,27733],{"class":772},"# Creates new CLSIDs for the provider and the filter and writes them into\n",[599,27735,27736],{"class":601,"line":613},[599,27737,27738],{"class":772},"# guid.h and all .reg files in this folder.\n",[599,27740,27741],{"class":601,"line":623},[599,27742,27743],{"class":772},"#\n",[599,27745,27746],{"class":601,"line":631},[599,27747,27748],{"class":772},"# Run it once in the project folder, then rebuild with build.bat.\n",[599,27750,27751],{"class":601,"line":639},[599,27752,27753],{"class":772},"# If an older version is still registered, run unregister.reg BEFORE this\n",[599,27755,27756],{"class":601,"line":647},[599,27757,27758],{"class":772},"# script. A copy with the old GUIDs is kept as unregister-old.reg anyway.\n",[599,27760,27761],{"class":601,"line":654},[599,27762,651],{"emptyLinePlaceholder":650},[599,27764,27765,27768,27770],{"class":601,"line":663},[599,27766,27767],{"class":949},"$ErrorActionPreference",[599,27769,946],{"class":605},[599,27771,27772],{"class":619}," 'Stop'\n",[599,27774,27775,27778,27780],{"class":601,"line":670},[599,27776,27777],{"class":666},"$root     ",[599,27779,1060],{"class":605},[599,27781,27782],{"class":949}," $PSScriptRoot\n",[599,27784,27785,27788,27790,27793,27796],{"class":601,"line":728},[599,27786,27787],{"class":666},"$guidFile ",[599,27789,1060],{"class":605},[599,27791,27792],{"class":949}," Join-Path",[599,27794,27795],{"class":666}," $root ",[599,27797,27798],{"class":619},"'guid.h'\n",[599,27800,27801,27804,27806,27809,27811,27814,27816,27819,27822,27825,27828,27830,27833,27836,27839,27842],{"class":601,"line":764},[599,27802,27803],{"class":666},"$regFiles ",[599,27805,1060],{"class":605},[599,27807,27808],{"class":949}," Get-ChildItem",[599,27810,1214],{"class":605},[599,27812,27813],{"class":666},"Path $root ",[599,27815,1132],{"class":605},[599,27817,27818],{"class":666},"Filter ",[599,27820,27821],{"class":619},"'*.reg'",[599,27823,27824],{"class":605}," |",[599,27826,27827],{"class":949}," Where-Object",[599,27829,5873],{"class":666},[599,27831,27832],{"class":949},"$_",[599,27834,27835],{"class":666},".Name ",[599,27837,27838],{"class":605},"-ne",[599,27840,27841],{"class":619}," 'unregister-old.reg'",[599,27843,27844],{"class":666}," }\n",[599,27846,27847],{"class":601,"line":769},[599,27848,651],{"emptyLinePlaceholder":650},[599,27850,27851],{"class":601,"line":776},[599,27852,27853],{"class":772},"# The first two {...} in guid.h are the current provider and filter GUIDs.\n",[599,27855,27856,27859,27861,27864,27867,27870,27873,27876,27878,27881,27883,27886],{"class":601,"line":816},[599,27857,27858],{"class":666},"$found ",[599,27860,1060],{"class":605},[599,27862,27863],{"class":666}," [",[599,27865,27866],{"class":605},"regex",[599,27868,27869],{"class":666},"]::Matches((",[599,27871,27872],{"class":949},"Get-Content",[599,27874,27875],{"class":666}," $guidFile ",[599,27877,1132],{"class":605},[599,27879,27880],{"class":666},"Raw)",[599,27882,10558],{"class":605},[599,27884,27885],{"class":619}," '\\{([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})\\}'",[599,27887,1029],{"class":666},[599,27889,27890,27893,27896,27899,27901,27903,27906,27909],{"class":601,"line":843},[599,27891,27892],{"class":605},"if",[599,27894,27895],{"class":666}," ($found.Count ",[599,27897,27898],{"class":605},"-lt",[599,27900,2576],{"class":949},[599,27902,13949],{"class":666},[599,27904,27905],{"class":605},"throw",[599,27907,27908],{"class":619}," 'Could not find the current GUIDs in guid.h.'",[599,27910,27844],{"class":666},[599,27912,27913,27916,27918,27921,27923,27926,27928],{"class":601,"line":848},[599,27914,27915],{"class":666},"$oldProvider ",[599,27917,1060],{"class":605},[599,27919,27920],{"class":666}," $found[",[599,27922,2074],{"class":949},[599,27924,27925],{"class":666},"].Groups[",[599,27927,1217],{"class":949},[599,27929,27930],{"class":666},"].Value.ToUpper()\n",[599,27932,27933,27936,27938,27940,27942,27944,27946],{"class":601,"line":854},[599,27934,27935],{"class":666},"$oldFilter   ",[599,27937,1060],{"class":605},[599,27939,27920],{"class":666},[599,27941,1217],{"class":949},[599,27943,27925],{"class":666},[599,27945,1217],{"class":949},[599,27947,27930],{"class":666},[599,27949,27950],{"class":601,"line":860},[599,27951,651],{"emptyLinePlaceholder":650},[599,27953,27954,27957,27959,27961,27964],{"class":601,"line":866},[599,27955,27956],{"class":666},"$newProvider ",[599,27958,1060],{"class":605},[599,27960,27863],{"class":666},[599,27962,27963],{"class":605},"guid",[599,27965,27966],{"class":666},"]::NewGuid().ToString().ToUpper()\n",[599,27968,27969,27972,27974,27976,27978],{"class":601,"line":912},[599,27970,27971],{"class":666},"$newFilter   ",[599,27973,1060],{"class":605},[599,27975,27863],{"class":666},[599,27977,27963],{"class":605},[599,27979,27966],{"class":666},[599,27981,27982],{"class":601,"line":938},[599,27983,651],{"emptyLinePlaceholder":650},[599,27985,27986],{"class":601,"line":978},[599,27987,27988],{"class":772},"# {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01} becomes\n",[599,27990,27991],{"class":601,"line":1316},[599,27992,27993],{"class":772},"# 0xb1e7c9a0, 0x2f4d, 0x4c6b, 0x9a, 0x11, 0x00, 0x00, 0xc0, 0xff, 0xee, 0x01\n",[599,27995,27996,27999,28002,28005,28007,28010,28012,28014,28016],{"class":601,"line":1321},[599,27997,27998],{"class":605},"function",[599,28000,28001],{"class":609}," Get-DefineGuid",[599,28003,28004],{"class":666},"([",[599,28006,691],{"class":605},[599,28008,28009],{"class":666},"]$name",[599,28011,10558],{"class":605},[599,28013,27863],{"class":666},[599,28015,691],{"class":605},[599,28017,28018],{"class":666},"]$guid)\n",[599,28020,28021],{"class":601,"line":1335},[599,28022,667],{"class":666},[599,28024,28025,28028,28030,28033,28036,28038,28041],{"class":601,"line":1341},[599,28026,28027],{"class":666},"    $hex   ",[599,28029,1060],{"class":605},[599,28031,28032],{"class":666}," $guid.Replace(",[599,28034,28035],{"class":619},"'-'",[599,28037,10558],{"class":605},[599,28039,28040],{"class":619}," ''",[599,28042,28043],{"class":666},").ToLower()\n",[599,28045,28046,28049,28051,28054],{"class":601,"line":1367},[599,28047,28048],{"class":666},"    $bytes ",[599,28050,1060],{"class":605},[599,28052,28053],{"class":605}," @",[599,28055,3717],{"class":666},[599,28057,28058,28060,28063,28065,28067,28070,28072,28075,28077,28079,28081,28084,28086,28089,28091,28094,28096,28098],{"class":601,"line":1375},[599,28059,3407],{"class":605},[599,28061,28062],{"class":666}," ($i ",[599,28064,1060],{"class":605},[599,28066,2562],{"class":949},[599,28068,28069],{"class":666},"; $i ",[599,28071,27898],{"class":605},[599,28073,28074],{"class":949}," 32",[599,28076,28069],{"class":666},[599,28078,1455],{"class":605},[599,28080,2576],{"class":949},[599,28082,28083],{"class":666},") { $bytes ",[599,28085,1455],{"class":605},[599,28087,28088],{"class":619}," '0x'",[599,28090,1201],{"class":605},[599,28092,28093],{"class":666}," $hex.Substring($i",[599,28095,10558],{"class":605},[599,28097,2576],{"class":949},[599,28099,28100],{"class":666},") }\n",[599,28102,28103,28106,28108,28110,28112,28115,28117,28120,28122,28124,28126,28128,28130,28132,28134,28136,28138,28140,28142,28144,28146,28148,28150,28152,28155,28157,28159,28161,28163],{"class":601,"line":1391},[599,28104,28105],{"class":666},"    $parts ",[599,28107,1060],{"class":605},[599,28109,28053],{"class":605},[599,28111,679],{"class":666},[599,28113,28114],{"class":619},"'0x'",[599,28116,1201],{"class":605},[599,28118,28119],{"class":666}," $hex.Substring(",[599,28121,2074],{"class":949},[599,28123,10558],{"class":605},[599,28125,1472],{"class":949},[599,28127,487],{"class":666},[599,28129,10558],{"class":605},[599,28131,28088],{"class":619},[599,28133,1201],{"class":605},[599,28135,28119],{"class":666},[599,28137,2326],{"class":949},[599,28139,10558],{"class":605},[599,28141,6716],{"class":949},[599,28143,487],{"class":666},[599,28145,10558],{"class":605},[599,28147,28088],{"class":619},[599,28149,1201],{"class":605},[599,28151,28119],{"class":666},[599,28153,28154],{"class":949},"12",[599,28156,10558],{"class":605},[599,28158,6716],{"class":949},[599,28160,18798],{"class":666},[599,28162,2543],{"class":605},[599,28164,28165],{"class":666}," $bytes\n",[599,28167,28168,28170,28173,28176,28178,28181,28184,28186,28189,28192,28195,28197,28199],{"class":601,"line":1405},[599,28169,3551],{"class":605},[599,28171,28172],{"class":619}," \"DEFINE_GUID(",[599,28174,28175],{"class":666},"$name",[599,28177,10558],{"class":619},[599,28179,28180],{"class":949},"`r`n",[599,28182,28183],{"class":619},"    \"",[599,28185,1201],{"class":605},[599,28187,28188],{"class":666}," ($parts ",[599,28190,28191],{"class":605},"-join",[599,28193,28194],{"class":619}," ', '",[599,28196,1124],{"class":666},[599,28198,2543],{"class":605},[599,28200,28201],{"class":619}," ');'\n",[599,28203,28204],{"class":601,"line":1416},[599,28205,981],{"class":666},[599,28207,28208],{"class":601,"line":1421},[599,28209,651],{"emptyLinePlaceholder":650},[599,28211,28212],{"class":601,"line":1449},[599,28213,28214],{"class":772},"# Keep an unregister file with the old GUIDs, in case they are still registered.\n",[599,28216,28217,28220,28222,28224,28226],{"class":601,"line":1462},[599,28218,28219],{"class":666},"$unregister ",[599,28221,1060],{"class":605},[599,28223,27792],{"class":949},[599,28225,27795],{"class":666},[599,28227,28228],{"class":619},"'unregister.reg'\n",[599,28230,28231,28233,28235,28238,28241,28244,28247,28250,28252,28255,28257,28259],{"class":601,"line":1477},[599,28232,27892],{"class":605},[599,28234,1327],{"class":666},[599,28236,28237],{"class":949},"Test-Path",[599,28239,28240],{"class":666}," $unregister) { ",[599,28242,28243],{"class":949},"Copy-Item",[599,28245,28246],{"class":666}," $unregister (",[599,28248,28249],{"class":949},"Join-Path",[599,28251,27795],{"class":666},[599,28253,28254],{"class":619},"'unregister-old.reg'",[599,28256,1124],{"class":666},[599,28258,1132],{"class":605},[599,28260,28261],{"class":666},"Force }\n",[599,28263,28264],{"class":601,"line":1483},[599,28265,651],{"emptyLinePlaceholder":650},[599,28267,28268,28271,28273,28275],{"class":601,"line":1496},[599,28269,28270],{"class":666},"$lines ",[599,28272,1060],{"class":605},[599,28274,28053],{"class":605},[599,28276,13310],{"class":666},[599,28278,28279],{"class":601,"line":1523},[599,28280,28281],{"class":619},"    '#pragma once'\n",[599,28283,28284],{"class":601,"line":1555},[599,28285,28286],{"class":619},"    '#include \u003Cguiddef.h>'\n",[599,28288,28289],{"class":601,"line":1561},[599,28290,28291],{"class":619},"    ''\n",[599,28293,28294],{"class":601,"line":1567},[599,28295,28296],{"class":619},"    '\u002F\u002F Created by new-guids.ps1. Keep them in sync with the .reg files.'\n",[599,28298,28299],{"class":601,"line":1577},[599,28300,28301],{"class":619},"    '\u002F\u002F dll.cpp includes initguid.h before this header, so the GUIDs are defined'\n",[599,28303,28304],{"class":601,"line":1582},[599,28305,28306],{"class":619},"    '\u002F\u002F there and only declared everywhere else.'\n",[599,28308,28309],{"class":601,"line":1587},[599,28310,28291],{"class":619},[599,28312,28313,28316,28319],{"class":601,"line":1616},[599,28314,28315],{"class":619},"    \"\u002F\u002F {",[599,28317,28318],{"class":666},"$newProvider",[599,28320,28321],{"class":619},"}\"\n",[599,28323,28324,28327,28330,28333],{"class":601,"line":1621},[599,28325,28326],{"class":666},"    (",[599,28328,28329],{"class":949},"Get-DefineGuid",[599,28331,28332],{"class":619}," 'CLSID_CTacProvider'",[599,28334,28335],{"class":666}," $newProvider)\n",[599,28337,28338],{"class":601,"line":1634},[599,28339,28291],{"class":619},[599,28341,28342,28344,28347],{"class":601,"line":1647},[599,28343,28315],{"class":619},[599,28345,28346],{"class":666},"$newFilter",[599,28348,28321],{"class":619},[599,28350,28351,28353,28355,28358],{"class":601,"line":1660},[599,28352,28326],{"class":666},[599,28354,28329],{"class":949},[599,28356,28357],{"class":619}," 'CLSID_CTacFilter'",[599,28359,28360],{"class":666}," $newFilter)\n",[599,28362,28363],{"class":601,"line":1665},[599,28364,1029],{"class":666},[599,28366,28367,28370,28372,28375,28377,28380,28382,28385,28387,28389,28391,28393],{"class":601,"line":1695},[599,28368,28369],{"class":949},"Set-Content",[599,28371,1214],{"class":605},[599,28373,28374],{"class":666},"Path $guidFile ",[599,28376,1132],{"class":605},[599,28378,28379],{"class":666},"Value ($lines ",[599,28381,28191],{"class":605},[599,28383,28384],{"class":619}," \"",[599,28386,28180],{"class":949},[599,28388,4362],{"class":619},[599,28390,1124],{"class":666},[599,28392,1132],{"class":605},[599,28394,28395],{"class":666},"Encoding Ascii\n",[599,28397,28398],{"class":601,"line":1700},[599,28399,651],{"emptyLinePlaceholder":650},[599,28401,28402,28405,28408,28410],{"class":601,"line":1720},[599,28403,28404],{"class":605},"foreach",[599,28406,28407],{"class":666}," ($file ",[599,28409,3413],{"class":605},[599,28411,28412],{"class":666}," $regFiles)\n",[599,28414,28415],{"class":601,"line":1731},[599,28416,667],{"class":666},[599,28418,28419,28422,28424,28427,28430,28432],{"class":601,"line":1745},[599,28420,28421],{"class":666},"    $text ",[599,28423,1060],{"class":605},[599,28425,28426],{"class":949}," Get-Content",[599,28428,28429],{"class":666}," $file.FullName ",[599,28431,1132],{"class":605},[599,28433,28434],{"class":666},"Raw\n",[599,28436,28437,28439,28441,28444,28447,28449,28451,28454,28456],{"class":601,"line":1750},[599,28438,28421],{"class":666},[599,28440,1060],{"class":605},[599,28442,28443],{"class":666}," $text ",[599,28445,28446],{"class":605},"-ireplace",[599,28448,27863],{"class":666},[599,28450,27866],{"class":605},[599,28452,28453],{"class":666},"]::Escape($oldProvider)",[599,28455,10558],{"class":605},[599,28457,28458],{"class":666}," $newProvider\n",[599,28460,28461,28463,28465,28467,28469,28471,28473,28476,28478],{"class":601,"line":1761},[599,28462,28421],{"class":666},[599,28464,1060],{"class":605},[599,28466,28443],{"class":666},[599,28468,28446],{"class":605},[599,28470,27863],{"class":666},[599,28472,27866],{"class":605},[599,28474,28475],{"class":666},"]::Escape($oldFilter)",[599,28477,10558],{"class":605},[599,28479,28480],{"class":666},"   $newFilter\n",[599,28482,28483,28486,28488,28491,28493,28496,28498,28501,28503],{"class":601,"line":1787},[599,28484,28485],{"class":949},"    Set-Content",[599,28487,1214],{"class":605},[599,28489,28490],{"class":666},"Path $file.FullName ",[599,28492,1132],{"class":605},[599,28494,28495],{"class":666},"Value $text ",[599,28497,1132],{"class":605},[599,28499,28500],{"class":666},"Encoding Ascii ",[599,28502,1132],{"class":605},[599,28504,28505],{"class":666},"NoNewline\n",[599,28507,28508],{"class":601,"line":1792},[599,28509,981],{"class":666},[599,28511,28512],{"class":601,"line":1815},[599,28513,651],{"emptyLinePlaceholder":650},[599,28515,28516,28519],{"class":601,"line":1820},[599,28517,28518],{"class":949},"Write-Host",[599,28520,28521],{"class":619}," ''\n",[599,28523,28524,28526,28529,28532,28535,28537],{"class":601,"line":1833},[599,28525,28518],{"class":949},[599,28527,28528],{"class":619}," \"Provider: {",[599,28530,28531],{"class":666},"$oldProvider",[599,28533,28534],{"class":619},"} -> {",[599,28536,28318],{"class":666},[599,28538,28321],{"class":619},[599,28540,28541,28543,28546,28549,28551,28553],{"class":601,"line":1863},[599,28542,28518],{"class":949},[599,28544,28545],{"class":619}," \"Filter:   {",[599,28547,28548],{"class":666},"$oldFilter",[599,28550,28534],{"class":619},[599,28552,28346],{"class":666},[599,28554,28321],{"class":619},[599,28556,28557,28559],{"class":601,"line":1870},[599,28558,28518],{"class":949},[599,28560,28521],{"class":619},[599,28562,28563,28565,28568,28571,28573,28575],{"class":601,"line":1875},[599,28564,28518],{"class":949},[599,28566,28567],{"class":619}," 'Updated guid.h and:'",[599,28569,28570],{"class":666}," ($regFiles.Name ",[599,28572,28191],{"class":605},[599,28574,28194],{"class":619},[599,28576,1029],{"class":666},[599,28578,28579,28581],{"class":601,"line":1880},[599,28580,28518],{"class":949},[599,28582,28583],{"class":619}," 'Now rebuild with build.bat and register again.'\n",[15,28585,28586],{},"Run it in the project folder and rebuild:",[148,28588,28590],{"className":23014,"code":28589,"language":23016,"meta":154,"style":154},"powershell -ExecutionPolicy Bypass -File .\\new-guids.ps1\n.\\build.bat\n",[69,28591,28592,28610],{"__ignoreMap":154},[599,28593,28594,28597,28599,28602,28604,28607],{"class":601,"line":602},[599,28595,28596],{"class":666},"powershell ",[599,28598,1132],{"class":605},[599,28600,28601],{"class":666},"ExecutionPolicy Bypass ",[599,28603,1132],{"class":605},[599,28605,28606],{"class":666},"File .",[599,28608,28609],{"class":949},"\\new-guids.ps1\n",[599,28611,28612,28615],{"class":601,"line":613},[599,28613,28614],{"class":666},".\\",[599,28616,28617],{"class":949},"build.bat\n",[15,28619,28620,28621,28623,28624,28627],{},"If an older version is already registered, run ",[69,28622,549],{}," first, while it still contains the old GUIDs. The script also keeps a copy with the old GUIDs as ",[69,28625,28626],{},"unregister-old.reg",", just in case.",[10,28629,526],{"id":28630},"build",[15,28632,28633],{},"You don't have to compile every file by hand.",[126,28635,28637],{"id":28636},"option-1-buildbat","Option 1: build.bat",[15,28639,28640,28641,3242],{},"Open the \"x64 Native Tools Command Prompt\" of your Visual Studio version from the start menu, go to the project folder and run ",[69,28642,520],{},[15,28644,28645],{},"It has to be the x64 prompt. LogonUI on a 64-bit Windows does not load a 32-bit DLL.",[15,28647,28648,28649,28651],{},"The script builds with ",[69,28650,71],{},". This links the C++ runtime into the DLL. Without it the VM would need the Visual C++ Redistributable, and if it is missing, LogonUI just doesn't load the DLL. You don't get an error, the tile simply doesn't show up.",[15,28653,28654,590],{},[69,28655,520],{},[148,28657,28661],{"className":28658,"code":28659,"language":28660,"meta":154,"style":154},"language-bat shiki shiki-themes github-dark","@echo off\nREM =====================================================================\nREM  Build TacProvider.dll and enroll.exe in one shot.\nREM\nREM  Run this from the \"x64 Native Tools Command Prompt\" of your Visual\nREM  Studio \u002F Build Tools version (Start menu -> Visual Studio folder). That shell puts\nREM  cl.exe and the Windows SDK on your PATH automatically.\nREM\nREM  Usage:   build.bat\nREM  Output:  TacProvider.dll  and  enroll.exe  in this folder.\nREM  \u002FMT links the C++ runtime statically, so the target machine needs\nREM  no Visual C++ Redistributable.\nREM =====================================================================\n\nsetlocal\ncd \u002Fd \"%~dp0\"\n\necho.\necho === Building TacProvider.dll (credential provider + filter) ===\ncl \u002Fnologo \u002FLD \u002FMT \u002FEHsc \u002Fstd:c++17 \u002FW3 \u002FDUNICODE \u002FD_UNICODE ^\n   dll.cpp CTacProvider.cpp CTacCredential.cpp CTacFilter.cpp ^\n   helpers.cpp totp.cpp store.cpp verify.cpp eventlog.cpp ^\n   \u002FFe:TacProvider.dll ^\n   \u002Flink \u002FDEF:TacProvider.def ^\n   bcrypt.lib crypt32.lib advapi32.lib secur32.lib shlwapi.lib ole32.lib uuid.lib gdi32.lib user32.lib wtsapi32.lib\nif errorlevel 1 goto :fail\n\necho.\necho === Building enroll.exe (enrollment tool) ===\ncl \u002Fnologo \u002FMT \u002FEHsc \u002Fstd:c++17 \u002FW3 \u002FDUNICODE \u002FD_UNICODE ^\n   enroll.cpp totp.cpp store.cpp ^\n   \u002FFe:enroll.exe ^\n   \u002Flink bcrypt.lib crypt32.lib advapi32.lib\nif errorlevel 1 goto :fail\n\necho.\necho === Done. Cleaning up intermediate files ===\ndel \u002Fq *.obj *.exp 2>nul\n\necho.\necho Built: TacProvider.dll  and  enroll.exe\necho (TacProvider.lib is just the import library; you don't deploy it.)\ngoto :eof\n\n:fail\necho.\necho BUILD FAILED - see the compiler errors above.\nexit \u002Fb 1\n","bat",[69,28662,28663,28671,28679,28686,28691,28698,28711,28718,28722,28729,28736,28743,28750,28756,28760,28765,28780,28784,28792,28803,28811,28818,28825,28832,28839,28844,28861,28865,28871,28882,28889,28896,28903,28908,28922,28926,28932,28939,28954,28958,28964,28971,28978,28988,28992,28998,29004,29011],{"__ignoreMap":154},[599,28664,28665,28668],{"class":601,"line":602},[599,28666,28667],{"class":605},"@echo",[599,28669,28670],{"class":605}," off\n",[599,28672,28673,28676],{"class":601,"line":613},[599,28674,28675],{"class":605},"REM",[599,28677,28678],{"class":772}," =====================================================================\n",[599,28680,28681,28683],{"class":601,"line":623},[599,28682,28675],{"class":605},[599,28684,28685],{"class":772},"  Build TacProvider.dll and enroll.exe in one shot.\n",[599,28687,28688],{"class":601,"line":631},[599,28689,28690],{"class":605},"REM\n",[599,28692,28693,28695],{"class":601,"line":639},[599,28694,28675],{"class":605},[599,28696,28697],{"class":772},"  Run this from the \"x64 Native Tools Command Prompt\" of your Visual\n",[599,28699,28700,28702,28705,28708],{"class":601,"line":647},[599,28701,28675],{"class":605},[599,28703,28704],{"class":772},"  Studio \u002F Build Tools version (Start menu -",[599,28706,717],{"class":28707},"s6RL2",[599,28709,28710],{"class":772}," Visual Studio folder). That shell puts\n",[599,28712,28713,28715],{"class":601,"line":654},[599,28714,28675],{"class":605},[599,28716,28717],{"class":772},"  cl.exe and the Windows SDK on your PATH automatically.\n",[599,28719,28720],{"class":601,"line":663},[599,28721,28690],{"class":605},[599,28723,28724,28726],{"class":601,"line":670},[599,28725,28675],{"class":605},[599,28727,28728],{"class":772},"  Usage:   build.bat\n",[599,28730,28731,28733],{"class":601,"line":728},[599,28732,28675],{"class":605},[599,28734,28735],{"class":772},"  Output:  TacProvider.dll  and  enroll.exe  in this folder.\n",[599,28737,28738,28740],{"class":601,"line":764},[599,28739,28675],{"class":605},[599,28741,28742],{"class":772},"  \u002FMT links the C++ runtime statically, so the target machine needs\n",[599,28744,28745,28747],{"class":601,"line":769},[599,28746,28675],{"class":605},[599,28748,28749],{"class":772},"  no Visual C++ Redistributable.\n",[599,28751,28752,28754],{"class":601,"line":776},[599,28753,28675],{"class":605},[599,28755,28678],{"class":772},[599,28757,28758],{"class":601,"line":816},[599,28759,651],{"emptyLinePlaceholder":650},[599,28761,28762],{"class":601,"line":843},[599,28763,28764],{"class":605},"setlocal\n",[599,28766,28767,28770,28773,28775,28778],{"class":601,"line":848},[599,28768,28769],{"class":605},"cd",[599,28771,28772],{"class":666}," \u002Fd ",[599,28774,4362],{"class":619},[599,28776,28777],{"class":949},"%~dp0",[599,28779,4710],{"class":619},[599,28781,28782],{"class":601,"line":854},[599,28783,651],{"emptyLinePlaceholder":650},[599,28785,28786,28789],{"class":601,"line":860},[599,28787,28788],{"class":605},"echo",[599,28790,28791],{"class":666},".\n",[599,28793,28794,28796,28799,28801],{"class":601,"line":866},[599,28795,28788],{"class":605},[599,28797,28798],{"class":666}," === Building TacProvider.dll (credential provider + filter) ",[599,28800,1349],{"class":605},[599,28802,10667],{"class":666},[599,28804,28805,28808],{"class":601,"line":912},[599,28806,28807],{"class":666},"cl \u002Fnologo \u002FLD \u002FMT \u002FEHsc \u002Fstd:c++17 \u002FW3 \u002FDUNICODE \u002FD_UNICODE ",[599,28809,28810],{"class":949},"^\n",[599,28812,28813,28816],{"class":601,"line":938},[599,28814,28815],{"class":666},"   dll.cpp CTacProvider.cpp CTacCredential.cpp CTacFilter.cpp ",[599,28817,28810],{"class":949},[599,28819,28820,28823],{"class":601,"line":978},[599,28821,28822],{"class":666},"   helpers.cpp totp.cpp store.cpp verify.cpp eventlog.cpp ",[599,28824,28810],{"class":949},[599,28826,28827,28830],{"class":601,"line":1316},[599,28828,28829],{"class":666},"   \u002FFe:TacProvider.dll ",[599,28831,28810],{"class":949},[599,28833,28834,28837],{"class":601,"line":1321},[599,28835,28836],{"class":666},"   \u002Flink \u002FDEF:TacProvider.def ",[599,28838,28810],{"class":949},[599,28840,28841],{"class":601,"line":1335},[599,28842,28843],{"class":666},"   bcrypt.lib crypt32.lib advapi32.lib secur32.lib shlwapi.lib ole32.lib uuid.lib gdi32.lib user32.lib wtsapi32.lib\n",[599,28845,28846,28848,28851,28853,28856,28858],{"class":601,"line":1341},[599,28847,27892],{"class":605},[599,28849,28850],{"class":605}," errorlevel",[599,28852,973],{"class":949},[599,28854,28855],{"class":605}," goto",[599,28857,8962],{"class":666},[599,28859,28860],{"class":605},"fail\n",[599,28862,28863],{"class":601,"line":1367},[599,28864,651],{"emptyLinePlaceholder":650},[599,28866,28867,28869],{"class":601,"line":1375},[599,28868,28788],{"class":605},[599,28870,28791],{"class":666},[599,28872,28873,28875,28878,28880],{"class":601,"line":1391},[599,28874,28788],{"class":605},[599,28876,28877],{"class":666}," === Building enroll.exe (enrollment tool) ",[599,28879,1349],{"class":605},[599,28881,10667],{"class":666},[599,28883,28884,28887],{"class":601,"line":1405},[599,28885,28886],{"class":666},"cl \u002Fnologo \u002FMT \u002FEHsc \u002Fstd:c++17 \u002FW3 \u002FDUNICODE \u002FD_UNICODE ",[599,28888,28810],{"class":949},[599,28890,28891,28894],{"class":601,"line":1416},[599,28892,28893],{"class":666},"   enroll.cpp totp.cpp store.cpp ",[599,28895,28810],{"class":949},[599,28897,28898,28901],{"class":601,"line":1421},[599,28899,28900],{"class":666},"   \u002FFe:enroll.exe ",[599,28902,28810],{"class":949},[599,28904,28905],{"class":601,"line":1449},[599,28906,28907],{"class":666},"   \u002Flink bcrypt.lib crypt32.lib advapi32.lib\n",[599,28909,28910,28912,28914,28916,28918,28920],{"class":601,"line":1462},[599,28911,27892],{"class":605},[599,28913,28850],{"class":605},[599,28915,973],{"class":949},[599,28917,28855],{"class":605},[599,28919,8962],{"class":666},[599,28921,28860],{"class":605},[599,28923,28924],{"class":601,"line":1477},[599,28925,651],{"emptyLinePlaceholder":650},[599,28927,28928,28930],{"class":601,"line":1483},[599,28929,28788],{"class":605},[599,28931,28791],{"class":666},[599,28933,28934,28936],{"class":601,"line":1496},[599,28935,28788],{"class":605},[599,28937,28938],{"class":666}," === Done. Cleaning up intermediate files ===\n",[599,28940,28941,28944,28947,28949,28951],{"class":601,"line":1523},[599,28942,28943],{"class":605},"del",[599,28945,28946],{"class":666}," \u002Fq *.obj *.exp ",[599,28948,4012],{"class":949},[599,28950,717],{"class":605},[599,28952,28953],{"class":949},"nul\n",[599,28955,28956],{"class":601,"line":1555},[599,28957,651],{"emptyLinePlaceholder":650},[599,28959,28960,28962],{"class":601,"line":1561},[599,28961,28788],{"class":605},[599,28963,28791],{"class":666},[599,28965,28966,28968],{"class":601,"line":1567},[599,28967,28788],{"class":605},[599,28969,28970],{"class":666}," Built: TacProvider.dll  and  enroll.exe\n",[599,28972,28973,28975],{"class":601,"line":1577},[599,28974,28788],{"class":605},[599,28976,28977],{"class":666}," (TacProvider.lib is just the import library; you don't deploy it.)\n",[599,28979,28980,28983,28985],{"class":601,"line":1582},[599,28981,28982],{"class":605},"goto",[599,28984,8962],{"class":666},[599,28986,28987],{"class":605},"eof\n",[599,28989,28990],{"class":601,"line":1587},[599,28991,651],{"emptyLinePlaceholder":650},[599,28993,28994,28996],{"class":601,"line":1616},[599,28995,590],{"class":666},[599,28997,28860],{"class":605},[599,28999,29000,29002],{"class":601,"line":1621},[599,29001,28788],{"class":605},[599,29003,28791],{"class":666},[599,29005,29006,29008],{"class":601,"line":1634},[599,29007,28788],{"class":605},[599,29009,29010],{"class":666}," BUILD FAILED - see the compiler errors above.\n",[599,29012,29013,29016,29019],{"class":601,"line":1647},[599,29014,29015],{"class":605},"exit",[599,29017,29018],{"class":666}," \u002Fb ",[599,29020,3509],{"class":949},[15,29022,29023,29024,8721,29027,590],{},"If everything works, it looks like this. Every source file shows up once, and at the end you have ",[69,29025,29026],{},"TacProvider.dll",[69,29028,29029],{},"enroll.exe",[15,29031,29032],{},[29033,29034],"img",{"alt":29035,"src":29036},"build.bat in the x64 Native Tools Command Prompt","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F01-build.webp",[126,29038,29040],{"id":29039},"option-2-cmake","Option 2: CMake",[15,29042,29043],{},"If you have CMake installed:",[148,29045,29048],{"className":29046,"code":29047,"language":153,"meta":154},[151],"cmake -B build -A x64\ncmake --build build --config Release\n",[69,29049,29047],{"__ignoreMap":154},[15,29051,29052,590],{},[69,29053,523],{},[148,29055,29059],{"className":29056,"code":29057,"language":29058,"meta":154,"style":154},"language-cmake shiki shiki-themes github-dark","cmake_minimum_required(VERSION 3.20)\nproject(TacProvider CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nadd_compile_definitions(UNICODE _UNICODE)\n\n# Static C++ runtime (\u002FMT): the target machine needs no VC++ Redistributable.\n# Without this, LogonUI silently fails to load the DLL on a clean VM.\nset(CMAKE_MSVC_RUNTIME_LIBRARY \"MultiThreaded$\u003C$\u003CCONFIG:Debug>:Debug>\")\n\n# --- the credential provider + filter DLL ---\nadd_library(TacProvider SHARED\n    dll.cpp\n    CTacProvider.cpp\n    CTacCredential.cpp\n    CTacFilter.cpp\n    helpers.cpp\n    totp.cpp\n    store.cpp\n    verify.cpp\n    eventlog.cpp)\n\ntarget_link_libraries(TacProvider PRIVATE\n    bcrypt crypt32 advapi32 secur32 shlwapi ole32 uuid gdi32 user32 wtsapi32)\n\n# apply the module-definition file (the COM exports)\nset_target_properties(TacProvider PROPERTIES\n    LINK_FLAGS \"\u002FDEF:\\\"${CMAKE_CURRENT_SOURCE_DIR}\u002FTacProvider.def\\\"\")\n\n# --- the enrollment console tool ---\nadd_executable(enroll\n    enroll.cpp\n    totp.cpp\n    store.cpp)\n\ntarget_link_libraries(enroll PRIVATE\n    bcrypt crypt32 advapi32)\n\n# ---------------------------------------------------------------------\n# Build (from a normal PowerShell\u002Fcmd, CMake must be installed):\n#   cmake -B build -A x64\n#   cmake --build build --config Release\n# Outputs land in build\\Release\\TacProvider.dll and build\\Release\\enroll.exe\n# ---------------------------------------------------------------------\n","cmake",[69,29060,29061,29074,29082,29086,29094,29106,29111,29115,29120,29125,29137,29141,29146,29154,29159,29164,29169,29174,29179,29184,29189,29194,29199,29203,29214,29219,29223,29228,29236,29256,29260,29265,29273,29278,29282,29287,29291,29300,29305,29309,29314,29319,29324,29329,29334],{"__ignoreMap":154},[599,29062,29063,29066,29068,29071],{"class":601,"line":602},[599,29064,29065],{"class":605},"cmake_minimum_required",[599,29067,679],{"class":666},[599,29069,29070],{"class":609},"VERSION",[599,29072,29073],{"class":666}," 3.20)\n",[599,29075,29076,29079],{"class":601,"line":613},[599,29077,29078],{"class":605},"project",[599,29080,29081],{"class":666},"(TacProvider CXX)\n",[599,29083,29084],{"class":601,"line":623},[599,29085,651],{"emptyLinePlaceholder":650},[599,29087,29088,29091],{"class":601,"line":631},[599,29089,29090],{"class":605},"set",[599,29092,29093],{"class":666},"(CMAKE_CXX_STANDARD 17)\n",[599,29095,29096,29098,29101,29104],{"class":601,"line":639},[599,29097,29090],{"class":605},[599,29099,29100],{"class":666},"(CMAKE_CXX_STANDARD_REQUIRED ",[599,29102,29103],{"class":605},"ON",[599,29105,1029],{"class":666},[599,29107,29108],{"class":601,"line":647},[599,29109,29110],{"class":666},"add_compile_definitions(UNICODE _UNICODE)\n",[599,29112,29113],{"class":601,"line":654},[599,29114,651],{"emptyLinePlaceholder":650},[599,29116,29117],{"class":601,"line":663},[599,29118,29119],{"class":772},"# Static C++ runtime (\u002FMT): the target machine needs no VC++ Redistributable.\n",[599,29121,29122],{"class":601,"line":670},[599,29123,29124],{"class":772},"# Without this, LogonUI silently fails to load the DLL on a clean VM.\n",[599,29126,29127,29129,29132,29135],{"class":601,"line":728},[599,29128,29090],{"class":605},[599,29130,29131],{"class":666},"(CMAKE_MSVC_RUNTIME_LIBRARY ",[599,29133,29134],{"class":619},"\"MultiThreaded$\u003C$\u003CCONFIG:Debug>:Debug>\"",[599,29136,1029],{"class":666},[599,29138,29139],{"class":601,"line":764},[599,29140,651],{"emptyLinePlaceholder":650},[599,29142,29143],{"class":601,"line":769},[599,29144,29145],{"class":772},"# --- the credential provider + filter DLL ---\n",[599,29147,29148,29151],{"class":601,"line":776},[599,29149,29150],{"class":605},"add_library",[599,29152,29153],{"class":666},"(TacProvider SHARED\n",[599,29155,29156],{"class":601,"line":816},[599,29157,29158],{"class":666},"    dll.cpp\n",[599,29160,29161],{"class":601,"line":843},[599,29162,29163],{"class":666},"    CTacProvider.cpp\n",[599,29165,29166],{"class":601,"line":848},[599,29167,29168],{"class":666},"    CTacCredential.cpp\n",[599,29170,29171],{"class":601,"line":854},[599,29172,29173],{"class":666},"    CTacFilter.cpp\n",[599,29175,29176],{"class":601,"line":860},[599,29177,29178],{"class":666},"    helpers.cpp\n",[599,29180,29181],{"class":601,"line":866},[599,29182,29183],{"class":666},"    totp.cpp\n",[599,29185,29186],{"class":601,"line":912},[599,29187,29188],{"class":666},"    store.cpp\n",[599,29190,29191],{"class":601,"line":938},[599,29192,29193],{"class":666},"    verify.cpp\n",[599,29195,29196],{"class":601,"line":978},[599,29197,29198],{"class":666},"    eventlog.cpp)\n",[599,29200,29201],{"class":601,"line":1316},[599,29202,651],{"emptyLinePlaceholder":650},[599,29204,29205,29208,29211],{"class":601,"line":1321},[599,29206,29207],{"class":605},"target_link_libraries",[599,29209,29210],{"class":666},"(TacProvider ",[599,29212,29213],{"class":609},"PRIVATE\n",[599,29215,29216],{"class":601,"line":1335},[599,29217,29218],{"class":666},"    bcrypt crypt32 advapi32 secur32 shlwapi ole32 uuid gdi32 user32 wtsapi32)\n",[599,29220,29221],{"class":601,"line":1341},[599,29222,651],{"emptyLinePlaceholder":650},[599,29224,29225],{"class":601,"line":1367},[599,29226,29227],{"class":772},"# apply the module-definition file (the COM exports)\n",[599,29229,29230,29233],{"class":601,"line":1375},[599,29231,29232],{"class":605},"set_target_properties",[599,29234,29235],{"class":666},"(TacProvider PROPERTIES\n",[599,29237,29238,29241,29244,29247,29250,29252,29254],{"class":601,"line":1391},[599,29239,29240],{"class":609},"    LINK_FLAGS",[599,29242,29243],{"class":619}," \"\u002FDEF:",[599,29245,29246],{"class":949},"\\\"",[599,29248,29249],{"class":619},"${CMAKE_CURRENT_SOURCE_DIR}\u002FTacProvider.def",[599,29251,29246],{"class":949},[599,29253,4362],{"class":619},[599,29255,1029],{"class":666},[599,29257,29258],{"class":601,"line":1405},[599,29259,651],{"emptyLinePlaceholder":650},[599,29261,29262],{"class":601,"line":1416},[599,29263,29264],{"class":772},"# --- the enrollment console tool ---\n",[599,29266,29267,29270],{"class":601,"line":1421},[599,29268,29269],{"class":605},"add_executable",[599,29271,29272],{"class":666},"(enroll\n",[599,29274,29275],{"class":601,"line":1449},[599,29276,29277],{"class":666},"    enroll.cpp\n",[599,29279,29280],{"class":601,"line":1462},[599,29281,29183],{"class":666},[599,29283,29284],{"class":601,"line":1477},[599,29285,29286],{"class":666},"    store.cpp)\n",[599,29288,29289],{"class":601,"line":1483},[599,29290,651],{"emptyLinePlaceholder":650},[599,29292,29293,29295,29298],{"class":601,"line":1496},[599,29294,29207],{"class":605},[599,29296,29297],{"class":666},"(enroll ",[599,29299,29213],{"class":609},[599,29301,29302],{"class":601,"line":1523},[599,29303,29304],{"class":666},"    bcrypt crypt32 advapi32)\n",[599,29306,29307],{"class":601,"line":1555},[599,29308,651],{"emptyLinePlaceholder":650},[599,29310,29311],{"class":601,"line":1561},[599,29312,29313],{"class":772},"# ---------------------------------------------------------------------\n",[599,29315,29316],{"class":601,"line":1567},[599,29317,29318],{"class":772},"# Build (from a normal PowerShell\u002Fcmd, CMake must be installed):\n",[599,29320,29321],{"class":601,"line":1577},[599,29322,29323],{"class":772},"#   cmake -B build -A x64\n",[599,29325,29326],{"class":601,"line":1582},[599,29327,29328],{"class":772},"#   cmake --build build --config Release\n",[599,29330,29331],{"class":601,"line":1587},[599,29332,29333],{"class":772},"# Outputs land in build\\Release\\TacProvider.dll and build\\Release\\enroll.exe\n",[599,29335,29336],{"class":601,"line":1616},[599,29337,29313],{"class":772},[15,29339,29340,29341,8721,29343,29345,29346,29349],{},"Both options create ",[69,29342,29026],{},[69,29344,29029],{},". The ",[69,29347,29348],{},"TacProvider.lib"," is only the import library and is not needed.",[10,29351,29353],{"id":29352},"install","Install",[15,29355,29356,29357,29359],{},"The registration is split into three files. ",[69,29358,543],{}," registers the provider and the event log source, but hides nothing:",[148,29361,29365],{"className":29362,"code":29363,"language":29364,"meta":154,"style":154},"language-ini shiki shiki-themes github-dark","Windows Registry Editor Version 5.00\n\n; Step 1: COM registration + provider. Does NOT hide any other tile.\n; GUIDs here MUST match guid.h. Regenerate both before using this anywhere.\n;   provider {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\n;   filter   {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\n; The DLL lives under Program Files so only admins can replace it.\n\n[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n@=\"TheAdminCafe 2FA Credential Provider\"\n[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\\InprocServer32]\n@=\"C:\\\\Program Files\\\\TheAdminCafe\\\\TacProvider.dll\"\n\"ThreadingModel\"=\"Apartment\"\n\n[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n@=\"TheAdminCafe 2FA Credential Provider Filter\"\n[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\\InprocServer32]\n@=\"C:\\\\Program Files\\\\TheAdminCafe\\\\TacProvider.dll\"\n\"ThreadingModel\"=\"Apartment\"\n\n[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n@=\"TheAdminCafe 2FA Credential Provider\"\n\n; Event log source for the 2FA events (Application log). EventCreate.exe has a\n; message table that prints the text as it is (%1) for the IDs 1 to 1000.\n[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\TheAdminCafe 2FA]\n\"EventMessageFile\"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,45,00,76,00,65,00,6e,00,74,00,43,00,72,00,65,00,61,00,74,00,65,00,2e,00,65,00,78,00,65,00,00,00\n\"TypesSupported\"=dword:00000007\n","ini",[69,29366,29367,29372,29376,29381,29386,29391,29396,29401,29405,29410,29418,29423,29430,29440,29444,29449,29456,29461,29467,29475,29479,29484,29490,29494,29499,29504,29509,29517],{"__ignoreMap":154},[599,29368,29369],{"class":601,"line":602},[599,29370,29371],{"class":666},"Windows Registry Editor Version 5.00\n",[599,29373,29374],{"class":601,"line":613},[599,29375,651],{"emptyLinePlaceholder":650},[599,29377,29378],{"class":601,"line":623},[599,29379,29380],{"class":772},"; Step 1: COM registration + provider. Does NOT hide any other tile.\n",[599,29382,29383],{"class":601,"line":631},[599,29384,29385],{"class":772},"; GUIDs here MUST match guid.h. Regenerate both before using this anywhere.\n",[599,29387,29388],{"class":601,"line":639},[599,29389,29390],{"class":772},";   provider {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\n",[599,29392,29393],{"class":601,"line":647},[599,29394,29395],{"class":772},";   filter   {B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\n",[599,29397,29398],{"class":601,"line":654},[599,29399,29400],{"class":772},"; The DLL lives under Program Files so only admins can replace it.\n",[599,29402,29403],{"class":601,"line":663},[599,29404,651],{"emptyLinePlaceholder":650},[599,29406,29407],{"class":601,"line":670},[599,29408,29409],{"class":609},"[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n",[599,29411,29412,29415],{"class":601,"line":728},[599,29413,29414],{"class":666},"@=",[599,29416,29417],{"class":619},"\"TheAdminCafe 2FA Credential Provider\"\n",[599,29419,29420],{"class":601,"line":764},[599,29421,29422],{"class":609},"[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}\\InprocServer32]\n",[599,29424,29425,29427],{"class":601,"line":769},[599,29426,29414],{"class":666},[599,29428,29429],{"class":619},"\"C:\\\\Program Files\\\\TheAdminCafe\\\\TacProvider.dll\"\n",[599,29431,29432,29435,29437],{"class":601,"line":776},[599,29433,29434],{"class":619},"\"ThreadingModel\"",[599,29436,1060],{"class":666},[599,29438,29439],{"class":619},"\"Apartment\"\n",[599,29441,29442],{"class":601,"line":816},[599,29443,651],{"emptyLinePlaceholder":650},[599,29445,29446],{"class":601,"line":843},[599,29447,29448],{"class":609},"[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n",[599,29450,29451,29453],{"class":601,"line":848},[599,29452,29414],{"class":666},[599,29454,29455],{"class":619},"\"TheAdminCafe 2FA Credential Provider Filter\"\n",[599,29457,29458],{"class":601,"line":854},[599,29459,29460],{"class":609},"[HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}\\InprocServer32]\n",[599,29462,29463,29465],{"class":601,"line":860},[599,29464,29414],{"class":666},[599,29466,29429],{"class":619},[599,29468,29469,29471,29473],{"class":601,"line":866},[599,29470,29434],{"class":619},[599,29472,1060],{"class":666},[599,29474,29439],{"class":619},[599,29476,29477],{"class":601,"line":912},[599,29478,651],{"emptyLinePlaceholder":650},[599,29480,29481],{"class":601,"line":938},[599,29482,29483],{"class":609},"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n",[599,29485,29486,29488],{"class":601,"line":978},[599,29487,29414],{"class":666},[599,29489,29417],{"class":619},[599,29491,29492],{"class":601,"line":1316},[599,29493,651],{"emptyLinePlaceholder":650},[599,29495,29496],{"class":601,"line":1321},[599,29497,29498],{"class":772},"; Event log source for the 2FA events (Application log). EventCreate.exe has a\n",[599,29500,29501],{"class":601,"line":1335},[599,29502,29503],{"class":772},"; message table that prints the text as it is (%1) for the IDs 1 to 1000.\n",[599,29505,29506],{"class":601,"line":1341},[599,29507,29508],{"class":609},"[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\TheAdminCafe 2FA]\n",[599,29510,29511,29514],{"class":601,"line":1367},[599,29512,29513],{"class":619},"\"EventMessageFile\"",[599,29515,29516],{"class":666},"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,45,00,76,00,65,00,6e,00,74,00,43,00,72,00,65,00,61,00,74,00,65,00,2e,00,65,00,78,00,65,00,00,00\n",[599,29518,29519,29522],{"class":601,"line":1375},[599,29520,29521],{"class":619},"\"TypesSupported\"",[599,29523,29524],{"class":666},"=dword:00000007\n",[15,29526,29527,29529],{},[69,29528,546],{}," adds the filter that hides all other tiles:",[148,29531,29533],{"className":29362,"code":29532,"language":29364,"meta":154,"style":154},"Windows Registry Editor Version 5.00\n\n; Step 2: the filter. Hides every other tile (password, PIN, Hello).\n; Import this ONLY after an enrolled account can log on through the 2FA tile.\n\n[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n@=\"TheAdminCafe 2FA Credential Provider Filter\"\n",[69,29534,29535,29539,29543,29548,29553,29557,29562],{"__ignoreMap":154},[599,29536,29537],{"class":601,"line":602},[599,29538,29371],{"class":666},[599,29540,29541],{"class":601,"line":613},[599,29542,651],{"emptyLinePlaceholder":650},[599,29544,29545],{"class":601,"line":623},[599,29546,29547],{"class":772},"; Step 2: the filter. Hides every other tile (password, PIN, Hello).\n",[599,29549,29550],{"class":601,"line":631},[599,29551,29552],{"class":772},"; Import this ONLY after an enrolled account can log on through the 2FA tile.\n",[599,29554,29555],{"class":601,"line":639},[599,29556,651],{"emptyLinePlaceholder":650},[599,29558,29559],{"class":601,"line":647},[599,29560,29561],{"class":609},"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n",[599,29563,29564,29566],{"class":601,"line":654},[599,29565,29414],{"class":666},[599,29567,29455],{"class":619},[15,29569,29570,29572],{},[69,29571,549],{}," removes everything again:",[148,29574,29576],{"className":29362,"code":29575,"language":29364,"meta":154,"style":154},"Windows Registry Editor Version 5.00\n\n; Removes the filter, the provider and the COM registration.\n; The enrolled secrets and the lock state under HKLM\\SOFTWARE\\TheAdminCafe\n; are NOT removed.\n\n[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n[-HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n[-HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n[-HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\TheAdminCafe 2FA]\n",[69,29577,29578,29582,29586,29591,29596,29601,29605,29610,29615,29620,29625],{"__ignoreMap":154},[599,29579,29580],{"class":601,"line":602},[599,29581,29371],{"class":666},[599,29583,29584],{"class":601,"line":613},[599,29585,651],{"emptyLinePlaceholder":650},[599,29587,29588],{"class":601,"line":623},[599,29589,29590],{"class":772},"; Removes the filter, the provider and the COM registration.\n",[599,29592,29593],{"class":601,"line":631},[599,29594,29595],{"class":772},"; The enrolled secrets and the lock state under HKLM\\SOFTWARE\\TheAdminCafe\n",[599,29597,29598],{"class":601,"line":639},[599,29599,29600],{"class":772},"; are NOT removed.\n",[599,29602,29603],{"class":601,"line":647},[599,29604,651],{"emptyLinePlaceholder":650},[599,29606,29607],{"class":601,"line":654},[599,29608,29609],{"class":609},"[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n",[599,29611,29612],{"class":601,"line":663},[599,29613,29614],{"class":609},"[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n",[599,29616,29617],{"class":601,"line":670},[599,29618,29619],{"class":609},"[-HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE01}]\n",[599,29621,29622],{"class":601,"line":728},[599,29623,29624],{"class":609},"[-HKEY_CLASSES_ROOT\\CLSID\\{B1E7C9A0-2F4D-4C6B-9A11-0000C0FFEE02}]\n",[599,29626,29627],{"class":601,"line":764},[599,29628,29629],{"class":609},"[-HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\TheAdminCafe 2FA]\n",[15,29631,29632],{},"Please follow this order.",[126,29634,29636],{"id":29635},"_1-snapshot","1. Snapshot",[15,29638,29639],{},"Create a snapshot of the VM. Really.",[126,29641,29643],{"id":29642},"_2-folder-under-program-files","2. Folder under Program Files",[15,29645,29646,29647,29650,29651,29654],{},"Create the folder ",[69,29648,29649],{},"C:\\Program Files\\TheAdminCafe\\",". Please don't use a folder directly under ",[69,29652,29653],{},"C:\\",". Such folders inherit rights that allow every user to change files in them. A normal user could then replace the DLL and LogonUI would run his code as SYSTEM.",[15,29656,29657],{},[29033,29658],{"alt":29659,"src":29660},"The TheAdminCafe folder under C:\\Program Files","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F02-program-files-folder.webp",[15,29662,29663,29664,8721,29666,29668,29669,29671],{},"Copy ",[69,29665,29026],{},[69,29667,29029],{}," into it. I also put the three ",[69,29670,27722],{}," files there, so I have everything in one place:",[15,29673,29674],{},[29033,29675],{"alt":29676,"src":29677},"TacProvider.dll, enroll.exe and the .reg files in the folder","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F03-copied-files.webp",[126,29679,29681],{"id":29680},"_3-register-the-provider","3. Register the provider",[15,29683,29684,29685,590],{},"Start PowerShell as administrator, go to the folder and import ",[69,29686,543],{},[148,29688,29690],{"className":23014,"code":29689,"language":23016,"meta":154,"style":154},"cd \"C:\\Program Files\\TheAdminCafe\"\nreg import .\\register.reg\n",[69,29691,29692,29700],{"__ignoreMap":154},[599,29693,29694,29697],{"class":601,"line":602},[599,29695,29696],{"class":666},"cd ",[599,29698,29699],{"class":619},"\"C:\\Program Files\\TheAdminCafe\"\n",[599,29701,29702],{"class":601,"line":613},[599,29703,29704],{"class":666},"reg import .\\register.reg\n",[15,29706,29707],{},[29033,29708],{"alt":29709,"src":29710},"reg import register.reg in an admin PowerShell","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F04-reg-import.webp",[15,29712,29713],{},"This registers the provider and the event log source. It doesn't hide anything yet.",[126,29715,29717],{"id":29716},"_4-check-the-logon-screen","4. Check the logon screen",[15,29719,29720],{},"Log off. At first the logon screen looks the same as before. Click \"Sign-in options\":",[15,29722,29723],{},[29033,29724],{"alt":29725,"src":29726},"The normal logon screen with \"Sign-in options\"","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F05-logon-sign-in-options.webp",[15,29728,29729],{},"Next to the key (the normal password provider) there is now our brown \"2FA\" icon. Click it, and you get three fields: username, password and one-time code.",[15,29731,29732],{},[29033,29733],{"alt":29734,"src":29735},"Our tile with username, password and one-time code","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F06-logon-2fa-tile.webp",[15,29737,29738],{},"On my VM Windows shows \"Other user\" and no list of accounts. That's why you see the fallback tile with a username field here. On a machine that lists the local users, you click a user first and only get password and code.",[15,29740,29741],{},"If something is wrong, you can still use the key icon and log on with the password.",[126,29743,29745],{"id":29744},"_5-enroll-and-test","5. Enroll and test",[15,29747,29748,29749,29752],{},"For the test I create a new local user ",[69,29750,29751],{},"test",", put it into the Administrators group and enroll it:",[148,29754,29756],{"className":23014,"code":29755,"language":23016,"meta":154,"style":154},"net user test \"\u003Cpassword>\" \u002Fadd\nnet localgroup \"Administrators\" \"test\" \u002Fadd\n& \"C:\\Program Files\\TheAdminCafe\\enroll.exe\" test\n",[69,29757,29758,29771,29786],{"__ignoreMap":154},[599,29759,29760,29763,29766,29768],{"class":601,"line":602},[599,29761,29762],{"class":666},"net user test ",[599,29764,29765],{"class":619},"\"\u003Cpassword>\"",[599,29767,24684],{"class":605},[599,29769,29770],{"class":666},"add\n",[599,29772,29773,29776,29779,29782,29784],{"class":601,"line":613},[599,29774,29775],{"class":666},"net localgroup ",[599,29777,29778],{"class":619},"\"Administrators\"",[599,29780,29781],{"class":619}," \"test\"",[599,29783,24684],{"class":605},[599,29785,29770],{"class":666},[599,29787,29788,29790,29793],{"class":601,"line":623},[599,29789,694],{"class":605},[599,29791,29792],{"class":619}," \"C:\\Program Files\\TheAdminCafe\\enroll.exe\"",[599,29794,29795],{"class":666}," test\n",[15,29797,29798],{},[29033,29799],{"alt":29800,"src":29801},"Creating the user test and enrolling it with enroll.exe","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F07-enroll-test-user.webp",[15,29803,29804,29805,29807],{},"You see the SID of the account, the secret and the ",[69,29806,10412],{}," URI. This is a throwaway VM that gets deleted, so it doesn't matter that password and secret are in the screenshot. On a real machine never show them to anybody.",[15,29809,29810,29811,29813],{},"Now add the secret to your authenticator app. I use the Google Authenticator: \"+\" → \"Enter a setup key\", give the account a name, paste the secret and leave the type on \"Time based\". That's exactly what ",[69,29812,29029],{}," created: TOTP with SHA1, 6 digits and 30 seconds, the defaults of every authenticator app.",[15,29815,29816],{},[29033,29817],{"alt":29818,"src":29819},"Adding the secret in the Google Authenticator","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F08-authenticator-add-key.webp",[15,29821,29822],{},"The app shows a new code right away. The small circle next to it is the 30 second countdown until the next code:",[15,29824,29825],{},[29033,29826],{"alt":29827,"src":29828},"The first code in the app","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F09-authenticator-code.webp",[15,29830,29831],{},"Then log off, choose the 2FA tile and enter username, password and the current code:",[15,29833,29834],{},[29033,29835],{"alt":29836,"src":29837},"The 2FA tile with username, password and code filled in","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F10-logon-filled-in.webp",[15,29839,29840],{},"First try a wrong code on purpose. The tile refuses it, and the password never reaches Windows:",[15,29842,29843],{},[29033,29844],{"alt":29845,"src":29846},"Invalid one-time code.","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F11-logon-invalid-code.webp",[15,29848,29849],{},"With the correct code the logon goes through:",[15,29851,29852],{},[29033,29853],{"alt":29854,"src":29855},"Applying user settings: the logon works","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fattachments\u002F12-logon-success.webp",[15,29857,29858,29859,29861],{},"Every attempt should now show up in the Application log with the source ",[69,29860,21950],{},". Enroll every other account you need the same way, including a break-glass admin.",[126,29863,29865],{"id":29864},"_6-enable-the-filter","6. Enable the filter",[15,29867,29868,29869,29871],{},"Only if everything works, import ",[69,29870,546],{}," and log off again:",[148,29873,29875],{"className":23014,"code":29874,"language":23016,"meta":154,"style":154},"reg import .\\register-filter.reg\n",[69,29876,29877],{"__ignoreMap":154},[599,29878,29879,29882,29885],{"class":601,"line":602},[599,29880,29881],{"class":666},"reg import .",[599,29883,29884],{"class":949},"\\register-filter",[599,29886,29887],{"class":666},".reg\n",[15,29889,29890],{},"Now the sign-in options are gone. The key icon disappears, and every logon asks for password and code.",[15,29892,29893],{},"The filter is the part that can lock you out. That's why it comes last.",[10,29895,29896],{"id":29751},"Test",[15,29898,29899],{},"I tested the following:",[277,29901,29902,29914],{},[280,29903,29904],{},[283,29905,29906,29909,29911],{},[286,29907,29908],{},"#",[286,29910,29896],{},[286,29912,29913],{},"Expected result",[293,29915,29916,29926,29936,29946,29956,29966,29976,29987,30000,30013,30024,30034,30044,30055,30066,30079,30089,30100],{},[283,29917,29918,29920,29923],{},[298,29919,1217],{},[298,29921,29922],{},"Enrolled user, correct password, current code",[298,29924,29925],{},"Logon works",[283,29927,29928,29930,29933],{},[298,29929,4012],{},[298,29931,29932],{},"Enrolled user, correct password, wrong or old code",[298,29934,29935],{},"\"Invalid one-time code.\", no logon",[283,29937,29938,29940,29943],{},[298,29939,4036],{},[298,29941,29942],{},"User not enrolled",[298,29944,29945],{},"Same message as in test 2, no logon",[283,29947,29948,29950,29953],{},[298,29949,6732],{},[298,29951,29952],{},"Enrolled user, correct code, wrong password",[298,29954,29955],{},"\"Incorrect password.\", password and code fields are empty again",[283,29957,29958,29960,29963],{},[298,29959,1847],{},[298,29961,29962],{},"Filter off, click a user, open \"Sign-in options\"",[298,29964,29965],{},"Brown \"2FA\" icon next to password and PIN",[283,29967,29968,29970,29973],{},[298,29969,3886],{},[298,29971,29972],{},"Filter active",[298,29974,29975],{},"Only our user tiles, no sign-in options, no password\u002FPIN\u002FHello",[283,29977,29978,29981,29984],{},[298,29979,29980],{},"7",[298,29982,29983],{},"Lock screen and unlock with password and code",[298,29985,29986],{},"Unlock works",[283,29988,29989,29991,29997],{},[298,29990,2326],{},[298,29992,29993,29994],{},"Normal user reads ",[69,29995,29996],{},"HKLM\\SOFTWARE\\TheAdminCafe\\2FA",[298,29998,29999],{},"Access denied",[283,30001,30002,30005,30010],{},[298,30003,30004],{},"9",[298,30006,30007,30009],{},[69,30008,29029],{}," with a name that doesn't exist",[298,30011,30012],{},"\"is not a local user account\", nothing is stored",[283,30014,30015,30018,30021],{},[298,30016,30017],{},"10",[298,30019,30020],{},"Microsoft account on the machine",[298,30022,30023],{},"Gets no tile from our provider",[283,30025,30026,30028,30031],{},[298,30027,26627],{},[298,30029,30030],{},"RDP with NLA",[298,30032,30033],{},"Username and password are filled in, code is still required",[283,30035,30036,30038,30041],{},[298,30037,28154],{},[298,30039,30040],{},"Log on, log off and log on again with the same code",[298,30042,30043],{},"\"Invalid one-time code.\", only the next code works",[283,30045,30046,30049,30052],{},[298,30047,30048],{},"13",[298,30050,30051],{},"5 wrong codes in a row",[298,30053,30054],{},"\"Too many wrong codes. Try again in 5 minutes.\"",[283,30056,30057,30060,30063],{},[298,30058,30059],{},"14",[298,30061,30062],{},"Correct code while the account is locked",[298,30064,30065],{},"Still locked, the code is not checked",[283,30067,30068,30071,30076],{},[298,30069,30070],{},"15",[298,30072,30073],{},[69,30074,30075],{},"enroll.exe \u002Funlock alice",[298,30077,30078],{},"Logon works again with the next code",[283,30080,30081,30083,30086],{},[298,30082,4001],{},[298,30084,30085],{},"Rename a user, create a new user with the old name",[298,30087,30088],{},"The renamed user still logs in, the new one has no secret",[283,30090,30091,30094,30097],{},[298,30092,30093],{},"17",[298,30095,30096],{},"Wrong code, then check the Application log",[298,30098,30099],{},"Event 101 with account, SID and console\u002FRDP address",[283,30101,30102,30105,30108],{},[298,30103,30104],{},"18",[298,30106,30107],{},"Restart into Safe Mode (Shift + Restart)",[298,30109,30110],{},"Check what you get. See \"Attacks that never touch the tile\"",[15,30112,30113],{},"For test 8 run this as a normal user:",[148,30115,30117],{"className":23014,"code":30116,"language":23016,"meta":154,"style":154},"Get-ItemProperty HKLM:\\SOFTWARE\\TheAdminCafe\\2FA\n",[69,30118,30119],{"__ignoreMap":154},[599,30120,30121,30124],{"class":601,"line":602},[599,30122,30123],{"class":949},"Get-ItemProperty",[599,30125,30126],{"class":666}," HKLM:\\SOFTWARE\\TheAdminCafe\\2FA\n",[10,30128,30130],{"id":30129},"debugging-and-what-to-do-if-you-are-locked-out","Debugging and what to do if you are locked out",[15,30132,30133],{},"LogonUI runs as SYSTEM on the Secure Desktop. You can't just attach Visual Studio. If the Credential Provider crashes, you don't get an error message, the logon just doesn't work anymore.",[15,30135,30136],{},"What helped me:",[56,30138,30139,30142,30145],{},[59,30140,30141],{},"Snapshot before every install. If something goes wrong, go back.",[59,30143,30144],{},"Write logs to a file (in a folder where SYSTEM can write) or use ETW. Real debugging on the Secure Desktop needs remote or kernel debugging and that is a lot of work for one log line.",[59,30146,30147],{},"Only enable the filter at the very end.",[15,30149,30150,30151,3242],{},"If you are locked out, restore the snapshot. If you don't have one, boot into the Windows Recovery Environment, load the registry offline and delete the filter key under ",[69,30152,30153],{},"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters\\",[15,30155,30156,30157,21925],{},"If the problem is only the lock (too many wrong codes), you don't need any of this. Another admin runs ",[69,30158,30159],{},"enroll.exe \u002Funlock \u003Cuser>",[15,30161,30162],{},"And now look at the recovery tip again: boot into WinRE, edit the registry offline, delete the filter. This works exactly the same for an attacker. That's the next chapter.",[10,30164,30166],{"id":30165},"attacks-that-never-touch-the-tile","Attacks that never touch the tile",[15,30168,30169],{},"Everything so far protects the tile. But the tile is only a DLL that Windows loads. Whoever controls how Windows starts doesn't have to talk to the tile at all. This chapter is about the person in front of the machine.",[126,30171,30173],{"id":30172},"safe-mode","Safe Mode",[15,30175,30176],{},"In Safe Mode Windows doesn't load third-party Credential Providers. Not our provider and not our filter. What's left is the normal password tile. Duo writes the same about their product: two-factor \"may be bypassed by restarting Windows into Safe Mode\".",[15,30178,30179],{},"And getting there is easy. You don't have to be logged in:",[172,30181,30182,30185,30188],{},[59,30183,30184],{},"On the logon screen hold Shift and click Restart in the power menu.",[59,30186,30187],{},"Troubleshoot → Advanced options → Startup Settings → Restart.",[59,30189,30190],{},"Press 4 for Safe Mode.",[15,30192,30193],{},"After that the password alone is enough. So everyone who knows the password and sits in front of the machine can skip the code. Please test this in your VM (test 18). It's better to see it yourself than to trust me.",[15,30195,30196],{},"A Credential Provider can't fix this, because in Safe Mode it doesn't run. What helps:",[56,30198,30199,30205,30214],{},[59,30200,30201,30204],{},[47,30202,30203],{},"BitLocker with TPM + PIN."," Every restart asks for the PIN before Windows starts. Someone who only knows the Windows password can't restart into Safe Mode, because they don't get past the PIN. BitLocker with TPM only doesn't help here. The TPM unlocks the disk automatically, also for Safe Mode.",[59,30206,30207,20524,30210,30213],{},[47,30208,30209],{},"Disable the Recovery Environment",[69,30211,30212],{},"reagentc \u002Fdisable",". The Startup Settings menu is part of WinRE, so Shift + Restart has nothing to offer anymore. The price: no automatic repair if Windows doesn't boot. Test it and keep a way back (installation media and your BitLocker recovery key).",[59,30215,30216,30219],{},[47,30217,30218],{},"A UEFI password"," and a fixed boot order, so nobody boots from a USB stick.",[15,30221,30222],{},"MITRE ATT&CK lists Safe Mode as its own technique (T1688). Ransomware uses it to start without the EDR. For us it means the same thing: a security component that only runs in normal mode doesn't run in Safe Mode.",[126,30224,30226],{"id":30225},"offline","Offline",[15,30228,30229,30230,20524,30233,30236],{},"With physical access and an unencrypted disk there are a lot of ways. Boot into WinRE or from a USB stick and delete the filter key, like in my recovery tip. Or replace ",[69,30231,30232],{},"utilman.exe",[69,30234,30235],{},"cmd.exe"," and get a SYSTEM shell on the logon screen. Or just copy the disk. None of this ever sees our tile.",[15,30238,30239,30240,30243],{},"Against all of this there is only one real answer: ",[47,30241,30242],{},"BitLocker",". With an encrypted disk, WinRE and a USB stick only see encrypted data. The command prompt in WinRE asks for the recovery key first. Without BitLocker this 2FA only protects against people who can't reboot the machine.",[126,30245,30247],{"id":30246},"the-clock","The clock",[15,30249,30250,30251,30253,30254,30257],{},"TOTP trusts the clock of the machine. In my first version this was a real attack: write down a code, turn the clock back in the BIOS, disconnect the network, boot and type the old code. The replay protection with ",[69,30252,1118],{}," closes this, because the old step is smaller than the last used one. What is left: someone who turns the clock ",[3290,30255,30256],{},"forward"," skips the lock. That's physical access again, and a UEFI password stops it.",[126,30259,30261],{"id":30260},"what-this-means","What this means",[15,30263,30264],{},"For a notebook that can be stolen, 2FA without BitLocker is decoration. With BitLocker (TPM + PIN), a UEFI password and WinRE under control, the attacks above don't work anymore. Then the 2FA protects what it is built for: the logon screen, at the console and over RDP.",[10,30266,30268],{"id":30267},"limits","Limits",[15,30270,30271],{},"This demo is a real 2FA, but only for one path. What it can't do:",[56,30273,30274,30280,30283,30289,30292,30295,30298,30301,30304,30307],{},[59,30275,30276,30277,30279],{},"Only the interactive logon and unlock are protected. Network logon, ",[69,30278,104],{},", scheduled tasks, remoting, WMI and UAC are not.",[59,30281,30282],{},"Safe Mode and offline access go around the provider completely. Without BitLocker (TPM + PIN) and a UEFI password the 2FA only protects against people who can't reboot the machine.",[59,30284,30285,30286,30288],{},"An admin can read the secret. The ACL only protects against normal users. And because of the machine scope of DPAPI, every copy of the ",[69,30287,8589],{}," hive (backup, shadow copy) is as good as the secret on this machine. The better solution would be a key in the TPM.",[59,30290,30291],{},"Anyone who reaches the tile can lock an account with 5 wrong codes. Leave NLA on for RDP, then this needs the password.",[59,30293,30294],{},"The lock counter is not atomic across parallel sessions. With several RDP sessions at the same moment an attacker gets one extra guess per session and lock.",[59,30296,30297],{},"The lock depends on the clock. Someone who sets the clock forward skips it. That needs physical access again.",[59,30299,30300],{},"The code comparison is not constant-time. With 6 digits this is not a real problem, but it would be cleaner.",[59,30302,30303],{},"If a user loses their phone, an admin has to enroll them again.",[59,30305,30306],{},"Only local accounts are supported. Domain and Microsoft accounts get no tile from our provider, so with the filter active they cannot log on interactively anymore.",[59,30308,30309],{},"On machines where Windows doesn't list local users (often domain joined ones), you only get the fallback tile with a username field.",[10,30311,30313],{"id":30312},"the-other-side","The other side",[15,30315,30316],{},"The same technique that I use for 2FA is also used by attackers. A malicious Credential Provider runs as SYSTEM on the logon screen and sees every password in plain text. MITRE ATT&CK lists this under T1556 (Modify Authentication Process).",[15,30318,30319],{},"That's why you should check which Credential Providers and filters are registered on your machines:",[148,30321,30323],{"className":23014,"code":30322,"language":23016,"meta":154,"style":154},"Get-ChildItem 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers'\nGet-ChildItem 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters'\n",[69,30324,30325,30333],{"__ignoreMap":154},[599,30326,30327,30330],{"class":601,"line":602},[599,30328,30329],{"class":949},"Get-ChildItem",[599,30331,30332],{"class":619}," 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers'\n",[599,30334,30335,30337],{"class":601,"line":613},[599,30336,30329],{"class":949},[599,30338,30339],{"class":619}," 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Provider Filters'\n",[15,30341,30342],{},"Save the list once and alert if something changes. And sign your own DLL. An unsigned DLL in LogonUI is exactly what your EDR should complain about.",[10,30344,30346],{"id":30345},"what-real-products-do-differently","What real products do differently",[15,30348,30349],{},"Most of the limits above have the same cause. The Credential Provider only sits in the UI, so it only sees the UI. If you want 2FA for all logon types, the check has to be in LSA. This is done with a custom authentication package or an SSP\u002FAP. AuthLite does exactly that.",[15,30351,30352],{},"Real products also don't do the check inside LogonUI. A central service makes the lock counter atomic, can keep the secret in the TPM and can ask a server, so there is one lock for all machines and not one per machine.",[15,30354,30355,30356,30358],{},"The LSA part is a lot more difficult. The code runs in ",[69,30357,162],{},", which is a Protected Process Light on a hardened system and has to work together with Credential Guard. If you have a bug there, you don't get an exception. LSA crashes and takes the whole machine with it.",[15,30360,30361],{},"Maybe I will try that in another article.",[15,30363,30364],{},"For now we have a working 2FA for local accounts that you can build and test yourself. And you know exactly what it protects and what not.",[30366,30367,30368],"style",{},"html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .s6RL2, html code.shiki .s6RL2{--shiki-default:#FDAEB7;--shiki-default-font-style:italic}",{"title":154,"searchDepth":623,"depth":623,"links":30370},[30371,30372,30373,30374,30380,30381,30384,30387,30388,30393,30397,30398,30399,30400,30404,30412,30413,30414,30420,30421,30422],{"id":12,"depth":613,"text":13},{"id":53,"depth":613,"text":54},{"id":81,"depth":613,"text":82},{"id":123,"depth":613,"text":124,"children":30375},[30376,30377,30378,30379],{"id":128,"depth":623,"text":129},{"id":142,"depth":623,"text":143},{"id":192,"depth":623,"text":193},{"id":271,"depth":623,"text":272},{"id":364,"depth":613,"text":365},{"id":558,"depth":613,"text":559,"children":30382},[30383],{"id":3324,"depth":623,"text":3325},{"id":5040,"depth":613,"text":5041,"children":30385},[30386],{"id":8672,"depth":623,"text":8673},{"id":8735,"depth":613,"text":8736},{"id":10449,"depth":613,"text":10450,"children":30389},[30390,30391,30392],{"id":10453,"depth":623,"text":454},{"id":10879,"depth":623,"text":10880},{"id":14674,"depth":623,"text":14675},{"id":20600,"depth":613,"text":20601,"children":30394},[30395,30396],{"id":20629,"depth":623,"text":20630},{"id":20704,"depth":623,"text":20705},{"id":21940,"depth":613,"text":21941},{"id":23094,"depth":613,"text":23095},{"id":24135,"depth":613,"text":24136},{"id":28630,"depth":613,"text":526,"children":30401},[30402,30403],{"id":28636,"depth":623,"text":28637},{"id":29039,"depth":623,"text":29040},{"id":29352,"depth":613,"text":29353,"children":30405},[30406,30407,30408,30409,30410,30411],{"id":29635,"depth":623,"text":29636},{"id":29642,"depth":623,"text":29643},{"id":29680,"depth":623,"text":29681},{"id":29716,"depth":623,"text":29717},{"id":29744,"depth":623,"text":29745},{"id":29864,"depth":623,"text":29865},{"id":29751,"depth":613,"text":29896},{"id":30129,"depth":613,"text":30130},{"id":30165,"depth":613,"text":30166,"children":30415},[30416,30417,30418,30419],{"id":30172,"depth":623,"text":30173},{"id":30225,"depth":623,"text":30226},{"id":30246,"depth":623,"text":30247},{"id":30260,"depth":623,"text":30261},{"id":30267,"depth":613,"text":30268},{"id":30312,"depth":613,"text":30313},{"id":30345,"depth":613,"text":30346},"windows","2026-09-30","How a Credential Provider works and how to build a working TOTP 2FA for local Windows accounts in C++. With rate limiting, replay protection and logging.",false,"md","\u002Fimages\u002Fposts\u002Fwindows-2fa-credential-provider\u002Fcover.webp",[30430],{"title":30431,"description":30432,"website":33,"image":30433},"Doppio on GitHub","The complete source code of this article. MIT licensed.","https:\u002F\u002Fgithub.githubassets.com\u002Fimages\u002Fmodules\u002Flogos_page\u002FGitHub-Mark.png",{},"\u002Fposts\u002Fwindows-2fa-credential-provider",{"title":5,"description":30425},"posts\u002Fwindows-2fa-credential-provider",[30423,30439,30440,558,30441],"credential-provider","2fa","security","S2ik4ijRdkFNhwjJgaYW5-TQ39Sy1qbZAOD0farI4E0",1790807807945]