[Windows] Fix certbot renew task failure under NT AUTHORITY\SYSTEM account (#7536)

Turned out that the scheduled task that runs `certbot renew` twice a day, is failing. Without any kind of log of course, otherwise it would not be fun.

It can be revealed by opening a powershell under the `NT AUTHORITY\SYSTEM` account, under which the scheduled task is run. Under theses circumstances, the bug is revealed: Certbot breaks when trying to invoke `certbot.compat.filesystem._get_current_user()`. Indeed the logic there implied to call `win32api.GetUserNameEx(win32api.NameSamCompatible)` and this function does not return always a useful value.

For normal account, it will be typically `DOMAIN_OR_MACHINE_NAME\YOUR_USER_NAME` (e.g. `My Machine\Adrien Ferrand`). But for the account `NT AUTHORITY\SYSTEM`, it will return `MACHINE_NAME\DOMAIN$`, which is a nonsense and makes fail the resolution of the actual SID of the account at the end of `_get_current_user()`.

This PR fixes this behavior by using an explicit construction of the account name that works both for normal users and `SYSTEM`.

* Use a different way to resolve current user account, that works both for normal users and SYSTEM.

* Add a comment to run Certbot under NT AUTHORITY\SYSTEM
This commit is contained in:
Adrien Ferrand
2019-11-13 09:43:50 -08:00
committed by Brad Warren
parent c26d459d0f
commit 75acdeb645
+5 -1
View File
@@ -588,7 +588,11 @@ def _get_current_user():
"""
Return the pySID corresponding to the current user.
"""
account_name = win32api.GetUserNameEx(win32api.NameSamCompatible)
# We craft the account_name ourselves instead of calling for instance win32api.GetUserNameEx,
# because this function returns nonsense values when Certbot is run under NT AUTHORITY\SYSTEM.
# To run Certbot under NT AUTHORITY\SYSTEM, you can open a shell using the instructions here:
# https://blogs.technet.microsoft.com/ben_parker/2010/10/27/how-do-i-run-powershell-execommand-prompt-as-the-localsystem-account-on-windows-7/
account_name = r"{0}\{1}".format(win32api.GetDomainName(), win32api.GetUserName())
# LookupAccountName() expects the system name as first parameter. By passing None to it,
# we instruct Windows to first search the matching account in the machine local accounts,
# then into the primary domain accounts, if the machine has joined a domain, then finally