UAC (Windows) a wspólny katalog dla wszystkich użytkowników

0

Witam Was,

Przerabiam swoją aplikację i dążę aby wykluczyć z niej manifest wymuszający uruchomienie z podwyższonymi uprawnieniami. Zgodnie z tym co jest w dokumentacji UAC program nie może modyfikować plików w katalogu "program files" także we własnym katalogu programu. Dlatego pobieram ogólnie dostępny katalog dla wszystkich użytkowników:

  CSIDL_COMMON_APPDATA                = $0023; { All Users\Application Data } 

przez co otrzymuję się ścieżkę typu:

C:\ProgramData

W tym katalogu tworzę katalog o nazwie programu a w nim np pliki ini. I tutaj pojawia się problem bo gdy zaloguję się do systemu Windows jako zwykły użytkownik to także nic nie mogę zmieniać w tych plikach z poziomu programu.

Pozostańmy na przykładzie tego pliku ini - powiedzmy że zapisuję w nim ustawienia programu. Czy ktoś mógłby mi wskazać gdzie w takim razie mogę zapisać taki plik aby był ogólnie dostępny dla odczytu i zapisu dla każdego użytkownika także tego bez praw administratora.

Poniżej lista ścieżek które możemy pobrać:

  CSIDL_DESKTOP                       = $0000; { <desktop> }
  CSIDL_INTERNET                      = $0001; { Internet Explorer (icon on desktop) }
  CSIDL_PROGRAMS                      = $0002; { Start Menu\Programs }
  CSIDL_CONTROLS                      = $0003; { My Computer\Control Panel }
  CSIDL_PRINTERS                      = $0004; { My Computer\Printers }
  CSIDL_PERSONAL                      = $0005; { My Documents.  This is equivalent to CSIDL_MYDOCUMENTS in XP and above }
  CSIDL_FAVORITES                     = $0006; { <user name>\Favorites }
  CSIDL_STARTUP                       = $0007; { Start Menu\Programs\Startup }
  CSIDL_RECENT                        = $0008; { <user name>\Recent }
  CSIDL_SENDTO                        = $0009; { <user name>\SendTo }
  CSIDL_BITBUCKET                     = $000a; { <desktop>\Recycle Bin }
  CSIDL_STARTMENU                     = $000b; { <user name>\Start Menu }
  CSIDL_MYDOCUMENTS                   = $000c; { logical "My Documents" desktop icon }
  CSIDL_MYMUSIC                       = $000d; { "My Music" folder }
  CSIDL_MYVIDEO                       = $000e; { "My Video" folder }
  CSIDL_DESKTOPDIRECTORY              = $0010; { <user name>\Desktop }
  CSIDL_DRIVES                        = $0011; { My Computer }
  CSIDL_NETWORK                       = $0012; { Network Neighborhood (My Network Places) }
  CSIDL_NETHOOD                       = $0013; { <user name>\nethood }
  CSIDL_FONTS                         = $0014; { windows\fonts }
  CSIDL_TEMPLATES                     = $0015;
  CSIDL_COMMON_STARTMENU              = $0016; { All Users\Start Menu }
  CSIDL_COMMON_PROGRAMS               = $0017; { All Users\Start Menu\Programs }
  CSIDL_COMMON_STARTUP                = $0018; { All Users\Startup }
  CSIDL_COMMON_DESKTOPDIRECTORY       = $0019; { All Users\Desktop }
  CSIDL_APPDATA                       = $001a; { <user name>\Application Data }
  CSIDL_PRINTHOOD                     = $001b; { <user name>\PrintHood }
  CSIDL_LOCAL_APPDATA                 = $001c; { <user name>\Local Settings\Application Data (non roaming) }
  CSIDL_ALTSTARTUP                    = $001d; { non localized startup }
  CSIDL_COMMON_ALTSTARTUP             = $001e; { non localized common startup }
  CSIDL_COMMON_FAVORITES              = $001f;
  CSIDL_INTERNET_CACHE                = $0020;
  CSIDL_COOKIES                       = $0021;
  CSIDL_HISTORY                       = $0022;
  CSIDL_COMMON_APPDATA                = $0023; { All Users\Application Data }
  CSIDL_WINDOWS                       = $0024; { GetWindowsDirectory() }
  CSIDL_SYSTEM                        = $0025; { GetSystemDirectory() }
  CSIDL_PROGRAM_FILES                 = $0026; { C:\Program Files }
  CSIDL_MYPICTURES                    = $0027; { C:\Program Files\My Pictures }
  CSIDL_PROFILE                       = $0028; { USERPROFILE }
  CSIDL_SYSTEMX86                     = $0029; { x86 system directory on RISC }
  CSIDL_PROGRAM_FILESX86              = $002a; { x86 C:\Program Files on RISC }
  CSIDL_PROGRAM_FILES_COMMON          = $002b; { C:\Program Files\Common }
  CSIDL_PROGRAM_FILES_COMMONX86       = $002c; { x86 C:\Program Files\Common on RISC }
  CSIDL_COMMON_TEMPLATES              = $002d; { All Users\Templates }
  CSIDL_COMMON_DOCUMENTS              = $002e; { All Users\Documents }
  CSIDL_COMMON_ADMINTOOLS             = $002f; { All Users\Start Menu\Programs\Administrative Tools }
  CSIDL_ADMINTOOLS                    = $0030; { <user name>\Start Menu\Programs\Administrative Tools }
  CSIDL_CONNECTIONS                   = $0031; { Network and Dial-up Connections }
  CSIDL_COMMON_MUSIC                  = $0035; { All Users\My Music }
  CSIDL_COMMON_PICTURES               = $0036; { All Users\My Pictures }
  CSIDL_COMMON_VIDEO                  = $0037; { All Users\My Video }
  CSIDL_RESOURCES                     = $0038; { Resource Directory }
  CSIDL_RESOURCES_LOCALIZED           = $0039; { Localized Resource Directory }
  CSIDL_COMMON_OEM_LINKS              = $003a; { Links to All Users OEM specific apps }
  CSIDL_CDBURN_AREA                   = $003b; { USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning }
  CSIDL_COMPUTERSNEARME               = $003d; { Computers Near Me (computered from Workgroup membership) }
  CSIDL_PROFILES                      = $003e;
 
1

Dlatego pobieram ogólnie dostępny katalog dla wszystkich użytkowników:

A nie lepiej katalog danego użytkownika? (CSIDL_APPDATA).
W ten sposób każdy będzie mógł mieć inną konfigurację.

Odgórnym założeniem w Windows jest, że jeśli coś ma być wspólne dla wszystkich (w tym dla administratorów), to «wszyscy» mają prawo do odczytu, a modyfikować może tylko administrator.

2

Też borykałem się z tym problemem, na szczęście krótko - skorzystałem z CSIDL_LOCAL_APPDATA oraz funkcji SHGetSpecialFolderPath - ze względu na kompatybilność z WinXP;

Microsoft sugeruje ten katalog do trzymania ustawień aplikacji; Na blogu można też znaleźć fajne podsumowanie - http://blogs.msdn.com/b/patricka/archive/2010/03/18/where-should-i-store-my-data-and-configuration-files-if-i-target-multiple-os-versions.aspx (jest tam też wzmianka o tym, gdzie trzymać globalne dla maszyny konfiguracje - patrz na drugi komentarz).

0

@furious programming Dzięki za ten link, lokalizację mam dobrą tylko muszę zmienić uprawnienia katalogu tak aby zwykły użytkownik mógł w nim modyfikować.

Teraz muszę tylko pomyśleć jak zmieniać uprawnienia z poziomu programu.

0
Azarien napisał(a):

A nie lepiej katalog danego użytkownika? (CSIDL_APPDATA).
Są przypadki, że o wiele lepiej i wygodniej będzie jak każdy user ma te same ustawienia. U mnie np. to są parametry połączenia do bazy danych na jakiej ma pracować system. Są userzy gdzie 20-30 siedzi po RDP na serwerze terminali i średnio widzę konfigurację tego dla każdego usera z osobna. Tak więc wszystko zależy. Z tym, że ja trzymam wartości w rejestrze HKLM.

0
Mr.YaHooo napisał(a)

Z tym, że ja trzymam wartości w rejestrze HKLM.

Do tej gałęzi rejestru domyślnie nie można nic zapisywać na systemach młodszych od WinXP; Wiadome - dobre miejsce na wspólne dla maszyny informacje (tak samo jak CSIDL_COMMON_APPDATA), jednak uprawnienia... No i też wiadome, że w projekcie można zaznaczyć poziom uprawnień requireAdministrator i problem z głowy, ale czy na pewno?

Jedna rzecz to zasady i dobre praktyki, a druga to techniczne sposoby rozwiązywania problemów i ich implementacja;

Można za pomocą instalatora nadać poszczególnym katalogom prawa do zapisu, można wykorzystać requireAdministrator i teoretycznie mieć z głowy kwestię uprawnień, można też zmienić koncepcję i użyć lokalizacji, do których domyślnie prawa dostępu ma każdy użytkownik;

Sprawa nieco się komplikuje, jeśli aplikacja nie posiada instalatora, a potrzebuje zapamiętać jakieś konfiguracje; Robią tak np. różne emulatory (dla NES czy SNES), czyli tworzą pliki konfiguracyjne i katalogi obok pliku wykonywalnego.

1

Instalator powinien wymagać praw admina a więc on powinien utworzyć podfolder aplikacji NazwaProducenta\NazwaProgramu w CSIDL_COMMON_APPDATA i nadać mu uprawnienia do zapisu dla wszystkich użytkowników i po krzyku. Nie wiem o co się rozchodzi... Dodam że aplikacji Portable (bez instalatora) problem nie powinno dotyczyć, bo to sprzeczne z założeniem aby one miały przechowywać stale jakiekolwiek ustawienia zwłaszcza dla wszystkich użytkowników.

0
furious programming napisał(a):

Do tej gałęzi rejestru domyślnie nie można nic zapisywać na systemach młodszych od WinXP;
Akurat to nie jest problemem w obecnych czasach jak dla mnie.

furious programming napisał(a):

Wiadome - dobre miejsce na wspólne dla maszyny informacje (tak samo jak CSIDL_COMMON_APPDATA), jednak uprawnienia... No i też wiadome, że w projekcie można zaznaczyć poziom uprawnień requireAdministrator i problem z głowy, ale czy na pewno?
Akurat ten konfig się nie zmienia aż tak często. Po prostu mam oddzielny program konfigurujący który trzeba uruchomić z uprawnieniami admina i już. Sama aplikacja swoje ustawienia zapisuje już w HKCU, ale to są ustawienia typu data ostatniego wejścia, ostatnio wybrana baza (bo baz może być kilka) czy ostatnio używany login w systemie. Więc to bardziej pasuje jako ustawienie per user. Taka konfiguracja nie sprawia większych problemów, więc zostaniemy przy niej jeszcze chyba długo. Problemy są tam gdzie informatyk jest daleko albo na urlopie. Jednak to już nie mój problem.

furious programming napisał(a):

Jedna rzecz to zasady i dobre praktyki, a druga to techniczne sposoby rozwiązywania problemów i ich implementacja;
Tak, sam poszukuję miejsca gdzie by można trzymać ustawienia "per machine" i gdzie można by pisać bez uprawnień admina, ale nie mam nic sensownego.

furious programming napisał(a):

Można za pomocą instalatora nadać poszczególnym katalogom prawa do zapisu, można wykorzystać requireAdministrator i teoretycznie mieć z głowy kwestię uprawnień, można też zmienić koncepcję i użyć lokalizacji, do których domyślnie prawa dostępu ma każdy użytkownik;
Prawda i takie podejście o którym piszesz jest chyba najlepsze.

furious programming napisał(a):

Sprawa nieco się komplikuje, jeśli aplikacja nie posiada instalatora, a potrzebuje zapamiętać jakieś konfiguracje; Robią tak np. różne emulatory (dla NES czy SNES), czyli tworzą pliki konfiguracyjne i katalogi obok pliku wykonywalnego.
Tylko dla mnie takie pisanie do katalogu programu jest z jednej strony złe, z drugiej dobre. Złe jeśli aplikacja ma instalator i instaluję w Program Files to też potrzeba uprawnień admina do zmiany. Natomiast dobre jest wtedy gdy to jest prosta aplikacja jak emulator o którym wspominasz. Wtedy mamy praktycznie aplikację portable bez żadnego wysiłku. Sam cenię sobie takie programy, bo lubię mieć na pendrive zestaw podstawowych programów.

0

Akurat to nie jest problemem w obecnych czasach jak dla mnie.

Tzn. nie jest to problemem dla aplikacji korzystających z uprawnień administratora oraz dla tych aplikacji, które z tego klucza tylko odczytują dane; Zapisywać też mogą, ale jak dobrze pamiętam, zostanie utworzona lokalna kopia zmodyfikowanych gałęzi, z czasem życia wynoszącym jedną sensję;

Akurat ten konfig się nie zmienia aż tak często. Po prostu mam oddzielny program konfigurujący który trzeba uruchomić z uprawnieniami admina i już. [...]

To akurat dobre rozwiązanie, pod warunkiem, że aplikacja odpalona przez zwykłego użytkownika nie potrzebuje modyfikować globalnych danych; Zapewne tak właśnie masz w swoim rozwiązaniu, więc wszystko gra;

Tak, sam poszukuję miejsca gdzie by można trzymać ustawienia "per machine" i gdzie można by pisać bez uprawnień admina, ale nie mam nic sensownego.

Zobacz na link, który podałem w pierwszym swoim poście w tym wątku - w drugim komentarzu facet wyjaśnia co i jak; O tym samym wspomniał także @kAzek dwa posty wyżej;

Jeśli aplikacja nie jest portable i posiada swój instalator, powinien on utworzyć wszystkie pliki i katalogi, a także w razie potrzeby nadać uprawnienia do zapisu; To że instalator musi być uruchomiony z prawami admina to normalna rzecz;

Prawda i takie podejście o którym piszesz jest chyba najlepsze.

Tzn. które? Podałem trzy różne możliwości; Jest jeszcze czwarta - wyłączyć UAC :D

Tylko dla mnie takie pisanie do katalogu programu jest z jednej strony złe, z drugiej dobre. [...]

Informacje o takich działaniach podałem jako kolejny przykład, który niestety działał na starych systemach, a od Vista w górę już może nie działać właściwie; W dzisiejszych czasach to nie jest prawidłowe podejście i nie należy traktować tego jako rozwiązanie;

Oczywiście nie ma to nic wspólnego z wersjami portable; Używam i widziałem dużo małych programów, które nie posiadają instalatora, ale potrzebują w plikach lub rejestrze przechowywać jakieś ustawienia (np. konfigurację klawiszy, ustawień interfejsu, sterowników, listę serwerów itd.); One zapisują dane obok exe chyba tylko dlatego, że powstawały na WinXP i nikomu nie chciało się przystosować aplikacji do wymogów, które stawia UAC;

PS: Ten wątek wcale nie dotyczy podstaw programowania, więc nie wiem dlaczego został założony w Newbie i dlaczego wcześniej nie przeniosłem go do odpowiedniej kategorii :]

0

Istotą kont użytkowników i konta admina jest, że zwykły użytkownik nie ma prawa grzebania w konfiguracji ani plikach innego użytkownika; może to tylko admin.
Więc jakąkolwiek konfigurację wspólną dla wszystkich powinien zapisywać wyłącznie administrator - czy to podczas instalacji programu, czy później z wykorzystaniem mechanizmu UAC.

Próbujesz to ominąć i stworzyć dziurę bezpieczeństwa. Możesz zrobić tak jak @kAzek zasugerował - ale ta przynajmniej jednorazowa interwencja admina podczas instalacji i tak będzie niezbędna.

1 użytkowników online, w tym zalogowanych: 0, gości: 1