2014-04-15 13 views
7

Próbuję napisać (w języku C#) oprogramowanie, które komunikuje się z innym oprogramowaniem, zbudowanym z MSYS, przez emulowane (emulowane przez MSYS) gniazda domeny Unix. Nauczyłem się, że „serwer gniazdo” (nie jestem jasne, na co właściwe jest terminologia) tworzy plik tymczasowy o treści jak poniżej:Jaki mechanizm jest używany przez MSYS/Cygwin do emulowania gniazd domeny Unix?

!<socket >59108 282F93E1-9E2D051A-46B57EFC-64A1852F 

59108 odpowiada portu TCP, którego "socket server" nasłuchuje na interfejsie pętli zwrotnej. Za pomocą narzędzia do przechwytywania pakietów udało mi się ustalić, że "klient gniazda" łączy się z tym portem, a informacje są wymieniane za pośrednictwem interfejsu pętli zwrotnej.

Powieliłem to zachowanie w moim oprogramowaniu, a "klient gniazda" łączy się z moim portem nasłuchującym, ale żadne informacje nie są przesyłane. Sądzę, że jest tu jeszcze jeden krok, jeden prawdopodobnie obejmujący GUID w pliku "socket", ale nie byłem w stanie określić, co to jest. Co muszę zrobić, aby uruchomić komunikację od klienta?

Wygląda na to, że MSYS używa mechanizmu Cygwin, który wiąże się z nazwanym wydarzeniem, czyli (prawdopodobnie?) Stworzonym przez "serwer" i sygnalizowanym (podobno) przez "serwer", ale moją naiwną próbą wdrożenia wydaje się nie działać.

Znalazłem an email written by Conrad Scott, który opisuje różne niedociągnięcia w procesie "uzgadniania" i proponuje łatę, która rzekomo rozwiązuje je. W tym e-mailu Conrad opisuje nieco używany proces, a on wskazuje, że faktycznie są dwa zdarzenia, jeden zarządzany przez "serwer" i jeden zarządzany przez "klienta". Użyłem API Monitor do wyszukiwania wywołań CreateEvent(), a gdy jest ich kilka, nie mogę znaleźć takiego, który wygląda jak "dymiący pistolet" tutaj. Nie ma też interesujących wywołań CreateSemaphore(), więc wygląda na to, że łatka Conrada nigdy nie została zastosowana (lub przynajmniej została zastosowana jakiś czas po rozwidleniu CYSZA przez MSYSa).

Odpowiedz

3

Przynajmniej dla cygwin mogę teraz odpowiedzieć na twoje pytanie: Właśnie zaimplementowałem serwer gniazd kompatybilny z cygwin za pomocą MFC. Zrobiłem to, patrząc na źródło cygwin. Wygląda na to, że nie ma nawet wydarzeń. Wygląda na to, że łatka, o której wspomniałeś, nie została zaimplementowana.

Wszystko, co się dzieje:

1.) Plik tworzony jest gniazdo, GUID ("shared key") są po prostu przypadkowymi liczbami. 2.) Plik MUSI mieć atrybut "systemowy". Kod cygwin wykonuje pewne dziwne pozwolenia, jeśli jest na NTFS, nie przyjrzałem się temu. 3.) Utworzono gniazdo sieciowe na localhost z portem wskazanym w pliku gniazda.

Tak więc, gdy klient łączy się z gniazdem (poprzez TCP/IP):

4.) To pierwszy wysyła 4 liczb losowych do serwera; serwer sprawdza, czy są one ważne 5.) Serwer odsyła je 6.) Klient wysyła 3 32-bitowe numery: pid, uid i gid 7.) Serwer odsyła własną wersję tych numerów.

Nie rozumiem, jaki jest cel tego uścisku dłoni, ponieważ z punktu widzenia bezpieczeństwa jest całkowicie bezwartościowy.

+0

JFYI: Tak jest również w przypadku MSYS, mój serwer gniazd (agent SSH) działa zarówno dla klientów ssh/rsync MSMS cygwin, jak i MSYS. – divB

2

Pracowałam z czegoś, co działa poprawnie na kompilacji OpenSSH (SSH-agent.exe), który pochodzi z Git:

konfiguracji po stronie serwera składa się z następujących czynności: 1.Utwórz "tajny ciąg" składający się z czterech grup ośmiu cyfr szesnastkowych rozdzielonych myślnikiem ("-") 2. Słuchaj lokalnego portu 3. Utwórz EventWaitHandle z modułem EventResetMode.AutoReset o nazwie cygwin.local_socket.secret. [Secret string]. [tu wysłuchaj numeru portu z odwrotną kolejnością bajtów] 4. Zapisz plik "socket", który składa się z ciągu znaków! [numer portu tutaj, kolejność bajtów NIE odwrócona] [ciąg tajny]

Kiedy połączenie przychodzi, należy wykonać następujące kroki: 1. Otwórz uchwyt zdarzenia klienta za pomocą EventWaitHandle.OpenExisting(), używając nazwy zdarzenia cygwin.local_socket.secret. [zdalny numer portu z odwróconą kolejnością bajtów]. [ciąg tajny] 2. Sygnał uchwyt zdarzenia serwera i czekać na uchwyt oczekiwania klienta sygnalizowany przez `EventWaitHandle.SignalAndWait()

Zgadzam się, że wygląda na to, że łatka omawiana na liście mailingowej nigdy nie została zastosowana. Wydana przeze mnie sekwencja wydaje się bliższa sekwencji omawianej na tej liście, a także pasuje do kodu wykopanego z Cygwin.

Nie rozumiem rozbieżności między tym, co znalazłem pracę vs co divB znaleźć pracę, ale nie potwierdzają, że działał z oprogramowaniem używałem (GIT za OpenSSH)

1

Wydaje się, że zarówno odpowiedzi od divB i Mark są poprawne, ale oba pomijają pewne szczegóły, więc mam nadzieję, że jest to nieco bardziej kompletne.

Istnieją dwie różne implementacje tutaj. Nie zrobiłem wyczerpującego dochodzenia, kto realizuje których realizacja, ale jak to pisze, obecna wersja Cygwin wykorzystuje realizacja opisanego przez divB i msysgit wykorzystuje realizację opisanego przez Marka.

Inicjowanie serwera:

  1. Tworzenie gniazdo (AddressFamily = IPv4, type = Stream Protocol = TCP). (.NET/MFC)
  2. Powiąż z pętlą zwrotną (127.0.0.1). (.NET/MFC)
  3. Powiedz gniazdu, aby nasłuchiwał. (.NET/MFC)
  4. wygenerować losowy GUID 16-bajtowy.
  5. Utwórz plik o następującej treści opartych na porcie TCP i GUID. Za pomocą oryginalnego przykładu, gdzie 59108 jest port TCP, a 282F93E1-9E2D051A-46B57EFC-64A1852F jest identyfikatorem GUID.

    W cygwin realizacji, zawartość pliku gniazdo to:

    !<socket >59108 s 282F93E1-9E2D051A-46B57EFC-64A1852F 
    

    I w realizacji msysgit, zawartość pliku gniazdo to:

    !<socket >59108 282F93E1-9E2D051A-46B57EFC-64A1852F 
    

    Różnica jest ekstra "s" pomiędzy port i identyfikator GUID.

  6. Ustaw atrybut systemu na tym pliku.

  7. Tylko w implementacji msysgit Utwórz nazwany uchwyt oczekiwania o nazwie cygwin.local_socket.secret.58598.282F93E1-9E2D051A-46B57EFC-64A1852F (InitalState = False, Reset = AutoReset).(.NET/MFC)

    58598 pochodzi stosując HostToNetworkOrder funkcję gniazda (w postaci 16-bitową liczbę całkowitą bez znaku). tj. 59108 == 0xE6E4 i 58598 == 0xE4E6.

obsługi połączeń:

  1. Zebrane gniazdo przychodzące. (.NET/MFC).
  2. W przypadku tylko cygwin wdrożenia zrobić uścisk dłoni, który składa się z:
    1. Przeczytaj 16 bajtów. Jeśli te nie pasują do identyfikatora GUID, a następnie nie.
    2. Wyślij to samo 16 bajtów.
    3. Odczytaj 12 bajtów jako 3 32-bitowe liczby całkowite. Są to pid, uid i gid procesu wywołującego.
    4. Wysyła 12 bajtów (3 32-bitowe liczby całkowite) z powrotem. Użyj pid serwera oraz odebranych uid i gid.
  3. W przypadku realizacji msysgit tylko synchronizować z klientem przez:
    1. Wirtualny port gniazda wejściowego. Na potrzeby tego przykładu powiemy, że jest to 63524.
    2. Otwórz istniejący uchwyt oczekiwania dla klienta. (.NET/MFC). Musisz przekonwertować port na kolejność bajtów sieciowych, tak jak to zrobiliśmy dla serwera. Tak więc, dla tego przykładu, nazwa to cygwin.local_socket.secret.9464.282F93E1-9E2D051A-46B57EFC-64A1852F
    3. Skieruj serwer i poczekaj na klienta (ToSignal = serwer, WaitOn = klient, Timeout = 10000 ms, ExitContext/Alertable = False). (.NET/MFC). Nie 100% pewności co do parametru ExitContext/Alertable, ale Fałsz wydaje się działać.
  4. Ręka gniazda do (mam nadzieję, że już istniejący) kod, niezależnie od tego, co robisz (co w przypadku całej naszej trójki wydaje się być agentem ssh).
+0

Zgodnie z https://cygwin.com/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/fhandler_socket.cc;hb=a9f4b71e8e63c363cd461aec3e0910dfd492e777#l345 kolejność poświadczeń procesu "pid, uid, gid", a nie "pid, gid, uid", jak określono tutaj, w kroku 2.3 i 2.4 – abourget

+0

Dzięki, zaktualizowałem swoją odpowiedź, aby zamienić zamówienie. –

+0

Dla zainteresowanych, napisałem pomyślną implementację w Go tutaj: https://github.com/abourget/secrets-bridge – abourget

Powiązane problemy