草庐IT

c++:让用户进程写入 LOCAL_SYSTEM 命名管道 - 自定义安全描述符

coder 2024-06-04 原文

我有一个作为 LocalSystem 运行的服务,它在登录用户的 session 中创建一个进程。 然后该服务创建一个命名管道,客户端连接到该管道进行读写。 根据https://msdn.microsoft.com/en-us/library/aa365600%28v=vs.85%29.aspx客户端只能从管道中读取(它不是 Admin,不是 Creator,也不是 LocalSystem)。

我创建了一个安全描述符来授予用户读写访问权限。但这没有用。所以我尝试为 Everyone-Group 提供读写访问权限。但这也行不通。 我的客户端返回的错误代码始终是 ACCESS_DENIED (5)。

我很高兴知道我做错了什么。

编辑:如果我不创建自定义安全描述符,而只是使用 GENERIC_READ 打开管道,它就可以工作(但只能读取)。

EDIT2 我想学习如何正确地做到这一点。而且我仍然只想成为能够写入的登录用户。不是每个人(这只是为了测试)。

服务代码(注释掉我获取用户 sid 的代码):

PSID EveryoneSID                      = nullptr;
        SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
        if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                                 SECURITY_WORLD_RID,
                                 0, 0, 0, 0, 0, 0, 0,
                                 &EveryoneSID))
        {
            throw(std::runtime_error("Failed to initialize group sid: " + std::to_string(GetLastError())));
        }

        //TOKEN_USER* tokeninfo     = nullptr;
        //DWORD tokeninfolen        = 0;
        //DWORD outlen              = 0;
        //// Query token info size
        //if(!GetTokenInformation(UserToken,
        //                  TokenUser,
        //                  tokeninfo,
        //                  tokeninfolen,
        //                  &outlen))
        //{
        //  throw(std::runtime_error("Failed to obtain user token size: " + std::to_string(GetLastError())));
        //}
        //// Allocate enough space to hold token user information
        //tokeninfo    = (TOKEN_USER*) LocalAlloc(LPTR, outlen);
        //tokeninfolen = outlen;

        //// Get SID from user token
        //if(!GetTokenInformation(UserToken,
        //                  TokenUser,
        //                  tokeninfo,
        //                  tokeninfolen,
        //                  &outlen))
        //{
        //  throw(std::runtime_error("Failed to obtain user token info: " + std::to_string(GetLastError())));
        //}

        //auto UserSID = tokeninfo->User.Sid;
        //LocalFree(tokeninfo);

        SECURITY_ATTRIBUTES sa = {0};
        ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.bInheritHandle = FALSE;

        // Set up ACE
        EXPLICIT_ACCESS ace      = {0};
        ace.grfAccessMode        = SET_ACCESS;
        ace.grfAccessPermissions = PIPE_ACCESS_DUPLEX;  // GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE
        ace.grfInheritance       = NO_INHERITANCE;
        ace.Trustee.TrusteeForm  = TRUSTEE_IS_SID;
        ace.Trustee.TrusteeType  = TRUSTEE_IS_WELL_KNOWN_GROUP;
        ace.Trustee.ptstrName    = (LPTSTR) EveryoneSID;

        PACL acl = nullptr;
        if(ERROR_SUCCESS != SetEntriesInAcl(1, &ace, nullptr, &acl))
            throw(std::runtime_error("Failed to set acl entries: " + std::to_string(GetLastError())));

        // Create security descriptor.
        auto sd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
        if(!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
            throw(std::runtime_error("Failed to initialize security descriptor: " + std::to_string(GetLastError())));
        if(!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE))
            throw(std::runtime_error("Failed to set DACL: " + std::to_string(GetLastError())));

        // Set security descriptor in security attributes
        sa.lpSecurityDescriptor = sd;

        // Create a named pipe to which the user-session application
        // connects.
        auto pipe = CreateNamedPipe(LOCAL_PIPE_NAME,
                         PIPE_ACCESS_DUPLEX,
                         PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS | PIPE_WAIT,
                         1,
                         256,
                         256,
                         NULL,
                         &sa);
        if(pipe == INVALID_HANDLE_VALUE)
            throw std::runtime_error("Failed to create named pipe");

        LocalFree(acl);
        LocalFree(sd);

用户进程代码:

auto pipe = CreateFile(LOCAL_PIPE_NAME,
                           GENERIC_READ | GENERIC_WRITE,    // read access 
                            0,              // no sharing 
                            NULL,           // default security attributes
                            OPEN_EXISTING,  // opens existing pipe 
                            0,              // default attributes 
                            NULL);          // no template file 
    if (pipe == INVALID_HANDLE_VALUE)
        throw(std::runtime_error("Failed to open local pipe: " + std::to_string(GetLastError())));

最佳答案

这是第一个问题:

    ace.grfAccessPermissions = PIPE_ACCESS_DUPLEX;

PIPE_ACCESS_DUPLEX 常量仅用作 CreateNamedPipe() 的参数,它不是有效的访问权限。 (巧合的是,它等于 FILE_READ_DATA|FILE_WRITE_DATA 但这些访问权限本身并不允许您连接到管道。)

根据 Named Pipe Security and Access Rights ,以下访问权限分配给双工管道的服务器端,这意味着它们也足以打开客户端:

    ace.grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | SYNCHRONIZE;

但是,FILE_GENERIC_WRITE 过于宽泛,无法授予客户;特别是,它允许客户端创建管道服务器端的新实例。这不太可能是理想的。相反,对于双工管道,您应该使用

    ace.grfAccessPermissions = FILE_GENERIC_READ | FILE_WRITE_DATA;

当然,你在打开客户端时请求的权限必须是一致的:

auto pipe = CreateFile(LOCAL_PIPE_NAME,
                       GENERIC_READ | FILE_WRITE_DATA,    // read-write access 
                       0,              // no sharing 
                       NULL,           // default security attributes
                       OPEN_EXISTING,  // opens existing pipe 
                       0,              // default attributes 
                       NULL);          // no template file 

详细信息

实验上,在 Windows 7 SP1 x64 上,为了连接到管道(即使您在调用 CreateFile 时请求无访问权),您必须具有 READ_ATTRIBUTESSYNCHRONIZE 权利。请注意,FILE_GENERIC_READ 常量合并了这两者。

要从管道中读取数据,您必须拥有(并请求)FILE_READ_DATA。 (这包含在 FILE_GENERIC_READ 中。)

要将数据写入管道,您必须拥有(并请求)FILE_WRITE_DATA

关于c++:让用户进程写入 LOCAL_SYSTEM 命名管道 - 自定义安全描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29947524/

有关c++:让用户进程写入 LOCAL_SYSTEM 命名管道 - 自定义安全描述符的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  7. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

随机推荐