Alle SQL Server enumerieren mit den OLE-DB Enumeratoren

Wie bekommt man eigentlich einfach eine Liste aller verfügbaren SQL-Server im Netz?

In der MSDN findet sich schnell ein Artikel How to enumerate available instances of SQL Server by using the SQLDMO components. Allerdings ist dieser Artikel wenig nützlich, denn SQL-DMO findet man nur noch selten auf einem Rechner.

Dabei ist es doch relativ einfach, denn OLE-DB sieht hierfür Enumeratoren vor. Aber auch die sind nicht sonderlich gut dokumentiert. In der SQL-2000 Server Doku findet sich noch ein Eintrag für den SQLOLEDB Enumerator. Für den neuen nativen OLE-DB Clienst für den SQL-Server finde ich nichts mehr dazu.

ATL stellt direkt Klassen zur Verfügung, die die Nutzung von Enumeratoren zu einem Kinderspiel machen.

Anbei ein Codeschnippsel der alle bekannten MS-SQL Server enumeriert. Ich beginne dabei mit dem neuesten Client (2008) und gehe die Schleife weiter bis zum ältesten Server Client (2000).
Wird ein Enumerator gefunden, und dieser lieferte Ergebnisse, dann wird die Schleife abgebrochen. Denn alle Enumeratoren liefern im Allgemeinen das gleiche Ergebnis.

Code:

//////////////////////////////////////////////////////////////////////////
// Main function to enumerate all servers with the appropriate
// known enumerators.

typedef std::set  TSET_CString;

void EnumSQLServer(TSET_CString &setSQLServer)
{
  // We may need the local server name. 
  // We replace the token (local) with the current computer name.
  CString strCompLocal;
  DWORD dwLen = MAX_COMPUTERNAME_LENGTH+1;
  ::GetComputerName(CStrBuf(strCompLocal,dwLen),&dwLen);

  // Loop over all enumerators we know
  static const PCWSTR aEnumerator[] =
  {
    L"SQLNCLI10 Enumerator",    // SQL 2008
    L"SQLNCLI Enumerator",      // SQL 2005
    L"SQLOLEDB Enumerator"      // SQL 2000
  };

  // Try all enumerators
  for (int i=0; i < _countof(aEnumerator); ++i)
  {
    // Check if we have an enumerator
    bool bFoundAny = false;
    HRESULT hr;
    CLSID clsid;
    hr = CLSIDFromProgID(aEnumerator[i],&clsid);
    if (SUCCEEDED(hr))
    {
      // Open enumerator and loop over all entries
      CEnumerator enumrator;
      hr = enumrator.Open(&clsid);
      if (SUCCEEDED(hr))
      {
        while ((hr=enumrator.MoveNext())==S_OK)
        {
          CString strServerName(enumrator.m_szName);

          // Skip empty server names 
          // (older enumerators return sometimes an empty name)
          if (strServerName.IsEmpty())
            continue;

          // Some enumerators return (local) for a local main
          // SQL server instance
          if (strServerName.CompareNoCase(_T("(local)"))==0)
          {
            ATLTRACE(__FUNCTION__ " found local computer\n");
            strServerName = strCompLocal;
          }

          // get uppercase server name
          strServerName.MakeUpper();

          // Insert in list and avoid duplicates with this, if
          // developer decides not to break the loop after the first
          // enumerator.
          if (setSQLServer.insert(strServerName).second)
            ATLTRACE(__FUNCTION__ " found server %s\n",
                  CT2A(strServerName.GetString()));
          bFoundAny = true;
        }
      }

      // After we have found data in one enumerator. There is no need
      // to do this again.
      // But a developer might decide to do this for every enumerator
      if (bFoundAny)
        break;
    }
  }
}

Ein lauffähiges Projekt kann man hier herunterladen: EnumSQLServer.zip.

Bug in der Windows UI: SetRedraw verändert WS_VISIBLE Stil in einem RTF Control

Ich habe eine relativ komplexe UI, die auch dynamisch Controls erzeugt. In diese Controls werden auch zum Teil Massen an Daten hineingeschoben. Damit alle Controls zeitgleich erst die Daten präsentieren verwende ich eine einfache Methode, die aus alten Windows Tagen stammt: CWnd::SetRedraw/WM_SETREDRAW. Man verwendet diese Nachricht zum Beispiel um das Flackern von Listboxen und Comboboxen zu verhindern, wenn man viele Daten einfügt.
Diese Nachricht wird von allen Fenstern unterstützt oder sollte unterstützt werden 😉

Meine Software macht nun folgendes:

  • Zuerst hat meine Ladeprozedur für die Daten, zuerst alle Controls erzeugt, oder überflüssige vernichtet und positioniert, oder evtl. nur ausgeblendet (ShowWindow(SW_HIDE). D.h. nach dem ersten Laden der Daten ändert sich am Layout evtl. nichts mehr.
  • Anschließend wurde an alle Controls CWnd::SetRedraw/WM_SETREDRAW mit FALSE gesendet.
  • Dann die Daten geladen.
  • Nach dem Laden wird einfach wieder CWnd::SetRedraw/WM_SETREDRAW mit TRUE gesendet und ein Invalidate durchgeführt.

Das funktioniert für alle Controls, mit einer Ausnahme: Das RTF Control. Wenn man WM_SETREDRAW TRUE an ein RTF Control sendet, das nicht sichtbar ist, dann wird dieses sichtbar. Der Stil WS_VISIBLE wird also verändert. 😮

Um das Problem zu isolieren habe ich hier ein kleines Testprogramm geschrieben. Der kritische Code sieht so aus. Das gesamte Projekt kann man hier auch herunterladen: Demoprojekt.

void CTestRTFSetRedrawDlg::OnBnClickedBtDoit()
{
 bool bWasVisible = (m_wndEdRTF.GetStyle() & WS_VISIBLE)!=0;
 m_wndEdRTF.SetRedraw(FALSE);
 m_wndEdRTF.SetWindowText(_T("Line 1\r\nLine 2\r\nLine 3\r\nLine 4"));
 m_wndEdRTF.SetSel(0,0);
 m_wndEdRTF.SetRedraw(TRUE);
 m_wndEdRTF.Invalidate();
 bool bIsVisible = (m_wndEdRTF.GetStyle() & WS_VISIBLE)!=0;

 // Check if the visible state changed
  if (bIsVisible!=bWasVisible)
  AfxMessageBox(_T("The visible state of the RTF control changed!"));
}

Nachtrag 16.01.2010 (Danke Sven für Deinen produktiven Kommentar):
Auch andere Controls wie Button-, Static– und Edit-Controls verändern den Visible Status wenn WM_SETREDRAW angewendet wird. Einzig Listbox– und Combobox-Controls behalten den Visiblestatus korrekt bei ❗

Nett: Windows 7 und sein GodMode ;)

Alleine der Name macht einen ja schon neugierig…

Was verbirgt sich dahinter?
Nichts anderes als eine Explorer Ansicht, die alles aus den Systemsteuerungspanels in einer Liste anzeigt. Nett…

Wie macht man das?

  1. Man legt auf dem Desktop (oder sonst wo) ein neues Verzeichnis an.
  2. Dieses Verzeichnis benennt man dann um in GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}
    Wobei der Name vor dem Punkt keine Rolle spielt. Es geht nur um die Extension und die GUID.
  3. Fertig! Das Symbol verändert sich dann auf das Symbol der Systemsteuerung.

Gefunden in: Understanding Windows 7’s ‚GodMode‘

Nachtrag 1: Das Ganze geht sogar unter Vista 32bit!
Nachtrag 2:
Es gibt Meldungen, dass dieser Link auf dem Desktop eines Vista 64bit Systems den Explorer zum Absturz bringt!
Evtl. sollte man den Ordner testweise in diesem Fall erstmal in einem Unterordner anlegen.
Nachtrag 3:
Auch Kay Giza berichtete ausführlich über diesen Modus, ich hatte dies allerdings übersehen.
http://www.giza-blog.de/Windows7VistaErweiterteSystemsteuerungAktivierenED7BA4708E54465E825C99712043E01C.aspx

CDialog::SetDefID und DM_SETDEFID, des Tastaturfreunds Liebling

Die Frage um die Eingabe-Taste in Dialogen und wie man diese „missbraucht“ (sage ich mal provokant) ist eine regelmäßige Frage in allen Foren.

Die Intention ist oft klar. Man möchte mit der Eingabetaste eine bestimmte Aktion verbinden, die evtl. sehr oft ausgeführt werden soll und nicht den Dialog schließen.
Die üblichen Wege sind schon mehrfach diskutiert worden und auch in meinem Blog finden sich dazu ein Artikel .

Zu kurz kommt bei dieser Diskussion die Funktion CDialog::SetDefID bzw. DM_SETDEFID Nachricht.
Was macht diese Funktion/Nachricht?
Sie definieren die Button-ID, die als Default-Aktion in einem Dialog ausgelöst werden soll und das ist nichts anderes als die Aktion die geschehen, soll wenn die Eingabe-Taste gedrückt wird.
Viele Entwickler definieren einfach OnOK um. Aber das eigentlich tolle ist mit SetDefID den Button in Abhängigkeit der Daten umzusetzen und das hat auch einen visuellen Effekt für den Nutzer.

Mal ein Beispiel:
Wir haben einen Dialog mit zwei List Views. Links Elemente die zur Auswahl stehen, rechts die Elemente in der Reihenfolge, die der Benutzer ausgewählt hat.
Der Mausschubser wird einfach die Einträge auf der linken oder rechten Seite doppelklicken und damit auswählen oder entfernen. Entsprechende Buttons für Hinzufügen und Entfernen wird es auch geben. Man kann also auch links oder rechts markieren und dann den Hinzufügen oder Entfernen Schalter nutzen.

Dem Tastaturnutzer können wir helfen indem wir intelligent CDialog::SetDefID / DM_SETDEFID verwenden. Die Vorgehensweise ist einfach.

  • Wir richten uns nur danach in welchem List View wir uns befinden, d.h. befinden wir uns im linken List View steuern wir den Hinzufügen Schalter, und im rechten List View steuern wir den Entfernen Schalter.
  • Wird also im linken List View ein Item ausgewählt, setzen wir mit CDialog::SetDefID / DM_SETDEFID die ID des Hinzufügen Schalters.
  • In dem Moment wird der Hinzufügen Schalter zum Default-Button. Der Nutzer kann nun die Eingabe-Taste drücken und die Items werden in die rechte Box verschoben.
  • Links liegt jetzt nun noch der Fokus, aber es sind keine Items mehr markiert. D.h. wir setzen nun den Default Button zurück auf IDOK.
  • Jetzt kann der Nutzer erneut ein Item markieren. Der Default-Button wird wieder der Hinzufügen/Entfernen Schalter und die Eingabetaste macht was der Nutzer gerne hätte.
  • Ist kein Item mehr markiert schließt die Eingabetaste wieder über IDOK den Dialog.

Ohne Maus kann man also mit den Pfeiltasten, der Leertaste (evtl. Strg-Taste) und der Eingabetaste diesen Dialog bedienen. Und das sogar intuitiv, denn der entsprechende Default Button wird ja in der UI schön umrandet und hervorgehoben.
Das freut jeden Tastaturfreund. Und man muss gar nichts groß machen mit der Behandlung Eingabetaste.

Damit das Ganze nicht so abstrakt ist, habe ich ein kleines Sample gebaut, dass diese Anwendung zeigt. Es hat keine Implementierung für Drag&Drop aber es macht deutlich, wie man dem Tastaturnutzer entgegen kommen kann indem man die Controls geschickt aktiviert.

MD 81335 DVD-Recorder Laufwerk erfolgreich in ein LG-GSA-H44N getauscht

Ich habe schon seit langer Zeit einen MD 81335 HD/DVD-Recorder (Baugleich LG RH188). Ich liebe das Ding, weil ich dann das sehen kann was ich will, ohne Werbung und dann, wenn es in meinen Zeitplan passt.
Den DVD Recorder habe ich nie benutzt, aber den DVD-Player.
Seit einiger Zeit dauerte es immer länger bis DVDs erkannt wurden. Besonders neuere DVDs mochte das MD 81335 gar nicht mehr lesen. Sehr zum Leidwesen meiner Tochter.

Nach etwas Recherche im Netz kam ich zu dem Schluss, dass man DVD Laufwerk einfach vergessen kann. Defekt ❗

Ein entsprechendes Original-Laufwerk war nicht aufzutreiben und auch nicht über den Elektronik-Fachhändler meines Vertrauens. Wenn man aber weiß, dass das MD 81335 ein baugleiches LG-RH188H ist, dann findet man im Netz doch einige hilfreiche Tipps zu diesem Gerät.

Auf der Seite http://ifndef.altervista.org/index_eng.html habe ich dann einige Anleitungen gefunden, wie man das DVD-Laufwerk tauschen kann gegen andere LG kompatible Laufwerke. Ich habe mich bei den vorgeschlagenen Möglichkeiten für ein LG-GSA-H44N entschieden, dass ich für ein Paar Euros auf Ebay ersteigern konnte.

Der Umbau ging dank der tollen bebilderten Anleitung perfekt. Alleine der erste Start des Rekorders klappte nicht. Der alte Recorder hatte keinen Jumper auf dem Master/Slave Selektor gesetzt. So habe ich auch das neue LG-GSA-H44N eingebaut. Dann startet der Rekorder allerdings nicht. Nachdem ich dann erst dachte ich habe einen Fehler beim Zusammenbauen gemacht hatte, habe ich doch noch mal den Jumper gesetzt auf der Master Position. Siehe da, alles geht wieder und DVDs können auch wieder abgespielt werden.

VS-Tipps & Tricks: Springe zur nächsten Klammer funktioniert auch für #if, #elif, #else und #endif

Wer sich schon durch die Windows Header gekämpft hat um herauszufinden warum welche Definition einer Struktur oder Funktion in irgend einer Windows Version so oder gar nicht vorhanden ist, der weiß auch wie einem #if, #elif, #else und #endif das Leben schwer machen können, was die Orientierung betrifft.

Netterweise hilft einem eine Funktion, die man nur von Blöcken und verschachtelten Funktionen her kennt Strg+´ (Edit.GotoBrace). Wichtig! Man darf nicht auf der Variable oder Bedingung stehen, sondern muss auf dem Schlüsselwort stehen.

Wenn man auf einer Präprozessor Direktive kann man mit den Tasten die einem zur passenden Klammer bringt zur nachfolgenden Direktive. Und mit dem Festhalten der Umschalttaste kann man den entsprechenden Block auch markieren.

Defekte Festplatte die Zweite – oder – Bloggen lohnt sich ;)

Letzte Woche ist mir ja eine Festplatte kaputt gegangen.
http://blog.m-ri.de/index.php/2009/12/10/mist-festplatte-hinueber/

Das muss ich jetzt korrigieren:
Die Festplatte war nicht defekt, Sie hatte nur einen Defekt im BIOS.

Sven hatte mich in einem Kommentar auf Probleme mit Seagate Festplatten vom Typ Baracuda 7200.11. Genau diesen Typ habe ich (ST3500620AS). Ich hatte auch bereits einen Case beim Fujitsu-Siemens Support eröffnet. Aber einen Versuch die kompletten Daten wieder zu erhalten wäre es ja wert.

Also habe ich bei Seagate angefragt und anhand der Seriennummer war schnell festgestellt, dass die Festplatte betroffen sein könnte. Der Seagate Support hat die Abholung per TNT-Express arrangiert und Montagabend war die Festplatte schon in Amsterdam bei i365. Am Donnerstag war die Platte zurück bei mir. Kostenlos!
Heile mit allen Daten ❗ Seagate hat nur die Firmware geflasht.

Wäre es ein anderer Defekt gewesen, hätte Seagate mir ein kostenpflichtiges Angebot für eine Festplattenreparatur gemacht.
Schade, dass mich der Fujitsu-Siemens Support nicht auf diese Möglichkeit hingewiesen hat.

BTW: Mit der Hilfe eines Prüfprogrammes von Seagate habe ich auch alle anderen 6 Festplatten geprüft und anschließend geflashed. Allehatten den den selben fehlerhaften BIOS verwendet.
http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931&NewLang=de&Hilite=

PS: Und nochmal vielen Dank an Sven für seinen sehr nützlichen und hilfreichen Kommentar ❗

Installation älterer Software auf Windows-Vista oder Windows 7

Jetzt wo sich Windows 7 langsam immer weiter verbreitet werden manche Benutzer feststellen, dass Windows 7 so viel anders als Vista nicht ist.
Insbesondere wenn es um Probleme mit älterer Software geht.
Ja es gibt den XP-Modus unter Windows 7, aber manchmal geht es eben doch mit ein paar Tricks und man die Software richtig installieren ohne XP-Mode-Overhead.

Ich habe die Erfahrung gemacht, dass die Virtualisierung durch UAC einiges leistet und dafür sorgt das einiges an Software unter Vista und Windows 7 laufen kann.
Ansonsten kann man manchmal nachhelfen, wenn man dem Programmen auf die entsprechenden Ordner in Program Files und HKLM in der Registry die Rechte für einen normalen Benutzer auf Vollzugriff setzt.
Ich mache dies nur für die Teiläste dieses Programmes, insofern kein allzu großes Sicherheitsrisiko, aber es wirkt oft Wunder. Unter XP habe ich damit ältere Siedler Versionen zum Laufen gebracht ohne das man Administrator sein musste 😉

Leider gibt es aber auch Fälle in denen die Software schon die Installation verweigert. Auch hier kann man manchmal auf einem XP Rechner installieren und dann die Software kopieren.
Aber es gibt auch hier Tricks, wenn einfach nur die Versionnummer falsch geprüft wird (was leider ziemlich oft passiert).

In meinem Beispiel war es RC-WinTrans, dass die Installation schon unter Vista verweigert hat.
Ein Blick mit Orcas in die MSI Datei zeugt eine falsche Versionsprüfung:

Installation unter Vista Windows 7-1

Unschwer zu erkennen, dass hier explizit auf die unterstützten Versionen geprüft wird und die Version 6.x für Vista und Windows 7 eben nicht durch diesen Test abgedeckt sind.

Mit Orcas ist das schnell geändert:

Installation unter Vista Windows 7-2

Und siehe da. Nicht nur die Installation läuft einfach und glatt.
Die ganze Software arbeitet perfekt unter Vista und Windows 7.

BTW: Wenn man eine EXE hat, die die Installation ausführt, dann kann man versuchen über den Karteireiter Eigenschaften der EXE Datei, den Kompatibilitätsmodus auf Windows XP SP2/SP3 zu setzen. Auch dann gelingt einem oft die Installation selbst wenn eine falsche Versionsnummer intern im Setup geprüft wird.

Mist – Festplatte hinüber…

Ein Sch<zensiert>…</zensiert>tag.

Heute morgen komme ich in die Firma und schalte meinen Fujitsu-Siemens Quad-Core Desktop ein. Dann gehe ich in die Büroküche und setze Wasser für meinen Tee auf. Wenn ich damit fertig bin, erwartet mich normalerweise der Anmeldebildschirm von Windows.
Heute ❗ Nix. Schwarzer Bildschirm.

Um es kurz zu machen: Die Seagate Baracuda hat Ihren Geist aufgegeben. Nicht mal 1 Jahr hat sie es gemacht. Am 18.12.2008 wurde der Rechner gekauft, am 10.12.2009 Platte kaputt!
Da ich noch eine absolut baugleiche Festplatte in dem Desktop meines Kollegen hatte, habe ich sogar versucht die Elektronik alleine zu tauschen. Hätte ja sein können, dass nur nur die einen Hau hat. Nix!

Zum Glück habe ich Alles, was die Entwicklung betrifft in meinem TFS. Und von meinen aktuellen wichtigen, Arbeitsverzeichnissen ein Backup mit Acronis, das mal gerade 3 Arbeitstage zurück liegt. Ausgecheckt waren drei Dateien.
Nur mit dem Vollimage meines Rechners habe ich in der letzten Zeit geschlampt. Das liegt leider fast 2 Monate zurück und war direkt vor meinem Update von Vista auf Windows 7.
Das nächste volle Backup hatte ich jetzt fest für das Wochenende geplant. Leider zählt die Absicht nicht!

Verloren habe ich einige interessante Testprogramme, die ich nicht im TFS und auf keinem Backup, Stick oder SD-Karte hatte und einige Downloads die ich in den letzten Wochen gemacht hatte und die noch zu archivieren waren. Und natürlich die Zeit um den Rechner wieder mit allen wichtigen Werkzeugen auszustatten.
Ärgerlich…

Was lernt man daraus: Mit Backups darf man nicht warten ❗
Das ist in 30 Jahren der erste Crash, der mich ärgert.  Sonst mache ich in der Firma und auf meinem privaten PC mit Acronis Trueimage grundsätzlich zum Wochenende hin ein Backup (1 Vollbackup dann 4 Wochen inkrementell).

Windows Integrity Control: Schreibzugriff auf eine Named Pipe eines Services über anonymen Zugriff auf Vista, Windows 2008 Server und Windows 7

Mein Problem war ein Service, der eine Pipe als Interface zur Verfügung stellt, auf die von beliebigen PCs zugegriffen werden soll. Insbesondere eben auch von PCs außerhalb der Domäne in der der Service läuft der die Named Pipe zur Verfügung stellt. Die Clients melden sich über VPN an dem entsprechenden Server an, gehören aber eben selbst nicht zur Domäne.

Von einem Rechner, der nicht in der Domäne des Rechners liegt, auf eine Pipe eines Rechners in einer Domäne zuzugreifen war schon immer mit extra Vorkehrungen verbunden. Der Code für den anonymen Zugriff auf eine Pipe finden wir als KB Artikel http://support.microsoft.com/kb/813414/en-us. Über die Qualität dieses Beispiels möchte ich mich hier allerdings nicht auslassen.

Dieses Sample ist nett für alle die XP und Windows 2003 Server nutzen. Und interessanter Weise funktioniert es auch auf Windows Vista, Windows 7 oder Windows Server 2008. Aber nur weil dieses Beispiel die Pipe nur lesend benutzt.

Dieses Programm berücksichtigt nicht die neuen Sicherheitsfunktionen von Vista, Windows 7 oder Windows Server 2008. Es klappt genau dann nicht, wenn der Server eben auf einem Vista, Windows 7, oder Server 2008 läuft UND die Pipe für Lesen und Schreiben geöffnet wird.  ERROR_ACCESS_DENIED (5) ist das was der Client dann bekommt, wenn die Pipe lesend und schreibend geöffnet werden soll.

Was ist das Problem ❓

Das Problem liegt in einem Sicherheitsmechanismus, der sogenannten Windows Integrity.
Ich rate jedem die Literatur der nachfolgenden beiden Links:

 

Kurzbeschreibung:
Prozessen oder auch anderen Systemobjekten wird ein Inegrity-Level zugeordnet.
Greift nun ein Prozess auf ein Systemobjekt zu, dann werden nicht nur die allgemeinen Rechte geprüft (z.B. Rechte für Anonymen Zugriff, oder die entsprechenden Gruppenrechte), sondern auch der Integrity Level dieses Prozesses wird mit dem der Ressource verglichen.
Liegt nun der Integrity Level des Clients niedriger als der Intergrity Level des Objektes, dann greift eine neue Policy, die dann festlegt was passiert. In den meisten Fällen bedeutet dies, dass der Lesezugriff zugelassen wird, aber der Schreibzugriff untersagt wird.

Übrigens passiert das gleiche, wenn man ein Addin für den IE8 auf Vista (und später hat). Der IE8 läuft im geschützten Modus und damit im Integrity Level Low. Normale Programme laufen im Integrity Level Medium.
Möchte nun das IE8 Addin eine Pipe oder einen Shared Memory Block eines Services oder eines „normalen“ anderen Programmes, schreibend öffnen, dann passiert das gleiche. Der Zugriff wird reduziert auf nur lesen.
Und dieses Thema wird hauptsächlich in der Doku und im Netz diskutiert (und zum Teil, gelöst).

Ich will das jetzt hier nicht über die Maßen ausdehnen. Ich kann nur anraten, die entsprechenden Artikel wirklich einmal zu lesen.

Jetzt zurück zu dem was NICHT in diesen entsprechenden Artikeln und Forumbeiträgen steht.

1. Anonymen Zugriff wird automatisch der Integrity Level Untrusted zugewiesen. Die Doku zeigt in dem Beispiel nur die Vorgehensweise für den Integrity Level low.
Mein Fehler war es, die ganze Zeit SECURITY_MANDATORY_LOW_RID zu verwenden. Aber ich sagte es schon: Der  Anonyme Zugriff erfolgt im Integrity Level Untrusted.

2. Ich arbeite mit SDDL String und auch dort in den Headern ist Low das niedrigste für das es im Netz und auch in der Doku (http://msdn.microsoft.com/en-us/library/bb625963.aspx) findet. Dort steht ziemlich weit unten ein Beispiel, um ein Objekt einem „Low“-Integrity-Prozess zugänglich zu machen. Und dort finden wir folgende SDDL Definition:

#define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"

3. Anonymer Zugriff ist also Integrity Level Untrusted (ich weiß ich wiederhole mich).
Und nun wird es spaßig. Es gibt auch gar keinen SDDL Sid für untrusted, es gibt nur die folgenden Definitionen in den Headern:

// Integrity Labels
#define SDDL_ML_LOW                         TEXT("LW")
#define SDDL_ML_MEDIUM                      TEXT("ME")
#define SDDL_ML_MEDIUM_PLUS                 TEXT("MP")
#define SDDL_ML_HIGH                        TEXT("HI")
#define SDDL_ML_SYSTEM                      TEXT("SI")

Alles das hat mich in die Irre geführt und 2 Tage Arbeit gekostet.

Als mir klar war, dass ich eine Regel für den Untrusted Intergity Level benötige, war die Lösung gefunden.
Bauen wir uns einen eigenen SID! Aus der Doku können wir die entsprechenden RIDs finden und uns nun folgenden SID konstruieren: „S-1-16-0“.
Und das bringt uns zu dem SDDL String für den Level untrusted:

#define UNTRUSTED_INTEGRITY_SDDL_SACL _T("S:(ML;;NW;;;S-1-16-0)")

Ich habe das oben beschriebene Sample etwas modifiziert, dass man genau dieses Problem des anonymen Zugriffs auf eine Pipe testen kann. Das Beispiel kann man hier herunterladen.
Ich habe das Sample dazu etwas umgebaut:

  • so dass lesender und schreibender Zugriff auch benutzt wird.
  • dass SDDL verwendet wird, was den Code extrem simplifiziert.
  • dass zumindest etwas an dem ekligem Code lesbarer wurde.
  • dass ein paar Bugs raus sind.

Ich bitte dennoch dies nur als Sample zu betrachten und nicht als Beispiel Software, die meinem Anspruch an C/C++ Code genügt 🙂

PS: Eine entsprechende Diskussion über das Problem findet sich in nntp://microsoft.public.de.vc
http://groups.google.de/group/microsoft.public.de.vc/browse_thread/thread/3be20505999b8aab
Danke noch mal explizit an den Regular Andreas Heyer für seinen wertvollen Diskussionsbeitrag.