Geschafft: Mein Software-Baby ist „Certified for Windows Vista“

Obwohl ich im Urlaub bin hat mich diese wirklich nette Nachricht von VeriTest erreicht:

Congratulations! AG-VIP SQL has successfully completed certification testing at VeriTest for the Microsoft “Certified for Windows Vista” logo program.

PS: Baby ist gut. AG-VIP SQL ist mittlerweile ein mittlerer Bolide… 😀

Vista beendet Programme auch wenn WM_QUERYENDSESSION FALSE returniert

Jeder kennt die nette Nachricht WM_QUERYENDSESSION die einem mitteilt, dass das System herunter gefahren wird, oder der Benutzer sich abmeldet.

Und wir alle sind auch einfach gewöhnt FALSE zu returnieren wenn wir das nicht wollen und damit waren wir sicher das WM_ENDSESSION mit FALSE gesendet wird und das System nicht herunterfährt. Ja! Richtig gelesen waren!

Das hat sich mit Vista nun auch geändert. Wird im lParam Bit ENDSESSION_CLOSEAPP (0x1) gesetzt, dann spielt es keine Rolle wie das Programm es gerne hätte. Die Applikation soll und muss beendet werden. D.h. die Applikation muss auch mit dem Zustand zurecht kommen, dass die Daten nicht gesichert sind, bzw. eben mit dem Zustand, der uns veranlasst hat FALSE zu returnieren.
Dies war bisher ausgeschlossen. Deshalb sollte man sich über das Verhalten seines Programmes an dieser Stelle mal Gedanken machen.

Für MFC Anwender noch eine kleine Herausforderung denn OnQueryEndSession wird von der MFC ohne Parameter aufgerufen und ohne das Vista SDK ist natürlich ENDSESSION_CLOSEAPP nicht definiert

#ifndef ENDSESSION_CLOSEAPP
#define ENDSESSION_CLOSEAPP 0x1
#endif

BOOL CMainFrame::OnQueryEndSession()
{
// Need to get the lParam value for this message to
// determine the reason of the shutdown
LPARAM lParam = AfxGetCurrentMessage()->lParam;
if (lParam & ENDSESSION_CLOSEAPP)
{
  // We are forced to exit here, the user want to close the
  // application, even if we loose data
  OnForcedShutdown():
  return TRUE;
}
else
  // do the default
  return __super::OnQueryEndSession();
}

BTW: Eine normale MFC Applikation berücksichtigt dies nicht korrekt. Es wird der Status von allen Dokumenten geprüft und evtl. einen entsprechender Dialog angezeigt, wenn eines der Dokumente nicht gespeichert ist. Wird aber die Anfrage mit ENDSESSION_CLOSEAPP gesendet, dann muss die Antwort in 5 Sekunden erfolgen. Einen Dialog anzuzeigen bzw. Frage zu stellen wie es die Standardimplementierung macht, passt hier nicht!

Man sollte sich unbedingt hier die Vista Änderungen zu Gemüte führen und gegebenenfalls auch ShutdownBlockReasonCreate implementieren.

Weitere Infos zu den Änderungen findet sich in der aktuellen MSDN:

Anmerkung: Jeder der sich mit der Vista-Zertifizierung auseinandergesetzt hat wird erkannt haben, dass es sich bei dem hier beschriebenen Verhalten um den Test Case 30 handelt, bzw. die Requirements, Reliability 3.1!

Ermitteln ob ein Prozess „als Administrator“ läuft oder nicht

Es gibt einigen Code im Netz, der ermittelt ob man administrative Rechte hat oder eben nicht.
Dazu wurden zwei Methoden meistens verwendet. Die meisten prüften ob im aktuellen Token der vordefinierte SID für den Administrator vorhanden war. Oder man verwendete NetUserGetInfo.
Besagte klassische Methoden sind auf Felix Kasza’s Win32-MPV Seiten (noch)* nachzulesen.

Leider berücksichtigt dieser Code nicht, dass es unter Vista ein sogenanntes Restricted Token geben kann. Theoretisch ist dies schon seit Windows 2000 und auch unter XP möglich. Nur richtig problematisch wird dies unter Vista, denn diese Restricted Token werden hier auch entsprechend verwendet.
Meldet man sich als Admin unter Vista an, dann meldet der Beispielcode, den man unter dem obigen Link findet, immer, dass der Benutzer Administrative Rechte hat! Egal ob nun der Prozess mit angehobenen oder ohne angehobene Rechte gestartet wurde.

Will also ein Programm das ein Trustinfo Manifest mit asInvoker hat wissen, ob es nun evtl. doch Als Administrator ausgeführt wird oder nicht, muss man das Restricted Token berücksichtigen. Dies macht der Code der in dem überarbeiteten KB-Artikel 118626 veröffentlicht wurde. Dieser Artikel hat in der Vergangenheit, die gleiche Methode verwendet die auch Felix Kasza’s (noch)* veröffentlicht.
Der neue Code den wir nun in dem KB-Artikel finden baut eine DACL auf mit der ACE des lokalen Admins, diese wird dann mit der Funktion AccessCheck gegen das aktuelle Token geprüft. Dieser Code ist nicht trivial und ist gut dokumentiert. Man sollte ihn sich wirklich mal komplett durchlesen. 

Das sehr interessante an diesem Code ist auch, dass er mit und ohne Trustinfo Manifest funktioniert. Er liefert TRUE wenn der Prozess mit administrativen Rechten läuft und FALSE wenn eben nicht.

Für was ist so etwas gut?
Nun man kann in seinem Programm auf diese Weise direkt ermitteln ob bestimmte Funktionen die z.B. schreibend auf die HKLM zugreifen erlaubt sind oder nicht. Sicher man könnte auch ein „Probe-Schreiben“, aber der in dem KB-Artikel beschriebene Weg ist mit Sicherheit eleganter.
Wobei das „Probe-Schreiben“ auch ein Trustinfo Manifest voraussetzt.

BTW: Der Code in dem KB-Artikel hat (noch)* einen lästigen Fehler. Er definiert ACCESS_READ und ACCESS_WRITE also const DWORD. Das ist unnötig mit den aktuellen Headern. Die Fehlermeldungen sind nicht ganz einfach zu verstehen. Am Besten einfach die beiden Zeilen auskommentieren.

*(noch) beschreibt den Zustand der entsprechenden Artikel, als ich diesen Beitrag schrieb. Das mag sich ändern, weil ich bereits entsprechende Emails über die Probleme mit den Beispielen geschrieben habe.

VS-2005 SP1 für Vista bringt kein Update für die MT.EXE

In meinem Beitrag UAC Trustinfo Manifest in ein VC-2005 SP1 Projekt einfügen habe ich berichtet wie man auf einfache Art und Weise ein UAC-Trustinfo-Manifest in ein VS2005 Projekt einbauen kann.

Dazu musste jedoch die MT.EXE aus dem Vista SDK in das entsprechende VC-Programmverzeichnis kopiert werden.

Ich hatte dies auch als Bug gemeldet und habe gehofft, dass dies auch im VS2005 SP1 für Vista noch behoben wird. Dem ist aber nicht so.
Die MT.EXE bleibt unverändert die Datei aus dem SP1 für VS2005. Und damit verbunden bleibt auch weiterhin das Versions Chaos. Wie schon berichtet haben beide Versionen aus dem Vista SDK und dem VS2005 SP1 die gleiche Versionsnummer. Wobei aber nur die Version aus dem Vista-SDK tut was man von ihr erwartet.

UAC und CreateNamedPipe mit lpSecurityAttributes==NULL

Das Leben steckt einfach voller Überraschungen. Da hat man einen Service der im LocalSystem Account läuft. Mit diesem Service wird über Named Pipes kommuniziert.

Das Programm, das diesen Service steuert soll nur für Administratoren verfügbar sein und greift lesend und schreibend auf diese Pipe zu. Der Admin nutzt dieses Programm oft, muss man dazu sagen.

In der Vergangenheit war da nicht viel zu tun. Einfach lpSecurityAttributes auf NULL setzen und OK. Der Admin hat dann einfach das Steuerungsprogramm gestartet und war glücklich.
Nun unter Vista läuft aber das Steuerungsprogramm nicht mehr mit administrativen Privilegien.

  • Ist das Programm nicht Vista aware (also hat kein Trustinfo Manifest), dann hat man keinen Zugriff auf die Pipe. Den in diesem Fall wird der Admin Token ausgefiltert!
  • Ist es Vista aware und man setzt asInvoker als Trustinfo, dann hat man auch keinen Zugriff. Logo.
  • Nur requireAdministrator führt zum gewünschten Ziel. Natürlich wieder mit der (manchmal) lästigen Meldung für ein Programm das häufig benutzt wird.


❗ Also liebe Programmierer Gemeinde! Bitte die SECURITY_ATTRIBUTES richtig ausfüllen mit einer DACL die eben nicht mehr nur den lokalen Admin enthält.  Diese bei CreateNamedPipe verwenden und dann kann das Programm auch normal mit asInvoker gestartet werden.

Ach ja! Und ehe ich es vergessen ein NULL DACL ist hier nicht im Sinne des Erfinders… 🙂

😐 Insgesamt ärgerlich:
Man möchte es dem Benutzer möglichst einfach machen Programme zu nutzen. Der Vista-Admin-Privileg Dialog stört da manchmal (nicht immer). Also was macht man? Man setzt die Rechte für die Names Pipes und andere Objekte dieser Welt herunter, weil der Admin Token eben nicht mehr Bestandteil der Rechte ist für Programme die mit asInvoker gestartet werden.
Die Folge: Die Programme werden mit weniger Sicherheitsschranken gebaut, als zuvor.
War das im Sinne des Erfinders?

BTW: Da man sich mittlerweile schon blind angewöhnt hat, diesen Dialog zu bestätigen kann man sich fragen ob da noch ein Sicherheitsaspekt verbleibt, weil keiner mehr liest, welches Programm eigentlich administrative Rechte haben will.

UAC Trustinfo Manifest in ein VC-2005 SP1 Projekt einfügen

An sich ist die Sache ganz einfach. Man erzeugt eine Manifest-Datei z.B. mit dem Namen Trustinfo.manifest, die nur den entsprechenden <trustinfo> Block enthält (und nicht mehr). Um die anderen Manifest Daten für CRT und COMCTL32 v6.0 kümmert man sich erstmal nicht, das soll ja MT.EXE und der Linker machen. Diese Datei fügt man in das Projekt ein. VS erkennt die Endung und der Manifest-Compiler soll diese Datei nun mit den anderen Manifest Daten mischen und das finale Manifest erzeugen.
Man wirft den Compiler an und… 🙄 … erhält die Fehlermeldung:
.\TrustInfo.manifest : manifest authoring warning 81010002: Unrecognized Element „requestedPrivileges“ in namespace „urn:schemas-microsoft-com:asm.v3“.

Entsprechende Recherche ergab, dass nur die MT.EXE aus dem Vista SDK dieses Manifest korrekt einmischt. Die funktionierende MT.EXE hat es nicht in das 2005 SP1 gepackt 🙁 .

OK also Vista SDK herunterladen installieren. MT.EXE ansehen und… 🙄
Die MT.EXE aus 2005 SP1 ist vom 2006-12-02 07:17,
die MT.EXE aus dem Vista SDK ist vom 2006-10-19 14:52,
beide haben eine Größe von 727.552 Bytes und haben die gleiche Versionsnummer 5.2.3790.2075. Es ist nicht zu fassen.

OK packen wir also trotzdem die MT.EXE aus dem Vista SDK in das Verzeichnis C:\Program Files\Microsoft Visual Studio 8\VC\bin

Nun kompilieren wir das Projekt noch einmal und nun… :mrgreen:
wunderbar, das Projekt kompiliert wie erwartet. Das Manifest wird eingefügt. Die erzeugte EXE hat alle entsprechenden Manifeste eingebettet.

Wen es interessiert, die Bug-Meldung bzgl. der Versionsnummer ist hier zu finden:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=258108

Es sei noch angemerkt: Mein Testrechner ist ein Vista-Ultimate Laptop. Installiert war auch das VS-2005 SP1 Beta für Vista. Auch diese Version enthält keine kompatible MT.EXE!
Danke Jochen für den Hinweis!

Notwendigkeit von Manifesten für DLL’s mit VC-2005

Durch eine Anfrage in meiner Lieblingsgruppe microsoft.public.de.vc bin ich auf folgende interessante Frage gestoßen: Benötigt eine DLL die mit VC-2005 erzeugt wurde ein Manifest?

Nun wie viele Antworten im Leben lässt sich dies nicht eindeutig mit Ja oder Nein beantworten.

Nein! Es wird kein Manifest benötigt, wenn die CRT statisch gelinkt wird. In diesem Fall wird auch kein Manifest benötigt zumindest nicht für die CRT, was nicht heißt, dass nicht auch andere Assemblies per Manifest angebunden werden müssen.

Nein! Wenn die EXE-Datei bereits über ein Manifest verfügt und eine CRT-DLL mit gleichem Namen lädt, hier also z.B. die MSVCR80.DLL. In diesem Fall kann man sich ein Manifest sparen. Es kann aber hier spannend werden, weil die entsprechende DLL natürlich so nicht beeinflussen kann dir 8.0 CRT als SP1 oder RTM zu nutzen. Aber vermutlich ist das sowieso egal.

Ja! Die DLL benötigt ein Manifest, wenn ein beliebiges Programm die DLL nutzt. Zum Beispiel eines, das die CRT statisch linkt, oder das mit einer älteren VC Version erzeugt wurde. In diesem Fall muss die DLL zwingend ein Manifest haben. Und jetzt wird es noch strenger. Wird die DLL per LoadLibrary geladen, dann muss dieses Manifest sogar embedded sein! 🙄
Externe Manifeste bei DLLs werden nur beim impliziten Laden berücksichtigt. Wird eine DLL mit LoadLibrary geladen, dann werden nur eingebette Manifeste berücksichtigt.

❗ Falle: Hat die DLL kein Manifest wird immer garantiert, dass die CRT Version von EXE und DLL passen. Man kann also gefahrlos Speicher in der DLL allozieren und in der EXE freigeben und umgekehrt. Oder eben auch CRT Objekte austauschen. Nutzt die DLL ein eigenes Manifest besteht die Möglichekit, dass EXE und DLL eine unterschiedliche CRT verwenden! Und noch spannender wird es wenn eine EXE mit CRTx eine DLL1 benutzt die per Manifest CRTy verwendet und diese nun eine DLL ohne Manifest lädt… Ja es wird die CRT der EXE verwendet…

Ja ja. Wir haben dank der Manifeste nun keine DLL Hölle mehr. Wir haben eine Manifest Hölle 😀

Meine Empfehlung daher:

  1. Wenn es eigenständige kleine Module sind, dann statisch gegen die CRT linken.
  2. Ansonsten immer ein Manifest einbetten, wenn die DLL eigenständig genutzt wird!
  3. Wird die DLL im Kontext einer bestimmten EXE(s) Datei verwendet, sollte nur die EXE(s) ein  Manifest haben.
  4. In jedem Fall darauf achten, dass gleiche CRT Versionen verwendet werden. RTM, SP1 und irgendwann wahrscheinlich SP2 werden hier Konflikte möglich machen.
  5. MFC Extension DLLs müssen zwingend mit der selben MFC Version (RTM oder SP1) verwendet werden!

Stoff zum weiterlesen:
Isolated Applications and Side-by-side Assemblies

Besonders lesenswert hier der Beitrag von Nicola Dudar:
How to Debug ‚The System cannot Execute the specified program‘ message

Der VirtualStore und seine Schattenseiten

Es ist ja bekannt, dass Programme, die nicht mit einem entsprechenden Trustinfo Manifest ausgestattet sind, unter Vista besonders behandelt werden. Werden diese Programme nicht im administrativen Rechten ausgeführt werden alle Zugriffe auf das Verzeichne C:\Program Files und auf HKEY_LOCAL_MACHINE\Software in der Registry umgeleitet.

Ein Registry Zugriff landet dann in HKEY_CURRENT_USER auf HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\SOFTWARE. Ein Dateizugriff auf C:\Program Files wird umgeleitet nach C:\Users\Username\AppData\Local\VirtualStore\Program Files.

Was passiert aber nun, wenn der Administrator nun tatsächlich die „richtigen“ Daten in HKLM und C:\Program Files ändert UND es existieren bereits entsprechende Daten im VirtualStore?

Die Antwort ist logisch! Eine Änderung der Daten bleibt ohne Wirkung! Denn die Daten aus dem VirtualStore werden hier mit Vorrang behandelt. Sonst macht das ganze ja keinen Sinn, denn der VirtualStore soll ja scheinbar Schreibzugriffe erlauben.

Im Klartext: Existieren Daten sowohl im VirtualStore als auch in den eigentlichen originalen Positionen, dann werden immer die Daten des VirtualStore verwendet. Nur wenn der entsprechende Registry Key nicht vorhanden/gelöscht wird oder die entsprechende Datei nicht vorhanden/gelöscht ist, dann werden die Daten aus den original Verzeichnissen bzw. Registryästen verwendet.

Nur daraus folgt ein Problem:
Macht der Admin Korrekturen an den realen Daten UND es existieren Daten im VirtualStore, dann bleiben die Änderungen des Admins wirkungslos, bis er die Daten aus dem VirtualStore entfernt. Das kann eine spannende Aufgabe werden.
Vielleicht ist dies eine profane Erkenntnis, aber die Implikationen sind meines Erachtens immens.

PS: Gemein ist einfach, dass Software die bisher mit einer Fehlermeldung gerechnet hat, wenn ein Schreibversuch nach HKLM oder C:\Program Files erfolgte, nun auf einmal erfolgreich schreiben kann. Da kann man sich noch so sehr an alle Empfehlungen halten, hier wird man von Vista reingelegt und man muss schleunigst das entsprechende Trustinfo Manifest nachrüsten.

Vista und die Notwendigkeit eines Manifestes für die UAC

Bei den vorbereiten von Software für Vista (Certified for Vista) ist mir die UAC (User Access Control) untergekommen. Unter Vista verschärft sich das ganze noch einmal gegenüber Windows 2000.

Einen der wichtigsten Punkte möchte einfach mal hier darlegen.
Unsere Software ist so geschrieben, dass ein Admin entsprechende Einstellungen in bestimmten Dateien im Programmverzeichnis ablegen kann und auch Einstellungen vornehmen kann die in HKLM abgelegt werden. Unter anderem dienen diese Dateien/Registry Einstellungen eben zur Kontrolle von Services und IPC. Sie müssen eben in einem allgemein zugänglichem Bereich liegen. Das ist ja nichts ungewöhnliches.

Brav wie wir sind haben wir entsprechende Prüfungen eingebaut und sagen dem Anwender, wenn er keine Rechte hat in HKLM zu schreiben, oder die entsprechenden Dateien im Programmverzeichnis zu ändern, z.B. INI Dateien die mit WritePrivateProfileString geschrieben werden.

Vista ist es nun egal, dass wir brave Entwickler sind. Vista behandelt uns per UAC Richtlinie wie einen Bösewicht und leitet alle Änderungen in den lokalen Bereich des Anwenders. Meine Software hat keine Chance zu erkennen, dass das schreiben in HKLM und den Programm-Datei Ordner eigentlich nicht erlaubt ist.

Man muss also zwingend ein Manifest für die UAC hinzufügen:

<?xml version=“1.0″ encoding=“utf-8″?>
<assembly xmlns=“urn:schemas-microsoft-com:asm.v1″ manifestVersion=“1.0″>
  <trustInfo xmlns=“urn:schemas-microsoft-com:asm.v3″>
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level=“asInvoker“ />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

Erst mit diesem Manifest verhält sich meinem Programm wieder so, wie ich es auch erwarte!

Eine gute Anleitung hierfür:
– How To: Tell Vista’s UAC What Privelege Level Your App Requires
http://channel9.msdn.com/Showpost.aspx?postid=211271

Weitere Infos, Dokus und Hilfsprogramme:
– Understanding and Configuring User Account Control in Windows Vista
http://technet.microsoft.com/en-us/windowsvista/aa905117.aspx
– Windows Vista Application Development Requirements for User Account Control Compatibility
http://www.microsoft.com/downloads/details.aspx?FamilyID=BA73B169-A648-49AF-BC5E-A2EEBB74C16B&displaylang=en
– Microsoft Application Verifier
http://www.microsoft.com/downloads/details.aspx?familyid=BD02C19C-1250-433C-8C1B-2619BD93B3A2&displaylang=en
– Microsoft Standard User Analyze
http://www.microsoft.com/downloads/details.aspx?familyid=DF59B474-C0B7-4422-8C70-B0D9D3D2F575&displaylang=en