【问题标题】:Is there a human-readable Windows user account ID that maps 1:1 with SID?是否存在与 SID 1:1 映射的可读 Windows 用户帐户 ID?
【发布时间】:2020-12-02 19:37:02
【问题描述】:

我需要在各个进程之间传递唯一的 Windows 用户帐户标识符(在运行 Windows 10 x64 1803 或更高版本的单台计算机范围内是唯一的)。

帐户的 SID 是自然选择,但不透明的 ID 会使调试变得痛苦,所以我更喜欢将 1:1 映射到 SID 的 人类可读

我最初只尝试了登录名(例如“Rosalyn”)。我可以将其映射回正确的 SID,但由于某种原因在不同的用户帐户下运行时我使用的映射方法不起作用(请参阅下面的编辑)。

Windows 使用至少两种其他形式的用户帐户 ID:

  • username@somedomain.com
  • 域\用户名

...但是这些让我有点紧张;文档提到并非所有用户都拥有的环境(例如 LDAP、域、目录服务等)。这必须适用于所有用户,无论他们是在家中还是在公司环境中。

有没有人遇到过这种情况?如果在某处有关于如何来回映射的文档,则可以加分。

编辑

...但是由于某种原因,在不同的用户帐户下运行时,我使用的映射方法不起作用。

你能解释一下原因吗? – 奋斗太阳 - MSFT

// Get the SID for this user
try
{
    var ntAccount = new NTAccount(logonUser); // e.g. logonUser = "Scott"
    return (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier));
}
catch (Exception)
{
    Trace.WriteLine($"Unable to get SID for {logonUser}", "ERROR");
    throw;
}

以登录用户身份运行时,此代码返回正确的 SID (S-1-5-21-4275680301-1639116052-1993100807-1001),但在 SYSTEM 帐户下运行时,给定相同的登录用户,此代码返回本地系统的 SID (S-1-5-18)。

我认为登录用户名可能不合格,所以我尝试了"<user-domain-name>\<user-name>""<machine-name>\<user-name>",但无论我使用的帐户是什么,这些都不起作用。

另外,使用 UserDomainName 之类的东西让我有点紧张,因为我选择的任何方法都必须适用于所有用户,无论他们的环境如何(家庭或公司 LAN)。这是一个对我知道的事情感到不安的情况......

【问题讨论】:

  • 按原样使用 sid。你需要独特的但不是人类可读的
  • @RbMm - 是的,我不需要需要人类可读的。对人类可读性的渴望源于过去在调试过程中必须一遍又一遍地查找 GUID 和其他不透明 ID 的经验。
  • ... but the mapping method I used didn't work when running under a different user account for some reason.你能解释一下原因吗?
  • 当用户对象从一个域移动到另一个域时,必须为用户帐户生成一个新的 SID 并将其存储在 ObjectSID 属性中。当用户登录并成功通过身份验证时,域身份验证服务会在 Active Directory 中查询与用户关联的所有 SID,包括用户的当前 SID、用户的旧 SID 和用户组的 SID。参考:Security identifiers
  • @StriveSun-MSFT - 我已经编辑了上面的问题。

标签: windows winapi windows-identity


【解决方案1】:

您可以使用LookupAccountNameA 获取 sid。

LookupAccountName 函数接受系统名称和 帐户作为输入。它检索安全标识符 (SID) 帐户以及在其中找到该帐户的域的名称。

并且使用这个api不需要在LocalSystem账户的上下文中运行。

代码示例:(C++)

#include <Windows.h>
#include <Sddl.h>

#include <stdio.h>

int main(int argc, char** argv)
{
    LPCTSTR wszAccName = TEXT("domainname\\username");
    LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
    DWORD cchDomainName = 1024;
    SID_NAME_USE eSidType;
    LPTSTR sidstring;
    char sid_buffer[1024];
    DWORD cbSid = 1024;
    SID* sid = (SID*)sid_buffer;

    if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
        return GetLastError();
    }

    if (!ConvertSidToStringSid(sid, &sidstring)) {
        return GetLastError();
    }

    printf("%ws\n", sidstring);
    return 0;

}

【讨论】:

  • 这不保证往返:如果指定的帐户被删除,并创建一个具有相同名称的新帐户,该名称现在将指代新帐户,而不是旧(已删除)的帐户.
  • @RaymondChen 谢谢提醒。我认为比较账户的创建时间来判断是否满足客户需求是一种方式。
  • @Scott Smith 不确定您是否考虑过 Raymond 所说的问题。就像我说的,比较帐户创建时间。但这似乎不是一个好的方向,见this。我认为更重要的是看你的需求。如果只是为了当前账号,不考虑ray说什么,那你可以用我的方法。
  • 比较帐户创建时间(假设您甚至可以得到帐户创建时间)将表明往返失败,您现在已经丢失了原始 sid。所以另一个问题是“如果往返有时失败可以吗?”另一种故障模式是如果您失去与 DC 的网络连接。
  • @StriveSun-MSFT - 使用WTS... API 的一个旁注:其中一些 API 的官方 Msft 文档声明(在某些情况下不正确)Windows 终端服务必须运行或他们会失败。再加上 Home 版本的 Windows 不支持远程桌面这一事实,我确信我不能依赖许多/大多数适用于 all 的 WTS... API Windows 10 所有版本的用户...
猜你喜欢
  • 1970-01-01
  • 2017-05-12
  • 2010-09-30
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-20
  • 2015-09-15
相关资源
最近更新 更多