PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++] SecurityDescriptor für Pipes


anakin87
2013-05-21, 12:47:26
Hallo,
zur Zeit versuche ich für eine NamedPipe den Zugriff zu beschränken.
Die Idee ist, dass nur ein Client-Prozess mit Admin-Rechten auf den Pipe-Server (NUR LOCAL-keine Zugriff per Netzwerk erlaubt) zugreifen darf.

Ich zeig halt mal etwas Code her:


SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) new byte[(SECURITY_DESCRIPTOR_MIN_LENGTH)];

InitializeSecurityDescriptor(sa.lpSecurityDescriptor,SECURITY_DESCRIPTOR_REVISIO N);

DWORD dwRes;
EXPLICIT_ACCESS ea[1];
PACL pacl= NULL;
PSID pAdminSID=NULL;

SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;

// Create a SID for the BUILTIN\Administrators group.
AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_GROUP_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdminSID);


// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow the Administrators group full access to
// the key.

ea[0].grfAccessPermissions = KEY_ALL_ACCESS;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance= NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR) pAdminSID;

dwRes = SetEntriesInAcl(1, ea, NULL, &pacl);

SetSecurityDescriptorDacl(sa.lpSecurityDescriptor,TRUE,pacl,FALSE); //Admin set in SecurityDescriptorAccessList

sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;

//create pipe
HANDLE hpipe = CreateNamedPipe(strPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
1,
BUFFER_SIZE,
BUFFER_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
&sa
);



Problem der ganzen Sache ist nun, dass mein Client ein Access_denied bekommt - egal ob als Run_as_admin, oder als user (der erst Adminrechte durch die WIN-UAC bekommt).

So wo liegt nun mein Fehler? Ich hab doch der ACL doch ein explicit_access zugewiesen... Oder Passt das Domain_GROUP_RID_ADMIN nicht? :freak:
DOMAIN_ALIAS_RID_ADMINS läuft auch nicht besser...

beste Grüße

PatkIllA
2013-05-21, 13:22:07
Wie ist denn der Name der Pipe?
Damit sie sessionübergreifend genutzt werden kann muss der Name mit Global\ anfangen.

anakin87
2013-05-21, 13:29:22
Ah ja klar - hab nur einen Teil gepostet.
Name: \\.\pipe\TestPipe
Die Pipe selbst scheint zu funktionieren - hab sie freigegeben für alle und da hat alles gepasst.
SetSecurityDescriptorDacl(sa.lpSecurityDescriptor,TRUE,NULL,FALSE);
Wie meinst du das? 'Global\.\pipe\Testpipe'?

EDIT:
Sessionübergreifend für verschiedene User wär gar nich so schlecht...
Moment ich teste das gleich mal

PatkIllA
2013-05-21, 13:32:39
Ich glaube so war das. Wenn Access Denied kommt schätze ich aber auch fast, dass die Pipe vorhanden ist und gefunden wird.
Probieren kannst du es ja trotzdem mal.

anakin87
2013-05-21, 13:35:38
Global\.\pipe\Testpipe liefert ein INVALID_HANDLE_VALUE
Seltsam...

EDIT:
Ich verstehe nicht, warum ich mit dem oben erstellten SecurityDescriptor nichtmal als Admin zugreifen kann auf die Pipe. Ich will ja nur die "Administrators" - Group drauf zugreifen lassen.

Ah ich glaube ich habe eine Idee...
Ich habe doch oben DOMAIN_GROUP_RID_ADMINS angegeben - bei mir sind die DomainAdmins den Administratoren zugewiesen. Kann es sein, dass die DomainAdmins nichts von den Lokalen wissen?
Wie gebe ich dann die (lokale) "Administrators" Gruppe für den SecurityDescriptor an?

Ectoplasma
2013-05-21, 14:06:15
Kann es sein, dass die DomainAdmins nichts von den Lokalen wissen?

Nein, woher auch?



Wie gebe ich dann die (lokale) "Administrators" Gruppe für den SecurityDescriptor an?

Ist schon lange her, dass ich damit gearbeitet habe. Lege noch einen weiteren EA an und google nach dem Namen für die lokale Administratoren Gruppe. Im Kopf weiss ich den auch nicht mehr.

anakin87
2013-05-21, 14:50:19
Hm die Idee ist mir auch dabei gekommen, nur leichter gesagt als getan.
Die User/Groups sind in winnt.h als #define eingetragen - da sucht man ein bisschen.
Google liefert meist folgende 2 -> sinds aber nicht...
SECURITY_BUILTIN_DOMAIN_RID
DOMAIN_GROUP_RID_ADMINS

Ectoplasma
2013-05-21, 15:15:43
Also die Default Admin Gruppe hat die SID "S-1-5-32-544". Hast du mal geschaut, welche SID nach dem Aufruf von 'AllocateAndInitializeSid' herauskommt? Gefunden habe ich die Admin-SID hier: Well-known security identifiers in Windows operating systems (http://support.microsoft.com/kb/243330).

anakin87
2013-05-21, 15:55:54
Meinst du was in pAdminSID (Typ: PSID) drinnen steht nach AllocateAndInitializeSid?
0053A8F8 oder 0053B408 je nachdem SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_GROUP_RID_ADMINS oder SECURITY_MANDATORY_LOW_RID, DOMAIN_USER_RID_ADMIN... sieht schwer nach Hex aus, aber wie passt das zu S-1-5-32-544?

Bsp: wie es in winnt.h steht
// Null SID S-1-0-0
// World S-1-1-0
#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0}
#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1}
...
...
// Local System S-1-5-18
#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L)

:confused:

Leider weiß ich nicht wo ich die SID direkt eintrage - muss da noch rumspielen...
Witztig ist, dass das unter C# ein Einzeiler ist und ich in C++ schon fast 50 habe

Ectoplasma
2013-05-21, 16:20:53
ConvertStringSidToSid (http://msdn.microsoft.com/en-us/library/windows/desktop/aa376399%28v=vs.85%29.aspx) ;)

Umgekehrt gibt es die natürlich auch (ConvertSidToStringSid).

anakin87
2013-05-21, 16:40:28
Danke - jetzt nimmt er den SID an. Leider führt es nicht zum gewünschten Verhalten...

Nennen mir ihn UserA; dieser gehört zur Gruppe 'Administrators'.
UserA startet den PipeServer (normal)
UserA startet den PipeClient (normal)
Server soll dem Client den Zugriff verweigern.

UserA startet den PipeServer (normal)
UserA startet den PipeClient (als Admin ausführern)
Server soll dem Client den Zugriff erlauben.

ZurZeit erlaubt der Server dem Client der unter UserA(normal) läuft den Zugriff. Ok ist klar UserA gehört zur Administratos-Gruppe darum wird es erlaubt - vermute ich mal. Wie erlaube ich den Zugriff nur dann wenn der Client mit Admin-Rechten gestartet wurde?

Ectoplasma
2013-05-21, 19:04:56
Wie erlaube ich den Zugriff nur dann wenn der Client mit Admin-Rechten gestartet wurde?

Ähm, gar nicht?! Du kannst keinen User ein Programm als Admin starten lassen, wenn er nicht der Gruppe Admin angehört. Anders könnte das mit Windows 7 und UAC sein, aber da müßte ich mich auch erst einlesen.

Thunderhit
2013-05-21, 19:30:06
Sicher geht das, "Ausführen als" lässt einen afaik unter XP ein Programm als anderer User ausführen.

PatkIllA
2013-05-21, 19:49:50
Ähm, gar nicht?! Du kannst keinen User ein Programm als Admin starten lassen, wenn er nicht der Gruppe Admin angehört. Anders könnte das mit Windows 7 und UAC sein, aber da müßte ich mich auch erst einlesen.
Die Zugehörigkeit zur Gruppe heißt aber nicht, dass ein Prozess administrative Rechte hat. Da muss man bei UAC erst zustimmen.
Außerdem gibt es ja noch die Dömanenadministratoren.

anakin87
2013-05-22, 00:40:23
Ähm, gar nicht?! Du kannst keinen User ein Programm als Admin starten lassen, wenn er nicht der Gruppe Admin angehört. Anders könnte das mit Windows 7 und UAC sein, aber da müßte ich mich auch erst einlesen.

Der User gehört den Admins an, aber läuft nicht immer unter Admin-Berechtigung; UAC und so Zeug...
Unter Win kannst ja eine .exe mit rechte Maustaste -> als Administrator ausführen -> dann kommt die UAC (natürlich muss der User den Admins angehören sonst läufts nicht) -> erst jetzt bekommt ein Prozess Admin-Rechte. Wie ein klickbares-sudo wenn man so will...
(Das ist jetzt nicht böse gemeint oder so - ich will nur sicherstellen, dass ich nicht falsch verstanden werde)

Toll ist dass das ganze Problemlos unter C# läuft da ist es ein Einzeiler bei dem ich "Administrators" als Gruppe angebe - genauso wie ich es auch im C++ Gegenstück machen möchte/tue..

Es muss ja nicht direkt als anderer User laufen - sondern dann Zugriff erlauben wenn der AdminUser auch auf den Prozess AdminRechte setzt/erhöht - da stimme ich Thunderhit & PatkIllA zu. Auch sind die Domänenadmins der Administrators-Gruppe zugeteilt.

Morgen poste ich den C# Teil - der bring vielleicht etwas Licht. (Vielleicht könnt ihr mir helfen den zu analysieren - der verwendet auch in den tieferen Ebenen die SID, ACL & SecurityDescriptoren -> hab mit ILspy etwas reingeschaut). Soweit sollte es möglich sein - es passt wahrscheinlich eine Option/Flag nicht.

THX für die Unterstützung; bin langsam echt ratlos - ich hoffe wir bekommen das gelöst ;D
-> werd mich heute Vormittag nochmal dran setztn

Ectoplasma
2013-05-22, 07:47:50
Sicher geht das, "Ausführen als" lässt einen afaik unter XP ein Programm als anderer User ausführen.

Ja, ist klar, darum ging es ja auch gar nicht in meiner Antwort. Aber entweder du oder ich, haben die Ausgangsfrage falsch verstanden.

Die Frage von anakin87 lautete: "Wie erlaube ich den Zugriff nur dann wenn der Client mit Admin-Rechten gestartet wurde? " Aus Sicht eines Executetables ist es doch völlig egal, ob es mit "Ausführen als" oder sonst wie gestartet wurde. Wie soll das Executable den Unterschied feststellen?

EDIT: Habe die Ausgangsfrage von anakin87 wohl falsch verstanden, habe gerade seinen letzten Post gelesen.

Ectoplasma
2013-05-22, 07:50:12
Die Zugehörigkeit zur Gruppe heißt aber nicht, dass ein Prozess administrative Rechte hat. Da muss man bei UAC erst zustimmen.
Außerdem gibt es ja noch die Dömanenadministratoren.

Wenn du dann zustimmst, hat dann der Prozess das Recht temporär, für diese eine Funktion, oder dann Dauerhaft?

Ectoplasma
2013-05-22, 08:05:06
THX für die Unterstützung; bin langsam echt ratlos - ich hoffe wir bekommen das gelöst ;D
-> werd mich heute Vormittag nochmal dran setztn

Dieses KEY_ALL_ACCESS, ist das überhaupt der richtige Wert? In der Doku gehört der zu Registry-Schlüsseln, aber nicht zu EXPLICIT_ACCESS. Nur so eine Idee.

anakin87
2013-05-22, 10:42:59
So wie versprochen die C# Ausführung:


PipeSecurity ps = new PipeSecurity();
PipeAccessRule par = new PipeAccessRule("Administrators", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); //Das ist der ganze Zauber - mehr sollte eigentlich nicht notwendig sein....
ps.AddAccessRule(par);
pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, bufferSize, bufferSize, ps);



Ich zweifle langsam an der Korrektheit meines C++ Codes.
Vorgegangen bin ich nach der MS-Doku für einen SecurityDescriptor (ich denke die goto muss man ignorieren):
http://msdn.microsoft.com/en-us/library/windows/desktop/aa446595(v=vs.85).aspx

Hab gestern noch gecodet - und es war spät, es können grobe Fehler drinnen sein...


//PipeName
CString strPipeName;
strPipeName.Format(_T("\\\\%s\\pipe\\%s"),
_T("."),
_T("TestPipe")
);

//set security attributes
SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) new byte[(SECURITY_DESCRIPTOR_MIN_LENGTH)];
InitializeSecurityDescriptor(sa.lpSecurityDescriptor,SECURITY_DESCRIPTOR_REVISIO N);

DWORD dwRes;
EXPLICIT_ACCESS ea[1];
PACL pacl= NULL;

PSID pAdminSID=NULL;
PSID* pAdminSIDptr = &pAdminSID;

SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;


//ConvertStringSidToSid((LPCSTR)"S-1-5-21-512",pAdminSID1); //Domain Admin
ConvertStringSidToSid((LPCSTR)"S-1-5-32-554",pAdminSIDptr); //Administrators

// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow the Administrators group full access to
// the key.
ZeroMemory(&ea,sizeof(EXPLICIT_ACCESS));

ea[0].grfAccessPermissions = KEY_ALL_ACCESS;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance= NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR) pAdminSID;


dwRes = SetEntriesInAcl(1, ea, NULL, &pacl);

SetSecurityDescriptorDacl(sa.lpSecurityDescriptor,TRUE,pacl,FALSE); //Admin set in SecurityDescriptorAccessList

//SetSecurityDescriptorDacl(sa.lpSecurityDescriptor,TRUE,NULL,FALSE); //set none in SecurityDescriptorAccessList
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;

//create pipe
HANDLE hpipe = CreateNamedPipe(
strPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
1,
BUFFER_SIZE,
BUFFER_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
&sa
);


k.a. was jetzt los ist, aber ich kann nicht zugreifen. Es muss ein Problem sein mit PSID / PSID* in Kombination mit den SECURITY_ATTRIBUTES sa;
Passt die zugewiesene PSID nicht hab ich aufeinmal "Zugriff erlaubt".... dafuq??

EDIT:
ok ich glaub ich dreh am Rad...
wenn ich
ea[0].Trustee.ptstrName = NULL;
anstelle von
ea[0].Trustee.ptstrName = (LPTSTR) pAdminSID;
verwende, dann wird der Zugriff anscheinend per default erlaubt - d.h. jedesmal wenn die Zeile Blödsinn übergibt hab ich Zugriff???

Ectoplasma
2013-05-22, 12:35:29
Hör doch ma :)

Ich schrieb das bereits eine Mail zuvor ...

Überprüfe doch einmal bitte die Access-Mask (ea[0].grfAccessPermissions = KEY_ALL_ACCESS). KEY_ALL_ACCESS ist eigentlich eine Mask für Registry-Keys. Das könnte für eine Named Pipe die falsche Access-Mask sein. Das ist das, was mir noch zum C++ Code einfällt.

anakin87
2013-05-22, 12:53:37
Ah ja sorry - ich hab noch nicht reingeschrieben dass ich auf FILE_ALL_ACCESS gewechselt habe. Wird laut http://graphics.stanford.edu/~mdfisher/Code/Engine/Pipe.cpp.html
für Pipes verwendet.

nichts für ungut...

habe gerade rausgefunden, dass

PSID all=null;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0,
0, 0, 0, 0, 0, 0,
&all);

sogar mal funktioniert...
SECURITY_LOCAL_SID_AUTHORITY -> gibts auch noch - habe gerade zu viele Baustellen im Kopf; ich muss das mal geordneter angehen.

EDIT:
!!SOLVED!!
Die Initialisierung des SecurityDescriptors war Mist... Rest wurde nach http://msdn.microsoft.com/en-us/library/windows/desktop/aa446595%28v=vs.85%29.aspx komplett neu erstellt und für die Pipe angepasst (FILE_ALL_ACCESS anstelle von KEY_ALL_ACCESS)

@ALL danke für die Hilfe (y)