为没有凭据的不同用户获取特殊文件夹
Get special folder for different user without credentials
我正在编写一个卸载程序,作为该过程的一部分,我想为所有本地用户清理缓存、临时文件等。该应用程序将 运行 提升以使其正常工作。
我要查找的文件位于 AppData\Local
等特殊文件夹中,因此我需要路径。对于当前登录的用户,这对 Environment.GetFolderPath
来说是微不足道的。但是,这不适用于其他用户。
根据 referencesource.microsoft.com,GetFolderPath
最终调用 SHGetFolderPath
,后者又包裹 SHGetKnownFolderPath
。这两个 Win32 API 都有一个可选的 hToken
参数,可以让我指定一个帐户令牌。
而且,确实,这会起作用:
private static string GetFolderPath(Guid knownfolderid, string user, string domain, string password)
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
SafeTokenHandle safeTokenHandle;
if (!LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
throw new System.Security.Authentication.InvalidCredentialException();
IntPtr pPath;
SHGetKnownFolderPath(knownfolderid,
0,
safeTokenHandle.DangerousGetHandle(),
out pPath);
string result = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
return result;
}
…但这对我的使用来说是不切实际的,当然——我不希望卸载某些东西的管理员必须知道并提供每个用户名和密码。
所以:
- 有没有办法在不需要知道用户凭据的情况下获得适当的访问令牌?
- 否则,是否有其他方法可以实现我的目标?从注册表中读取信息 seems unsafe,当然,硬编码文件夹名称也是如此。
假设修改应用程序以支持您的卸载程序还为时不晚,您可以在安装时在 ProgramData 中创建一个文件夹,然后每次您的应用程序启动时它都可以为当前用户写入一个文件包含相关目录 and/or 文件的路径。 (您甚至可以将其作为更新进行改造,尽管它不适用于在安装更新和卸载产品之间未登录的用户。)
您需要注意安全。非管理员用户应该只有 "create files" 访问该文件夹,该文件夹应设置为不可继承。这样他们就无法查看或操作彼此的文件。您可能还想为 CREATOR OWNER 分配可继承的完全访问权限。
您还需要验证保存的路径信息,而不是盲目相信它,否则恶意用户可能会让您的卸载程序删除错误的文件。我建议您检查您要删除的文件或文件夹是否属于包含保存的路径信息的文件的同一个人,如果不是,请寻求帮助。为了额外的安全,您的应用程序还可以标记它创建的文件,这些文件应该在卸载时删除,也许可以使用备用数据流。
我正在编写一个卸载程序,作为该过程的一部分,我想为所有本地用户清理缓存、临时文件等。该应用程序将 运行 提升以使其正常工作。
我要查找的文件位于 AppData\Local
等特殊文件夹中,因此我需要路径。对于当前登录的用户,这对 Environment.GetFolderPath
来说是微不足道的。但是,这不适用于其他用户。
根据 referencesource.microsoft.com,GetFolderPath
最终调用 SHGetFolderPath
,后者又包裹 SHGetKnownFolderPath
。这两个 Win32 API 都有一个可选的 hToken
参数,可以让我指定一个帐户令牌。
而且,确实,这会起作用:
private static string GetFolderPath(Guid knownfolderid, string user, string domain, string password)
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
SafeTokenHandle safeTokenHandle;
if (!LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
throw new System.Security.Authentication.InvalidCredentialException();
IntPtr pPath;
SHGetKnownFolderPath(knownfolderid,
0,
safeTokenHandle.DangerousGetHandle(),
out pPath);
string result = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
return result;
}
…但这对我的使用来说是不切实际的,当然——我不希望卸载某些东西的管理员必须知道并提供每个用户名和密码。
所以:
- 有没有办法在不需要知道用户凭据的情况下获得适当的访问令牌?
- 否则,是否有其他方法可以实现我的目标?从注册表中读取信息 seems unsafe,当然,硬编码文件夹名称也是如此。
假设修改应用程序以支持您的卸载程序还为时不晚,您可以在安装时在 ProgramData 中创建一个文件夹,然后每次您的应用程序启动时它都可以为当前用户写入一个文件包含相关目录 and/or 文件的路径。 (您甚至可以将其作为更新进行改造,尽管它不适用于在安装更新和卸载产品之间未登录的用户。)
您需要注意安全。非管理员用户应该只有 "create files" 访问该文件夹,该文件夹应设置为不可继承。这样他们就无法查看或操作彼此的文件。您可能还想为 CREATOR OWNER 分配可继承的完全访问权限。
您还需要验证保存的路径信息,而不是盲目相信它,否则恶意用户可能会让您的卸载程序删除错误的文件。我建议您检查您要删除的文件或文件夹是否属于包含保存的路径信息的文件的同一个人,如果不是,请寻求帮助。为了额外的安全,您的应用程序还可以标记它创建的文件,这些文件应该在卸载时删除,也许可以使用备用数据流。