{"id":93447,"date":"2016-05-12T07:00:00","date_gmt":"2016-05-12T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=93447"},"modified":"2019-03-13T11:02:58","modified_gmt":"2019-03-13T18:02:58","slug":"20160512-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160512-00\/?p=93447","title":{"rendered":"How come a duplicated token doesn&#8217;t behave identically to the original?"},"content":{"rendered":"<p>A customer was experimenting with tokens and discovered that things fall apart when they have a thread impersonate itself. Shouldn&#8217;t that have no effect? Here&#8217;s what they discovered. Error checking and cleanup have been elided for expository purposes. <\/p>\n<pre>\n\/\/ This call succeeds\nCComPtr&lt;IUnknown&gt; something;\nCoCreateInstance(CLSID_Something, nullptr,\n                 CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&amp;something));\n\n\/\/ Get the current token for the thread.\n\/\/ This call also succeeds. (Note that OpenThreadToken\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/junfeng\/archive\/2004\/03\/16\/90279.aspx\">fails if the thread is not impersonating<\/a>.)\nHANDLE token;\nOpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &amp;token);\n\n\/\/ Duplicate the token. This call succeeds.\nHANDLE dupToken;\nDuplicateToken(token, SecurityImpersonation, &amp;dupToken);\n\n\/\/ Impersonate the duplicate. This call succeeds.\nImpersonateLoggedOnUser(dupToken);\n\n\/\/ But now, CoCreateInstance fails with E_ACCESSDENIED!\nCComPtr&lt;IUnknown&gt; something2;\nCoCreateInstance(CLSID_Something, nullptr,\n                 CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&amp;something2));\n<\/pre>\n<p><a HREF=\"https:\/\/msdn.microsoft.com\/library\/windows\/desktop\/aa446616(v=vs.85).aspx\">The <code>Duplicate&shy;Token<\/code> function<\/a> says that the new token duplicates the original, but it does not appear to be a true duplicate because when we swap out the original thread token for the duplicate, things stop working. What&#8217;s going on? <\/p>\n<p>There are <a HREF=\"https:\/\/msdn.microsoft.com\/library\/windows\/desktop\/aa374909(v=vs.85).aspx\">a lot of things in a token<\/a>. But there&#8217;s something important that&#8217;s not in the token. <\/p>\n<p>One of my colleagues from the kernel team explains: When you duplicate a token with the <code>Duplicate&shy;Token<\/code> function, it creates a new kernel object, namely the token, and the new token is a duplicate of the original. But the new token has its own properties, and the important one here is the security descriptor. <\/p>\n<p>When a new kernel object is created, and you don&#8217;t provide an explicit security descriptor for the new object, then the object is given a default security descriptor. And that default security descriptor comes from the default DACL of the token that is in effect at the point of the call. <\/p>\n<p>When you apply this rule to tokens, you find that, even though the behavior is consistent with other kernel objects, it also means that it is very easy to create a token that doesn&#8217;t have access to itself. When you impersonate with that token, bad things happen. <\/p>\n<p>It&#8217;s like going to the FedEx Office store and giving them a DHL envelope with the instructions, &#8220;Please make a copy of this letter.&#8221; They take the letter out of the envelope, make a copy, and then take the copy and give it to you <i>in a FedEx Office envelope<\/i>. They copied the letter, like you instructed, but it&#8217;s in a different envelope. <\/p>\n<p>If you also want to duplicate the security descriptor, you can get the original token&#8217;s security descriptor with <code>Get&shy;Kernel&shy;Object&shy;Security<\/code> or <code>Get&shy;Security&shy;Info<\/code>, and then pass that security descriptor to <code>Duplicate&shy;Token&shy;Ex<\/code>. <\/p>\n<p>The customer confirmed that the recommendation worked. <\/p>\n<pre>\n\/\/ This call succeeds\nCComPtr&lt;IUnknown&gt; something;\nCoCreateInstance(CLSID_Something, nullptr,\n                 CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&amp;something));\n\n\/\/ Get the current token for the thread.\n\/\/ This call also succeeds. (Note that OpenThreadToken\n\/\/ fails if the thread is not impersonating.)\nHANDLE token;\nOpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &amp;token);\n\n<font COLOR=\"blue\">\/\/Get the security descriptor for the token.\n\/\/ This call succeeds.\nPACL dacl;\nPSECURITY_DESCRIPTOR sd;\nGetSecurityInfo(token, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,\n    nullptr, &amp;dacl, &amp;sd);\n\n\/\/ Duplicate the token with that security descriptor.\n\/\/ This call succeeds.\nSECURITY_ATTRIBUTES sa = { sizeof(sa), sd, TRUE };\nHANDLE dupToken;\nDuplicateTokenEx(token, MAXIMUM_ALLOWED, &amp;sa, SecurityImpersonation,\n    TokenImpersonation, &amp;dupToken);<\/font>\n\n\/\/ Impersonate the duplicate. This call succeeds.\nImpersonateLoggedOnUser(dupToken);\n\n\/\/ CoCreateInstance now succeeds.\nCComPtr&lt;IUnknown&gt; something2;\nCoCreateInstance(CLSID_Something, nullptr,\n                 CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&amp;something2));\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The inside&#8217;s the same, but the outside is different.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-93447","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The inside&#8217;s the same, but the outside is different.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93447","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=93447"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93447\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=93447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=93447"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=93447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}