windows - c++: Let user process write to LOCAL_SYSTEM named pipe - Custom Security Descriptor -
i have service running localsystem creates processes in logged on users' session. service creates named pipe client connects read , write. according https://msdn.microsoft.com/en-us/library/aa365600%28v=vs.85%29.aspx client can read pipe (it's no admin, not creator, neither localsystem ).
i created security descriptor grant user read & write access. didn't work. tried giving read & write-access everyone-group. not work. error code client returns access_denied (5).
i glad know doing wrong.
edit: if don't create custom security descriptor , open pipe generic_read
works (but reading).
edit2 want learn how right. , still want logged on user able write. not (this testing).
service-code (commented-out code getting user 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 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 obtain user token size: " + std::to_string(getlasterror()))); //} //// allocate enough space hold token user information //tokeninfo = (token_user*) localalloc(lptr, outlen); //tokeninfolen = outlen; //// sid user token //if(!gettokeninformation(usertoken, // tokenuser, // tokeninfo, // tokeninfolen, // &outlen)) //{ // throw(std::runtime_error("failed 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 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 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 initialize security descriptor: " + std::to_string(getlasterror()))); if(!setsecuritydescriptordacl(sd, true, acl, false)) throw(std::runtime_error("failed set dacl: " + std::to_string(getlasterror()))); // set security descriptor in security attributes sa.lpsecuritydescriptor = sd; // create named pipe 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 create named pipe"); localfree(acl); localfree(sd);
user-process-code:
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 open local pipe: " + std::to_string(getlasterror())));
this first problem:
ace.grfaccesspermissions = pipe_access_duplex;
the pipe_access_duplex
constant meant used argument createnamedpipe(), not valid access permission. (by coincidence, equal file_read_data|file_write_data
access rights not allow connect pipe.)
according named pipe security , access rights, following access rights assigned server end of duplex pipe, implying sufficient open client end:
ace.grfaccesspermissions = file_generic_read | file_generic_write | synchronize;
however, file_generic_write
broad grant client; in particular, allows client create new instance of server end of pipe. unlikely desirable. instead, duplex pipe, should use
ace.grfaccesspermissions = file_generic_read | file_write_data;
of course, access request when opening client end must consistent:
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
details
experimentally, on windows 7 sp1 x64, in order connect pipe (even if request no access in call createfile) must have read_attributes
, synchronize
rights. note file_generic_read
constant incorporates both of these.
to read data pipe must have (and request) file_read_data
. (this incorporated in file_generic_read
.)
to write data pipe must have (and request) file_write_data
.
Comments
Post a Comment