Forcing a file handle closed when it has been opened remotely


Today's Little Program closes a file handle that was opened remotely. It builds on previous discussion on how to use the Net­Xxx functions.

int __cdecl wmain(int argc, wchar_t **argv)
{
 FILE_INFO_3 *pinfo3;
 NET_API_STATUS status;
 DWORD_PTR resumeHandle = 0;
 do {
  DWORD actual, estimatedTotal;
  status = NetFileEnum(NULL, NULL, NULL, 3,
                       (LPBYTE*)&pinfo3,
                       MAX_PREFERRED_LENGTH,
                       &actual,
                       &estimatedTotal,
                       &resumeHandle);
  if (status == NERR_Success ||
      status == ERROR_MORE_DATA) {
   for (DWORD i = 0; i < actual; i++) {
    if (lstrcmpiW(argv[1], pinfo3[i].fi3_pathname) == 0) {
     wprintf(L"Closing %ls result %d\n", pinfo3[i].fi3_pathname,
             NetFileClose(NULL, pinfo3[i].fi3_id));
     status = ERROR_NO_MORE_FILES;
     break;
    }
   }
   NetApiBufferFree(pinfo3);
  }
 } while (status == ERROR_MORE_DATA);
 return 0;
}

Forcing a network file handle closed does not actually close the handle. This makes it very different from the various "force handle closed" utilities out there. Rather, forcing a network file handle closed is accomplished by simulating a network failure, so that when the remote machine tries to use the handle again, it's told, "Wha? I'm sorry, we must have a bad connection, because I'm not sure what you're talking about." Since programs which access network resources must deal with the possibility of network connectivity loss, this deception does not violate the interface contract.

(Doing this to handles to local resources is a much riskier undertaking, because applications expect access to local files to remain valid for the lifetime of the handle. There is no equivalent of transient network connectivity failure for local files on non-removable drives. There is also no API for simulating it.)

Comments (23)
  1. John Doe says:

    You should call NetApiBufferFree only in the success and the "more data" cases (e.g. inside the if). Unless there's something you know that can't be read in the documentation.

    [Fixed. Thanks. -Raymond]
  2. Ben says:

    I had used these "force handle close" utilities back in the past, oblivious to the incredible danger. Just how invasive are these programs? Should it be harder for an application to do this to another? Process Explorer tells me "Forcing a handle closed can lead to an application crash and system instability", but this seems quite mild compared to "may cause random corruption of your data". Should process explorer have a better warning?

    [There are two types of "forcing handles closed". One is forcing a Close­Handle, which is horribly dangerous. The other is disconnecting the handle from the underlying medium, which is what we're doing here, and which means that the handle goes into a permanent error state (but it's still a valid handle). How dangerous that is depends on how well the app recovers from I/O errors. -Raymond]
  3. A person says:

    The warning should probably be "Forcing a handle closed is bad and you should feel bad."

  4. Forcing a handle closed is like playing Russian Roulette, it is just a matter of time…

  5. Nick says:

    When a handle to a network file is "disconnected", is there any mediation taken by the filesystem to attempt to "reconnect" the handle later on once the resource is available again? Say that I have a file open on a Windows networked drive and I unplug the cable — if the handle enters this state, is it entirely up to the application to restore the handle, or will the OS assist (for example, on the next ReadFile)?

    One reason I ask is that when I was a sysadmin I would need to restart our Windows file servers after installing updates. I always wondered how disruptive that was to users that (for example) left a Word document open overnight. Obviously all the state on the server was lost, but it seemed like the clients might be able to reconnect and continue where they left off. The main problem I presume is that any file sharing access has been blown away, and that goes double for files with unsaved modifications.

    I looked around online at one point, but couldn't find a good answer to this.

    [The automatic reconnection happens at the virtual circuit level. You cannot safely reconnect after the server timed out the connection, because during the interim, the original assumptions may have been violated. E.g. the app opened a file in deny-write mode, then the connection is lost, and the server declares the client dead. The file is now closed on the server, and somebody else can modify it. If the client reconnects and says, "Sorry, I lost connectivity for a little while. Can you get things back the way they were?" the server will say "Sorry, no can do." If you force the file closed on the server, then the answer will always be "Sorry, no can do." -Raymond]
  6. Joshua says:

    @Crescens2k: If the issue ever comes up for me again, I'll build that tool that replaces the closed handle with a handle to NUL so CreateFile doesn't reissue it.

    [The problem then is that the app doesn't get any errors, so it thinks the data got written successfully when in fact it was all thrown away. -Raymond]
  7. Joshua says:

    [The problem then is that the app doesn't get any errors, so it thinks the data got written successfully when in fact it was all thrown away. -Raymond]

    Not if I open the handle with access mask 0.

  8. Silly says:

    > forcing a Close­Handle, which is horribly dangerous

    Unless you're Chuck Norris. Any application that even dreams of misbehaving when Chuck Norris forces any of its handles closed better wake up and apologise. </obligatory>

  9. Is it possible to do this with .NET API too? I mean without cheating and importing Win32 functions.

  10. Random832 says:

    Is there any situation in which forcing a [local] handle closed is a better idea than terminating the process? If not, why do these tools exist?

  11. John Doe says:

    @Random832, so you can sh0wz ur l33t sk1lz.

  12. Danny says:

    Yeah blah. Look, I got problems with handles in XP. First thing I do is download and install Unlocker, it gives you also a nice GUI interface on who still has handles to the file you can't delete. Try this, create a file, write something in it, keep it open in Notepad, run Unlocker. It will show it's only Notepad who got handles open to that file. Now, while still opened go Win+E and delete it (or try actually). Zbang, Monsieur Exploiter whines it can't delete. Fine, now go and close Notepad and good luck deleting the file from Exploiter. And if you run Unlocker it will show that the only handles opened to that file belongs to Explorer only. And funny thing is, as long as you keep it open in Notepad, each time you try to delete it another handle is opened by Explorer to that file. So, like I said, blah on your 2009 rant on "stoled and replaced bags" Ray. The reason these utilities are a necessity is because of the above scenario. Once I force close the handles I can delete the file just fine and Explorer will run nicely. And this is a nuisance only in XP, because in 7 you guys seems to corrected this "behavior" (let's not use the word "bug"). Now, once I close the file in Notepad I can delete it just fine from Explorer afterwards. Don't know when this was corrected because I jumped from XP to 7 directly (sorry 2003, Vista and 2008, you don't exist for me or my clients).

  13. Killer{R} says:

    //There is also no API for simulating it

    You provocating me.. I can't resist this.. ;(

    So, while there'is no InvalidateHandleApi, there'is DuplicateHandle. And SuspendThread (and sith' know how to do same for process with same easy manner). So.. Suspend victim, and while he'is under anaesthesia – ablate neccessary handle with DuplicateProcess(…DUPLICATE_CLOSE_SOURCE..).. and dont forget to put an implant – duplicate useless file handle (no read, no write, no animal, no plants..) handle instead of initial one: repeat DuplicateHandle until handle value matches.. After it matched – remove unneccessary implants.. Now its time to awake patient, and hope he will survive..

  14. Gabe says:

    Random832: One use case for closing a handle is when you have a major app (or worse yet, a server you can't restart) that has a handle leak.

    Let's say your IDE has a problem where the built-in debugger opens a handle to your EXE and forgets to close it when you're done debugging. Since there is an open handle to your EXE, you can't compile anymore until you either close your IDE or close the handle. Considering the enormous hassle of closing and opening your IDE versus the easr of simply closing a handle, I'd say this is a very good use case.

  15. Gabe says:

    Random832: One use case for closing a handle is when you have a major app (or worse yet, a service you can't restart) that has a handle leak.

    Let's say your IDE has a problem where the built-in debugger opens a handle to your EXE and forgets to close it when you're done debugging. Since there is an open handle to your EXE, you can't compile anymore until you either close your IDE or close the handle. Considering the enormous hassle of closing and opening your IDE versus the easr of simply closing a handle, I'd say this is a very good use case.

    Another time I had a service that leaked a handle. Since it was hosted in a process with many other services, closing the handle was the only way to fix it short of restarting all the other services (and their dependencies) in the same host process.

  16. alegr1 says:

    @Danny:

    It's because you have some buggy extension loaded to your Explorer.

  17. Danny says:

    @alegr1 – dude, first try it on XP then post, ok? It's a "thing" XP explorer does, right from the start – do you need a dropbox link to a empty vmware xp machine? or you feel knowledgeable enough to make one yourself?

  18. ChrisR says:

    @Danny: You sound like a whiny child.  Regardless, I have just tried your test (on XP SP3), and Notepad does not even hold an open handle to the file.  Explorer then has no problem deleting it while it is open in Notepad.

  19. Rick C says:

    @Danny,

    Also, the guy's name is Raymond, not Ray.  It's not as if he doesn't sign every comment he edits.  Why do you feel the need to change his name?  Would you like it if someone came in and crapped all over your living room?

  20. Marc says:

    Say I have a process to update files on a remote machine that I have admin access to and want to kill handles to those files before overwrite. I do not necessarily have admin access to other machines that have handle locks (e.g. someone is running a program in that folder from the network from some other machine). This NetFileClose API call doesn't do the "network connectivity loss" thing so the handle can be re-obtained seamlessly from what I can tell. Is there some way via Win32 api (or otherwise) to remotely cause that "network connectivity loss"?

    [The handle obviously cannot be recovered seamlessly because you changed the file! Imagine if one of the handles you disconnected was "deny write". -Raymond]
  21. Marc says:

    Sorry I mean that if someone is running the program from the network and I terminate the handles using these API methods, I didn't think the user of the app from the remote machine would notice at all. Windows seems to recover from the handles being closed in this scenario and the program continues to function without the user seeing that the handles were severed?

  22. Marc says:

    "The handle obviously cannot be recovered seamlessly because you changed the file!"

    Sorry to clarify – I was thinking more from the angle of "how can I prevent or reduce the probability a process will re-obtain a handle quickly/automatically before I am able to complete my redeployment"… so when I was referring to "recovered seamlessly", I meant from the perspective of handles to the files preventing update, not so much attempts to obtain handles to files that actually have been updated. In that situation, crashing the app is not an issue (we don't mind that).

    [I guess I don't understand the question. If the handle is forced closed on the server, then it is unrecoverable. A handle is recoverable if the client loses connectivity, then regains connectivity before the server forces the handle closed due to loss of communication. -Raymond]
  23. Joshua says:

    I understand Marc's question. He wants to replace the file while leaving the handles open (let's say for argument it's read only from the clients' perspective). Unfortunately, unless the file is designed like a database (in which case there is an API to update in place), trying to do this will surely blow it up as the handle carries file offsets which will now be in the middle of records.

Comments are closed.