{"id":91891,"date":"2015-10-29T07:00:00","date_gmt":"2015-10-29T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151029-00\/?p=91891\/"},"modified":"2019-03-13T12:21:10","modified_gmt":"2019-03-13T19:21:10","slug":"20151029-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20151029-00\/?p=91891","title":{"rendered":"When you open a securable object, make sure you pass the security mask you actually want (no more, no less)"},"content":{"rendered":"<p>There are two categories of &#8220;Access denied&#8221; errors. One occurs when you attempt to create the handle, and the other occurs when you attempt to use the handle. <\/p>\n<pre>\nHANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT(\"<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/10\/01\/10561544.aspx\">MyEvent<\/a>\"));\n<\/pre>\n<p>If this call fails with <i>Access denied<\/i>, then it means that you don&#8217;t have access to the object to the level you requested. In the above example, it means that you don&#8217;t have <code>SYNCHRONIZE<\/code> access to the event. <\/p>\n<p>A common reason for getting an <i>Access denied<\/i> when trying to create a handle is that you asked for too much access. For example, you might write <\/p>\n<pre>\n<i>HKEY hkey;\nLONG lError = RegOpenKeyEx(\n    hkeyRoot, subkeyName, 0, KEY_ALL_ACCESS, &amp;hkey);\nif (lError == ERROR_SUCCESS) {\n DWORD dwType;\n DWORD dwData;\n DWORD cbData = sizeof(dwData);\n lError = RegQueryValueEx(hkey, TEXT(\"ValueName\"), nullptr,\n                          &amp;dwType, &amp;dwData, &amp;cbData);\n if (lError == ERROR_SUCCESS &amp;&amp; dwType == REG_DWORD &amp;&amp;\n     cbData == sizeof(dwData)) {\n  .. do something with dwData ..\n }\n RegCloseKey(hkey);\n}<\/i>\n<\/pre>\n<p>The call to <code>Reg&shy;Open&shy;Key&shy;Ex<\/code> fails with <i>Access denied<\/i>. The proximate reason is that you don&#8217;t have <code>KEY_ALL_ACCESS<\/code> permission on the registry key, which makes sense because <code>KEY_ALL_ACCESS<\/code> asks for <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/02\/27\/7912126.aspx\">permission to do <i>everything imaginable<\/i> to the registry key<\/a>, including crazy things like &#8220;Change the permissions of the key to deny access to the rightful owner.&#8221; <\/p>\n<p>But why are you asking for full access to the key if all you&#8217;re going to do is read from it? <\/p>\n<pre>\nHKEY hkey;\nLONG lError = RegOpenKeyEx(\n    hkeyRoot, subkeyName, 0, <font COLOR=\"blue\">KEY_READ<\/font>, &amp;hkey);\nif (lError == ERROR_SUCCESS) {\n DWORD dwType;\n DWORD dwData;\n DWORD cbData = sizeof(dwData);\n lError = RegQueryValueEx(hkey, TEXT(\"ValueName\"), nullptr,\n                          &amp;dwType, &amp;dwData, &amp;cbData);\n if (lError == ERROR_SUCCESS &amp;&amp; dwType == REG_DWORD &amp;&amp;\n     cbData == sizeof(dwData)) {\n  .. do something with dwData ..\n }\n RegCloseKey(hkey);\n}\n<\/pre>\n<p>If you want to go for bonus points, ask for <code>KEY_QUERY_VALUE<\/code> instead of <code>KEY_READ<\/code>, since all you are going to do with the key is read a value. <\/p>\n<blockquote CLASS=\"m\"><p>When requesting access to an object, it&#8217;s best to ask for the minimum access required to get the job done. <\/p><\/blockquote>\n<p>This is like the old principle of mathematics: After you&#8217;ve proved something, try to weaken the hypothesis as much as possible and strengthen the conclusions as much as possible. In other words, once you&#8217;ve solved a problem, figure out the absolute minimum requirements for your solution to work, and figure out the largest amount of information your solution produces. <\/p>\n<p>On the other hand, if you get an <i>Access denied<\/i> error when trying to <u>use<\/u> a handle, then the problem is that you didn&#8217;t open the handle with <i>enough<\/i> access. <\/p>\n<pre>\n<i>HKEY hkey;\nLONG lError = RegOpenKeyEx(\n    hkeyRoot, subkeyName, 0, KEY_READ, &amp;hkey);\nif (lError == ERROR_SUCCESS) {\n DWORD dwData = 1;\n lError = RegSetValueEx(hkey, TEXT(\"ValueName\"), nullptr,\n             REG_DWORD, (const BYTE*&gt;)&amp;dwData, sizeof(dwData));\n if (lError == ERROR_SUCCESS &amp;&amp; dwType == REG_DWORD &amp;&amp;\n     cbData == sizeof(dwData)) {\n  .. do something with dwData ..\n }\n RegCloseKey(hkey);\n}<\/i>\n<\/pre>\n<p>Here, the <code>Reg&shy;Open&shy;Key&shy;Ex<\/code> succeeds, but the <code>Reg&shy;Set&shy;Value&shy;Ex<\/code> fails. That&#8217;s because the registry key was opened for <code>KEY_READ<\/code> access, but the <code>Reg&shy;Set&shy;Value&shy;Ex<\/code> operation requires <code>KEY_SET_VALUE<\/code> access. To fix this, you need to open the key with the access you actually want: <\/p>\n<pre>\nHKEY hkey;\nLONG lError = RegOpenKeyEx(\n    hkeyRoot, subkeyName, 0, <font COLOR=\"blue\">KEY_SET_VALUE<\/font>, &amp;hkey);\nif (lError == ERROR_SUCCESS) {\n DWORD dwData = 1;\n lError = RegSetValueEx(hkey, TEXT(\"ValueName\"), nullptr,\n             REG_DWORD, (const BYTE*&gt;)&amp;dwData, sizeof(dwData));\n if (lError == ERROR_SUCCESS &amp;&amp; dwType == REG_DWORD &amp;&amp;\n     cbData == sizeof(dwData)) {\n  .. do something with dwData ..\n }\n RegCloseKey(hkey);\n}\n<\/pre>\n<blockquote CLASS=\"m\"><p>When requesting access to an object, it&#8217;s best to ask for the minimum access required to get the job done, <u>but no less<\/u>. <\/p><\/blockquote>\n<p>Armed with this information, you can solve this problem: <\/p>\n<blockquote CLASS=\"q\">\n<p>In the main thread, we create an event like this: <\/p>\n<pre>\nTheEvent = CreateEvent(NULL, TRUE, FALSE, name);\n<\/pre>\n<p>A worker thread opens the event like this: <\/p>\n<pre>\nEventHandle = OpenEvent(SYNCHRONIZE, FALSE, name);\n<\/pre>\n<p>The <code>Open&shy;Event<\/code> succeeds, but we try to use the handle, we get <i>Access denied<\/i>: <\/p>\n<pre>\nSetEvent(EventHandle);\n<\/pre>\n<p>On the other hand, if the worker thread uses the <code>Create&shy;Event<\/code> function to get the handle, then the <code>Set&shy;Event<\/code> succeeds. <\/p>\n<p>What are we doing wrong? <\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>You will get all you want, but you have to ask for it.<\/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-91891","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You will get all you want, but you have to ask for it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91891","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=91891"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91891\/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=91891"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=91891"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=91891"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}