• The Old New Thing

    Hacking the law: On the role of the marriage officiant in the State of Washington


    The role of the officiant in marriages in the State of Washington is kind of strange.

    For example, the wedding license is filled out in triplicate. One copy goes to the couty clerk. The second copy goes to Olympia, the state capital. The third copy goes to the officiant. But the law doesn't say what the officiant must do with that third copy. There is no law that requires the officiant to keep records of the weddings at which he or she has served as officiant, nor is there any law that requires the officiant to produce the copy of the license in case of a dispute. It's just given to the officiant with no strings attached.

    And then there's the issue of which people are qualified to act as officiants: In addition to the usual list of government officials, the law authorizes "any regularly licensed or ordained minister ... or similar official of any religious organization." Although the term "religious organization" is defined, the definition is broad enough that any organization can be a religious organization by simply claiming to be one, at which point it can nominate anyone it chooses as a minister.

    Okay, so basically anybody can serve as an officiant if they are willing to work at it.

    But suppose you find out years later that your minister was not properly ordained, or that he or she lied about his qualifications? No worries; the State of Washington has you covered there, too:

    RCW 26.04.060: Marriage before unauthorized cleric

    A marriage solemnized before any person professing to be a minister ... or similar official of any religious organization in this state ... is not void, nor shall the validity thereof be in any way affected [on these grounds], if such marriage be consummated with a belief on the part of the persons so married, or either of them, that they have been lawfully joined in marriage.

    So if your officiant turns out to have been unqualified, don't worry. The marriage is still valid. So much for that sitcom plot.

    Indeed, only one partner needs to believe that the marriage is valid in order for it to become so. One of the partners could knowingly hire a fake officiant, but as long as the other partner believes that the officiant is real, the marriage is still valid.

    But wait, it's even more than that. Neither party needs to believe in the officiant's legitimacy. They merely need to believe that the marriage is valid.

    Now things get circular.

    Suppose both partners convince themselves (by delusion, or mistaken understanding, or by reading the law quoted above) that they found a loophole that permits comedian Don Novello in the character Father Guido Sarducci to be an officiant at their wedding. The fact that they believe it to be true makes it true.

    The conclusion I draw from this is that the role of the officiant in weddings solemnized in the State of Washington is entirely perfunctory. The important thing is that the paperwork gets filed with the county and state.

  • The Old New Thing

    Calling ShutdownBlockReasonCreate from my service doesn't stop the user from shutting down


    A customer had a service application that needs to perform a sequence of operations that cannot be interrupted by a system shutdown.

    The service starts performing those operations when it starts up, but we found that group policy or other shenanigans can trigger other actions that ultimately lead to a system reboot. We would like to delay the reboot until our service completes its critical sequence of operations.

    We created a simple test application that calls Shutdown­Block­Reason­Create, and it works. If we try to reboot the computer, the shutdown dialog appears indicating that it is waiting for the test application to complete.

    We ported this code into the service, and even though the call succeeds, there is no message shown to the user at reboot, and the reboot proceeds anyway.

    Is Shutdown­Block­Reason­Create expected to work when called from a service? If so, then what we are doing wrong? If not, what alternative designs are available?

    Shutdown blocks apply only to the session in which they are created. This is sort-of implied by the fact that the Shutdown­Block­Reason­Create function is exported from user32.dll, and it takes a window handle parameter, and window handles are valid only in the desktop from which they were created. Since the interactive session is session 1 and services are in session 0, the block request has no effect. (This is just another application of the principle Does this work in a service? The default answer is NO.)

    Note also that the shutdown block is not a hard block. The user could click "Shut down anyway". Besides, the system assumes "Shut down anyway" if the user takes no action within some number of seconds.

    Note also that if the system is shut down remotely, there is nobody present to answer the question, and it's not clear where to display the message anyway.

    The correct way to delay shutdown indefinitely from a service is to set the SERVICE_ACCEPT_PRE­SHUTDOWN flag in its service status. This registers the service for preshutdown notifications, at which point it can finish up your critical actions before releasing shutdown to continue.

    Note that long shutdown times is one of the major points of end-user frustration, so you should do what you can to wrap things up quickly. Otherwise, you're going to be another data point in the "Windows sucks" database.

  • The Old New Thing

    If you can't remember the exact text of a dialog box (so you can search for it), you can ask the Internet


    Some time ago, I noted that If you're looking for the code that displays a particular dialog box, the most directly way to find it is to look for the dialog box. That works if you have a screen shot of the dialog box. But what if you don't?

    A colleague of mine wanted to find the code that displays the "Your password is going to expire soon" notification, but he didn't know what string to look for. It so happened that he asked me four hours too late, because my password happened to have expired that morning, but by the time he asked me for the text of the message, I had already changed my password.

    Think out of the box: You know who probably has a screen shot of the "your password is going to expire soon" notification? Somebody on the Internet.

    A Web image search quickly turned up the exact text.

  • The Old New Thing

    Why can't I create a file equal to the available disk space?


    A customer was trying to exercise some boundary cases in their application, one of which entailed "out of disk space" scenarios. The way they did this was very simple: Call Get­Disk­Free­Space­Ex to see how much disk space is available, and then create a file of that size. This worked on some volumes, but on other volumes, it failed with "Not enough disk space." Even after making sure no other programs were accessing the drive in question, the error persisted. Why?

    The amount of disk space required to create a file of a particular size is not exactly equal to the number of bytes in the file. After all, the file system also needs to remember the file name, the security attributes, various timestamps, and information to keep track of where on the disk all the bytes of the file are stored. And then there are the less obvious things like the change journal records to record that the file was created and object tracking records for link tracking.

    Just because your volume has exactly X bytes free doesn't mean that you will be able to create a file whose size is exactly X, because additional disk space will be needed to keep track of the metadata. If you want to fill a disk to the brim, you could start by filling it nearly to the brim, then growing the file until you get "Not enough disk space." If you want to get fancy, you could grow the file by large chunks until you can't add large chunks any more, and then switch to smaller and smaller chunks. You may also want to use the Set­File­Valid­Data function to avoid wasting time writing zeroes to all the sectors.

  • The Old New Thing

    The trust relationship between this workstation and the primary domain failed, what does this mean?


    Just like users, machines have domain accounts. And just like user accounts, machine accounts have passwords. And just like user account passwords, machine account passwords expire (by default, every 30 days). Now, you don't normally notice any of this because machines automatically change their machine account passwords before they expire.

    Well, you notice it when something gets messed up.

    One way you can trigger a password mismatch is to roll back a VM past a password change point. The machine will roll back to using the old password, which is not the correct password any more.

    Another way you can run into this is by leaving a machine off the network for a few months. The machine password on the domain will expire, and the machine will be locked out of the domain.

    If you get into this state, the standard solution is to leave the domain, and then rejoin it.

    Bonus reading: How to disable automatic machine account password changes. The article also describes why machine account passwords expire in the first place.

  • The Old New Thing

    What happens to lost timer messages if I don't process them fast enough?


    Some time ago, I noted that if your WM_TIMER handler takes longer than the timer period, your queue will not fill up with WM_TIMER messages. The WM_TIMER message is generated on demand, and if your handler doesn't check for messages, then there is no demand for timer messages. But what happens when your thread finally starts processing messages again? What happens to the timers that elapsed while you were busy? Do they accumulate?

    Here's a sketch of how timers work. (Note that the timers under discussion here are the timers set by the Set­Timer function.)

    When a timer is created, it is initially not ready.

    Every n milliseconds (where n is the period of the timer), the timer is marked ready. This is done regardless of the state of the UI thread. Note that ready is a flag, not a counter. If the timer is already ready, then it stays ready; there is no such thing as "double ready". The QS_TIMER flag is set on the queue state, indicating that there is now a pending timer for the thread. This in turn may cause a function like Get­Message or Msg­Wait­For­Multiple­Objects to wake up.

    When the appropriate conditions are met (as discussed earlier), the window manager checks whether there are any timers for the thread that are marked ready. If so, then the corresponding WM_TIMER message is generated and the ready flag is cleared.

    Let's illustrate this with our scratch program. Make the following changes:

    #include <strsafe.h>
    DWORD g_tmStart;
    void SquirtTime()
     TCHAR sz[256];
     StringCchPrintf(sz, 256, "%d\r\n", GetTickCount() - g_tmStart);

    This adds a function that prints the number of milliseconds which have elapsed since g_tmStart. Note that we use simple subtraction and rely on unsigned arithmetic to handle timer rollover issues.


    Our timer tick handler merely prints the elapsed time to the debugger.

    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
     g_tmStart = GetTickCount();
     SetTimer(hwnd, 1, 500, OnTimer);
     return TRUE;

    Finally, we create a 500ms timer on our window, but we also intentionally stall the thread for 1750ms.

    Can you predict the output of this program?

    Here's what I got when I ran the program:


    Let's see if we can explain it.

    Since the timer is set to fire at 500ms intervals, every 500ms, the timer gets marked ready.

    • At T = 500ms, the timer is marked ready.
    • At T = 1000ms, the timer is marked ready. This is redundant, since the timer is already ready.
    • At T = 1500ms, the timer is marked ready. Again, this is redundant.
    • At T = 1750ms, the program finally wakes up from its Sleep and eventually gets around to processing messages.
    • Hey look, there is a ready timer, so we generate a WM_TIMER message and clear the ready flag.
    • At T = 1797ms, the timer message is processed.
    • The program returns to its message loop, where there are no further messages to process, so it sits and waits.
    • At T = 2000ms, the timer is marked ready. This causes the Get­Message to wake up generate a WM_TIMER message and clear the ready flag.
    • At T = 2000ms, the timer message is processed.
    • At T = 2500ms, the timer is marked ready. This causes the Get­Message to wake up generate a WM_TIMER message and clear the ready flag.
    • At T = 2500ms, the timer message is processed.
    • And so on, with a new timer message every 500ms that is processed immediately.

    Observe that when the program begins processing messages at T = 1750ms, it receives only one timer message right away, even though three timer periods have elapsed.

    I guess another way of looking at this is to think of your timer as setting a frame rate. If your thread is busy when it's time to render the next frame, then the next frame is late. And if your thread is really busy, it may drop frames entirely.

  • The Old New Thing

    Why doesn't my keyboard hook get called for keyboard messages I manually posted?


    A customer was generating synthesized keyboard input by posting WM_KEY­DOWN and related messages to a window. They found that a WH_KEYBOARD keyboard hook was not triggering for these keyboard messages and they wanted to know why.

    You already know enough to answer this question, though the pieces are scattered about over several years for you to put together.

    First of all, you can't simulate keyboard input with Post­Message because you are going straight to the end product without going through the other paperwork that leads to that end product.

    It's like sending a letter to a friend by putting it directly in his mailbox, and then saying, "My friend filed a change of address with the postal service, and anything sent to his address is supposed to be redirected to his new address, but my letter is still sitting in his mailbox at his old address." Well, yeah, because you didn't actually mail the letter. You bypassed the mail system and merely replicated the end product (a letter in the mailbox). You will also find that if you go to the postal service's Web site and ask for a delivery confirmation of the letter, the Web site is going to say, "Sorry, we have no record of having delivered that letter to that mailbox."

    The window manager does not have a fake message detector that looks to see if you posted a fake input message, and if so, reverse-engineers the logic that led to that fake input message and internally simulates the actions of that reverse-engineered logic. If you post a WM_CHAR message, it's not going to say, "Well, let me see, to get to that message, the user needed to have pressed the Shift key, then pressed the A key, then released the A key, then released the Shift key, so I'll retroactively send out WH_KEYBOARD hook notifications for those events, and if any of the hooks blocks the event, then I created a time paradox, and I have to go back in time and kill the program that posted the WM_CHAR message." (It's also not going to insert the posted message in the processing queue in the correct order relative to true input messages.)

    If you want to simulate input, you need to send it through the input system with functions like Send­Input.

  • The Old New Thing

    How do I call SetTimer with a timer ID that is guaranteed not to conflict with any other timer ID?


    Suppose you want to create a timer for a window, but you don't know what timers that window already has running. You don't want your timer to overwrite any existing timer, so you need to find a unique ID for your timer. If this were for a window message, you could use Register­Window­Message, but there is no corresponding Register­Timer­Id function. How do you generate a unique timer ID?

    Every window gets to decide how to assign its own timer IDs, which are 32-bit integers on 32-bit Windows or 64-bit integers on 64-bit Windows. If you are an outsider, then you will have to negotiate with the window for a timer ID. There is no standard for this, so you will have to talk to whoever wrote the code for the window and come to some sort of agreement. "Okay, Bob, I'll let you have timers in the range 1000 to 1999."

    But what if you don't personally know the person who wrote the code for the window, and the documentation for the window class does not specify how to negotiate a timer ID?

    If you don't have a way to negotiate a timer ID for a window, then just create your own window and put your timer there. Since you created your own window, you control the window class, and you can set the rules for how timer IDs are assigned for that window class.

    It's hardly a coincidence that the timer ID space is the same size as the address space. You can allocate some memory to track the timer (you probably have already done this), and use the address of that memory as the timer ID. Another common design is to use the handle to the object associated with the timer as the timer ID.

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Elevation from Administrator to SYSTEM


    A security vulnerability report arrived that took the following form:

    I have discovered a critical security vulnerability in Windows which I intend to present at the XYZ conference. It allows any user with administrator privileges to perform operation Q, something that should be available only to SYSTEM.

    I think you know how this story ends. If you have administrator privileges, then you are already on the other side of the airtight hatchway. That you can use administrator privileges to pwn the machine is not interesting, because by virtue of being an administrator you already pwn the machine.

    There is formally a distinction between Administrator and SYSTEM, seeing as they are some things which are ACL'd so that SYSTEM can do them and not arbitrary adminitrators, but that distinction is formal and not practical. An administrator who wanted to get some code running as SYSTEM could install a service that runs as SYSTEM. Or use Debug Privilege to take over a process (say, a service) running as SYSTEM. Or simply open a command prompt as SYSTEM and go to town. No need to go through the complex operation Q to get SYSTEM access.

    So yes, a user with administrator privileges can use operation Q to do things that are normally limited to SYSTEM. But so what? Users with administrator privileges already have plenty of easier ways of doing things that are normally limited to SYSTEM. The distinction between the SYSTEM and Administrator accounts is a roadblock to make it harder to mess up your system by mistake. You can still mess up your system, but you have to try harder.

    Before dismissing these reports, you have to verify that the attack is effective only against the current machine. In other words, that obtaining administrator privileges on the computer gets you nothing more than administrator privileges on the computer. And in this case, that was true. The attack described gives the user access to the local machine, but had no effect on other machines.

  • The Old New Thing

    Thanks for informing us that you know about the compatibility issue in your application, so we don't have to fix it


    During the public prerelease period of a version of Windows some time ago, I remember a bug came in from an application developer. It went something like this:

    Hi, we just tried our program on the most recent public prerelease version of Windows, and we noticed that you changed the undocumented XYZ function. Our program uses that undocumented function, and your change to the function breaks us. can you change it back? Yes, we understand that there are no guarantees surrounding the use of undocumented APIs, but still we'd like you to continue supporting the old version. It should just be a few dozen lines of code on your side.

    How very nice of the application vendor to identify their compatibility issues for us. Now we don't need to create a compatibility shim, because not only do we know that the application vendor is still actively supporting the program in question, but that they have already been alerted to the problem with plenty of advance warning for them to issue a patch to their customers before the next version of Windows is released.

    The product team rejected this change request with the simple comment, "Unsupported APIs are unsupported." Presumably the customer liaison translated this into something a bit more polite before communicating it back to the vendor.

Page 1 of 460 (4,594 items) 12345»