{"id":96145,"date":"2017-05-11T07:00:00","date_gmt":"2017-05-11T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=96145"},"modified":"2019-03-13T01:11:21","modified_gmt":"2019-03-13T08:11:21","slug":"20170511-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170511-00\/?p=96145","title":{"rendered":"How to calculate the resulting security descriptor of a child object without creating it"},"content":{"rendered":"<p>The <code>Create&shy;Private&shy;Object&shy;Security<\/code> function is part of a family of functions intended for programs that implement security descriptors for their own custom objects. Normally, you would let the kernel object manager deal with security descriptors, but if your object isn&#8217;t a kernel object, then you have to do your own security management. These functions let you give your objects a security model that matches those of kernel objects. <\/p>\n<p>The <code>Create&shy;Private&shy;Object&shy;Security<\/code> function is one of the functions for assigning security descriptors to sub-objects. It understands the rules for &#8220;container inherit&#8221; and &#8220;inherit only&#8221; as well as the magic SIDs like &#8220;creator owner&#8221;. This is what your custom <code>Create&shy;Sub&shy;Object<\/code> function uses to generate the security descriptor for a new sub-object. <\/p>\n<p>But we can use it here to calculate the security descriptor that would be applied to a subdirectory. We pretend that we are the file system, managing our custom &#8220;directory&#8221; object. <\/p>\n<pre>\n  GENERIC_MAPPING fileGenericMapping = {\n    FILE_GENERIC_READ,\n    FILE_GENERIC_WRITE,\n    FILE_GENERIC_EXECUTE,\n    FILE_GENERIC_ALL,\n  };\n  PSECURITY_DESCRIPTOR childSd;\n  CreatePrivateObjectSecurity(\n    parentSd,   \/\/ ParentDescriptor\n    nullptr,    \/\/ CreatorDescriptor\n    &amp;childSd,   \/\/ NewDescriptor\n    TRUE        \/\/ IsDirectoryObject\n    nullptr,    \/\/ Token\n    &amp;fileGenericMapping); \/\/ GenericMapping\n  ...\n  DestroyPrivateObjectSecurity(childSd);\n<\/pre>\n<p>The <code>Create&shy;Private&shy;Object&shy;Security<\/code> gives you the security descriptor which results from the information you pass in: <\/p>\n<ul>\n<li>    The security descriptor of the parent object.     In our case, it&#8217;s the security descriptor of the     parent directory. <\/li>\n<li>    An optional custom security descriptor for the child object.     In our case, we pass <code>NULL<\/code>     to indicate that we want to inherit from the parent. <\/li>\n<li>    Whether the sub-object is itself a container.     The function uses this to decide whether     &#8220;container inherit&#8221; ACEs apply to the new object. <\/li>\n<li>    An optional token representing the user doing the creating.     This is used to set the owner and group on the resulting     security descriptor, as well as knowing what &#8220;creator owner&#8221;     ACEs should be converted to.     We pass <code>NULL<\/code> to say that the function should     use the current default token. <\/li>\n<li>    A <code>GENERIC_MAPPING<\/code> structure that specifies     how generic access bits should be converted.     Fortunately, the generic mapping for file system objects     <a HREF=\"https:\/\/msdn.microsoft.com\/library\/windows\/desktop\/aa364399(v=vs.85).aspx\">    is documented<\/a>,     and it even has convenient names that we can use. <\/li>\n<\/ul>\n<p>The theory is that this could be used to avoid the race condition when <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170223-00\/?p=95545\">creating a folder that inherits its parent&#8217;s ACL, and then overriding part of it<\/a>. That race condition exists in the period of time after the subdirectory is created with default attributes and before the program can apply the new seurity attributes. During that time, somebody might gain access to the directory in a form that would have been disallowed by your override. <\/p>\n<p>Using this technique, you can precalculate what the default attributes would be, then apply your custom override, and then pass those security attributes when you call <code>Create&shy;Directory<\/code>. This removes the race window where the subdirectory briefly has the wrong security attributes. <\/p>\n<p>Unfortunately, you have other problems. <\/p>\n<p>For one thing, you opened a different race condition: If the security attributes of the parent directory change, then you will apply those stale attributes to the subdirectory. <\/p>\n<p>But the worse thing is that I glossed over the hard part: getting the security descriptor of the parent directory. The <code>Create&shy;Private&shy;Object&shy;Security<\/code> function is intended to be used by the code that is managing security of its custom objects, so it has full access to all the security descriptors. But in this case, we are an outside operator, and getting access to that security descriptor may not be possible. We may not have <code>READ_CONTROL<\/code> access to the DACL. We may not have <code>ACCESS_SYSTEM_SECURITY<\/code> rights to read the SACL. <\/p>\n<p>So this idea sounded good on paper, but runs into problems in practice. Still, I mentioned it because it gives me an excuse to write about the <code>Create&shy;Private&shy;Object&shy;Security<\/code> function. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pretend that it&#8217;s a private object.<\/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-96145","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Pretend that it&#8217;s a private object.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96145","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=96145"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96145\/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=96145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=96145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=96145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}