Probleme mit Berechtigungen im "ProgrammData"-Verzeichnis



  • Hallo zusammen,

    und ja, es gibt etliche Antworten dazu im Netz. Leider sind 90% davon unbrauchbar.
    Auch habe ich selbst auch schon einen Thread dazu hier drin.

    Nun mein lapidares Problem:
    Mein Programm verwendet dieses Verzeichnis zum Speichern von INI-Daten, die von allen Benutzern genutzt werden.
    Somit müssen auch alle Benutzer diese Daten ändern können!

    Mir wurde das hier so erklärt, dass genau dieses Verzeichnis dafür gedacht ist!

    Leider stellt sich das nun genau anders heraus.
    Wenn ich mich mit einem anderen Benutzer anmelde, kann dieser nicht mehr schreibend auf diese Daten zugreifen.

    Es ist nun auch leider so, dass das Programm selbst die nötigen Unterverzeichnisse in "ProgrammData" anlegt und nicht "Setup.exe".
    Damit fängt das Dilemma leider schon an.

    Das Dilemma geht dann damit weiter, dass das Programm über einen Link auf
    einen Netzwerkpfad aufgerufen werden soll und damit ohne echtes "Setup" auskommen muss.
    Also ist hier dieses Dilemma schon mal unlösbar.

    Ein "Setup" könnte ja Berechtigungen setzen, weil im Admin-Mode ausgeführt.
    Das müsste ich auch erst so scheiben:-(

    Kann mir bitte jemand da weiterhelfen?

    Ich müsste diesem Programm die Fähigkeit geben, die Schreibrechte auf die erzeugten Verzeichnisse,
    für alle authentifizierten User zu freizugeben!
    Klar, ich muss dann natürlich prüfen, ob der User, der gerade damit arbeitet,
    auch Admin Rechte besitzt.

    Wie mache ich das in C++ (nicht .NET !!)?

    Ein kleines Code-Beispiel wäre super!

    Grüsse
    Helmut



  • Rein aus WinAPI-Sicht (keine Ahnung, was MFC kapselt):

    Berechtigungen in ProgramData können auch von Nicht-Admins gesetzt werden. Schau dir mal SECURITY_ATTRIBUTES in CreateDirectory und CreateFile an.

    Dieser Code (1. Antwort) ist alles andere als schön und sollte angepasst werden, zeigt aber eine Lösung.

    Falls die Frage nach dem Admin doch noch nötig sein sollte, kannst du das mit GetTokenInformation herausfinden (wobei dabei die TOKEN_INFORMATION_CLASS TokenElevation ist und der dritte Parameter ein Zeiger auf eine TOKEN_ELEVATION-Struktur sein sollte).



  • Vielen Dank dsdfas,

    da sind ein paar Sachen dabei, die sich sich sehr gut anhören.
    Ausprobieren kann ich es erst in einer Woche. Ich brauch Urlaub.



  • ich glaube die Funktion SHGetFolderPath ist da dein Freund. Du solltest das immer damit machen, da unter verschiedenen Betriebssystemen diese Pfade auch mal anders lauten können. Wenn Du den 2. Parameter auf CSIDL_COMMON_APPDATA setzt müsste die genau das machen was du möchtest. In diesem Verzeichnis hast Du auch ohne erhöhte Rechte Schreibzugriff. Damit muss man auch kein Setup als Administrator ausführen.



  • Vielen Dank, Andy,
    ich werde die Anregungen ab Montag ausprobieren.



  • Hallo zusammen,

    inzwischen habe ich mir die Vorschläge angesehen.

    Das mit "SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA,..)" habe ich schon so gemacht.
    Das alleine hilft jedenfalls nichts.

    Die Unterverzeichnisse dort hatte ich mit
    "CreateDirectory(g_LocalAppDataPath + APPDATA_HOMEPATH, NULL)" erstellt.
    Das führte dann zur Zugriffsverweigerung für andere Benutzer.

    Momentan versuche ich es mit dem Vorschlag von dsdfas "Dieser Code ...".
    Damit kann ich die Verzeichnisberechtigungen jedenfalls einstellen.
    Leider ist dieses Thema sehr umfangreich, und der gezeigte Lösungsvorschlag auch ein sehr grober Rundumschlag,
    der doch weitgehend angepasst werden muss.
    D.h. dort werden alle Gruppeen und User gelöscht und durch "jeder" ersetzt.
    Also scheint das der Lösungsweg aber noch nicht die Lösung zu sein.

    Vielen Dank nochmal an alle
    Helmut



  • Nun bin ich wieder einen kleinen Schritt weiter.

    Der Quellcode in dem Link von dsdfas hat den Nachteil, dass er alle bestehenden Berechtigungen löscht und einfach nur "Jeder" einträgt.
    Man sieht nichtmal, welche Berechtigungen eingetragen sind.

    Ich habe dann folgendes Codebeispiel verwendet:
    https://stackoverflow.com/questions/18096772/how-to-give-everyone-write-permissions-via-c-mfc-on-windows-8

    Ich erzeuge mein Haupt-Verzeichnis wie gewohnt über "CreateDirectory(g_LocalAppDataPath + APPDATA_BASEPATH, NULL)".
    Es werden dadurch die bestehenden Berechtigungen des übergeordneten Verzeichnisses geerbt.
    Danach wird über den Code aus dem Link die Grupps "Jeder" ergänzt.
    Weitere Unterverzeichnisse darunter erben dann diese Berechtigungen auch.

    Aber nun will ich noch die Berechtigung für die Gruppe der "lokalen user" anpassen und denen auch Schreibrechte geben.
    Das ist mit der obigen Anpassung leider immernoch nicht passiert.

    Wie mache ich denn das?
    Weiss da jemand noch Rat?
    Dazu habe ich das ganze Zeug einfach noch zu wenig verstanden.

    Ausserdem wäre es auch gut zu wissen, ob man dss, unter Aspekten der Sicherheit, vielleicht ganz anders lösen müsste.

    Ganz speziell geht es dabei um ein exklusiv zum Programm gehörendes Unterverzeichnis innerhalb des "ProgrammData" Verzeichnisses,
    das doch eigentlich für Benutzer übergreifende INI-Dateien gedacht sein sollte.
    Aber Microsoft stellt dieser Verwendung permanent Fallstricke in den Weg!

    Grüsse
    Helmut



  • Habe den nächsten Schritt nun auch herausgefunden:

    In allen Beispielen wird die SID "S-1-1-0" verwendet.
    Diese nennt sich "Jeder".
    Damit kann kein user, der nur lokal im Rechner eingetragen ist, arbeiten.
    Mit einem weiteren Domänen-User habe ich das nicht probiert.

    Dann gibts aber noch die SID "S-1-2-0", die sich "LOKAL" nennt.
    Mit dieser Einstellung haben verschiedene Domänen-User, die sich am Rechner lokal anmelden,
    sowie die nur lokal im Rechner eingetragenen User, die sich ebenfalls dort lokal anmelden, die nötige Berechtigung.

    Also heisst "LOKAL" nicht "lokal eingetragene Benutzer", sondern es sind alle, die sich am Rechner lokal (physisch) anmelden.
    Im Gegensatz: Man könnte sich ja remote anmelden...

    Bleibt meine Frage: Habe ich das auch korrekt, gemäss den momentan üblichen Sicherheitsaspekten, gemacht?
    Oder ist meine Lösung scheisse?

    Und danke noch an dsdfas.
    Dein Vorschlag war sehr hilfreich.



  • Ich würde niemals das Konto Jeder benutzen, sondern eher nur das vordefinierte Konto Benutzer. DOMAIN_GROUP_RID_USERS

    Also nur die Leute, die an diesem PC als Benutzer angemeldet sein können, können den Ordner sehen...

    Ungeprüfter uralter Code, der die entsprechenden Rechte für Benutzer vererbar auf einen Folder oder Datei setzt.

    DWORD SetFileAccess(PCTSTR pszPath)
    {
    	// Variables needed for a later Cleanup
    	PACL pDacl=NULL, pNewDacl=NULL;
    	PSID pUserSID=NULL;
    	PSECURITY_DESCRIPTOR pSecurity=NULL;
    	SID_IDENTIFIER_AUTHORITY ntAuth = SECURITY_NT_AUTHORITY;
    
    //-------------get existing security settings---------------------------
    	// Get a copy of the name
    	TCHAR	szName[_MAX_PATH];
    	_tcscpy(szName,pszPath);
    	::PathRemoveBackslash(szName);
    
    	// Get current Securiry Settings
    	DWORD dwError;
    	if (dwError=GetNamedSecurityInfo(szName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,&pDacl,NULL,&pSecurity))
    		goto Cleanup;
    
    //-------------create SID for user--------------------------------------
    	if (!AllocateAndInitializeSid(&ntAuth,
    		2,SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_USERS,0,0,0,0,0,0,
    		&pUserSID))
    	{
    		dwError = GetLastError();
    		goto Cleanup;
    	}	
    
    //-------------Create new entries---------------------------------------
    	EXPLICIT_ACCESS newEntries[1];
    	ZeroMemory(newEntries,sizeof(newEntries));
    	newEntries[0].grfAccessPermissions = FILE_ALL_ACCESS & ~(WRITE_DAC|WRITE_OWNER);
    	newEntries[0].grfAccessMode = GRANT_ACCESS;
    	newEntries[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    	newEntries[0].Trustee.pMultipleTrustee = NULL;
    	newEntries[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
    	newEntries[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    	newEntries[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    	newEntries[0].Trustee.ptstrName = (PTSTR)pUserSID;
    
    //-------------Set new values-------------------------------------------
    	if (dwError=SetEntriesInAcl(1,newEntries,pDacl,&pNewDacl))
    		goto Cleanup;
    
    //-------------Set Security---------------------------------------------
    	dwError = SetNamedSecurityInfo(szName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL);
    
    //-------------Free all buffsers----------------------------------------
    Cleanup:
    	// Free users SID
    	FreeSid(pUserSID);
    	// Free buffer
    	LocalFree(pDacl);
    	LocalFree(pNewDacl);
    	LocalFree(pSecurity);
    	return dwError;
    }
    


  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Danke Martin!

    Dein Code ist eigentlich das, was ich gesucht hatte!
    Es sind nur ein paar Parameter anders gesetzt, sonst ist es gleich.

    Wie ich es von Hand gemacht hätte, wird hier die bestehende Berechtigung für "Benutzer" angepasst.
    Bei allem, was ich gefunden habe, wird eine weitere Gruppe in die Berechtigungsliste hinzugefügt.

    Aber um das Wirrwar an Parametern zu verstehen, braucht man leider einige Zeit.