c++ - 连接到同一网络中的命名管道,无需管理员权限

标签 c++ c windows winapi

我创建了一个命名管道服务器并授予Everyone完全访问权限。 我尝试从同一网络上的不同计算机连接到命名管道服务器,但收到一条错误消息,提示登录失败 - ERROR_LOGON_FAILURE。

我阅读了有关 NullSessionPipes 的内容,并从 MSDN 编译了示例。但是,我需要管理权限才能在注册表中注册 NullSessionPipe,这是我试图避免的。

CreateFile 实际上是如何登录远程命名管道的?我是否需要在特定上下文中运行我的客户端才能使其正常工作? (例如客人)。

服务器代码:

DWORD dwRes, dwDisposition;
PSID pEveryoneSID = NULL, pAdminSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
    SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
LONG lRes;
HKEY hkSub = NULL;

// Create a well-known SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
    SECURITY_WORLD_RID,
    0, 0, 0, 0, 0, 0, 0,
    &pEveryoneSID))
{
    return false;

}

// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, 1 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = 0xFFFFFFFF;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;

// Create a new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
    return false;
}

// Initialize a security descriptor.  
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
    SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
    return false;

}

if (!InitializeSecurityDescriptor(pSD,
    SECURITY_DESCRIPTOR_REVISION))
{
    return false;
}

// Add the ACL to the security descriptor. 
if (!SetSecurityDescriptorDacl(pSD,
    TRUE,     // bDaclPresent flag   
    pACL,
    FALSE))   // not a default DACL 
{
    return false;
}

// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;

// create named pipe
auto NamedPipe = CreateNamedPipeA(namedPipeName,
                                    PIPE_ACCESS_DUPLEX,
                                    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT | PIPE_ACCEPT_REMOTE_CLIENTS,
                                    PIPE_UNLIMITED_INSTANCES,
                                    NAMED_PIPE_SIZE,
                                    NAMED_PIPE_SIZE,
                                    NMPWAIT_USE_DEFAULT_WAIT, 
                                    &sa);

最佳答案

How to create an anonymous pipe that gives access to everyone中描述的这项任务是如何进行的

错误ERROR_LOGON_FAILURE表示客户端代码未与网络资源建立连接。确实需要调用WNetAddConnection2 (或在远程管道上调用 CreateFile 之前的模拟 api)

The client opens the pipe with a call to the CreateFile function. If an error occurs, the client checks if it is a logon failure error, an access denied error, or a bad password error. If an error occurs, perform an anonymous logon by calling the WNetAddConnection2 function and passing an empty string as user name and password. When the null session is established, the client calls the CreateFile function again.

所以客户端代码必须如下所示:

    NETRESOURCE nr = {};
    nr.dwUsage = RESOURCEUSAGE_CONNECTABLE|RESOURCEUSAGE_CONTAINER;
    nr.lpRemoteName = L"\\\\server\\IPC$";

    WNetAddConnection2W(&nr, L"", L"",0);

    HANDLE hFile = CreateFileW(L"\\\\?\\UNC\\server\\PIPE\\MyPipe",
        FILE_GENERIC_READ|FILE_GENERIC_WRITE, 
        0, 0, OPEN_EXISTING, 0, 0);

从服务器端不仅需要设置 0 DACL(这允许任何访问)或为 WinAnonymousSid 添加允许的ACE (这是 != WinWorldSid 又名 everyone),但也设置了不受信任的强制标签。这在代码示例中被忽略了,因为我认为代码还处于 vista 之前。

    SECURITY_DESCRIPTOR sd;
    BOOL fOk = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) &&
        SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE);

    if (fOk)
    {
        RTL_OSVERSIONINFOW ovi = { sizeof(ovi) };
        if (0 > RtlGetVersion(&ovi))
        {
            fOk = FALSE;
        }
        else
        {
            if (ovi.dwMajorVersion > 5)
            {
                fOk = FALSE;
                ULONG cb = GetSidLengthRequired(1);
                PSID UntrustedLabelSid = alloca(cb);
                if (CreateWellKnownSid(WinUntrustedLabelSid, 0, UntrustedLabelSid, &cb))
                {
                    PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
                    fOk = InitializeAcl(Sacl, cb, ACL_REVISION) &&
                        AddMandatoryAce(Sacl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, UntrustedLabelSid) &&
                        SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
                }
            }
        }
    }

关于c++ - 连接到同一网络中的命名管道,无需管理员权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52802339/

相关文章:

c++ - 具有不同类型的模板非类型参数

c++ - boost 优先级队列,查看元素是否已经在队列中

c++ - 我可以在 Xcode 上为非基于 os x 的框架等编写 C++ 代码吗?

c - 'b3Vec' 之前的预期说明符限定符列表

ruby - 是否可以在 ruby​​/tk 中使用 unicode 字符?

c++ - 卡住 Flash 影片

c - C 中数组索引的值递增或递减

c - uint32_t 和 size_t 的 printf 格式说明符

windows - 确定给定窗口当前是否正在移动

c++ - rapidxml 在 wchar_t 内容上抛出异常