ETAP Pardus Programlama Notlarım – 1

Bu yazıda QR Kod (EBAQR) özelinde LightDM altyapısı hakkında yaptığım incelemeleri paylaşıyor olacağım. İncelediğim kısmı kadarıyla altyapının büyük kısmında kod emeği olan Bayram Karahan hocamızın emeğine sağlık.

“Sabit kullanıcı (ebaqr) giriş” ve “Kişiye Özel Giriş” giriş seçeneklerinin yer aldığı ETAP sistemlerde lightdm-greeter adlı grafik giriş yöneticisi kullanılıyor. Karşılama ekranını (login) oluşturan python kaynak kodları /usr/share/pardus/pardus-lightdm-greeter dizininde bulunabilir. Aşağıda ekran görüntüsü yer alan QR giriş seçenekleri main.py tarafından yüklenen module/ebaonline.py tarafından sağlanıyor.

Kaynak kod incelendiğinde bir WebKit.WebView() nesnesi içinde “https://giris.eba.gov.tr/EBA_GIRIS/studentQrcode.jsp” sayfasının yüklendiği görülebilir. Bu webview nesnesinin load-changed olayına bağlanan response_dataonline yordamı sayfa tazelendiğinde çalışacak şekilde ayarlanmış. Sayfanın tazelenmesi için EBA uygulaması üzerinden kamera ile QR kodu okutulması yeterli. Okutma gerçekleştikten sonra webview’de yüklü sayfaya taramayı yapan kullanıcıya ait JSON verisi EBA sunucusu tarafından geri döndürülüyor (Response). Sayfayı bir tarayıcıda açarak network hareketlerinden ilgili JSON verisini inceleyebilirsiniz.

ebaonline.py modülü JSON biçiminde gelen response verisi içerisinden gerekli alanları parsellenerek bir python listesine dönüşütürüyor. ebaonine.py modülünün python listesini oluşturmak için kullandığı alanların listesi aşağıdan görülebilir.

modül kodunun ilerleyen satırları incelendiğinde; oturumun açılması için bu veri yapısı TCP 7777’yi dinleyen bir prosese gönderiliyor. Veri yapısının gönderilmesi için aşağıdaki format kullanılmış.

Eğer “Sabit kullanıcı (ebaqr) giriş” seçilmiş ise sokete gönderilen veri şuna benziyor ebaqrebaqr:ozgur-koca:209823d20ad93948434

Eğer “Kişiye özel giriş” seçilmiş ise sokete gönderilen veri şunun gibi oluyor: ebaonline:ozgur-koca:209823d20ad93948434

İlk alandaki değerler ebaqrebaqr veya ebaqronline hangi kullanıcı ile oturum açılacağını söylüyor. Yani sabit kullanıcı olan ebaqr ile mi yoksa kullanıcının ad-soyad ile oluşturulan kişisel hesabı ile mi. Diğer alan ad (name) ve soyad (surname) alanlarından oluşturulan kullanıcı adını ifade ediyor. Son alan ise kullanıcının EBA üzerindeki kullanıcı ID’si ve bu kullanıcının geçici parolasını tanımlamak için kullanılıyor.

Öğretmen kullanıcılarının rol tanımı EBA sisteminde 2 ile ifade edilmiş. 39’un veli olduğu görülebiliyor. 300 ve 301 ile ilgili bir dökümantasyon paylaşılmamış.

TCP 7777’ye gönderilen bu veri ilgili kullanıcı hesabının oluşturulması ve oturum açılması için yeterli. Komut satırında aşağıdaki komutu vererek ali-candan isimli kullanıcının oluşturulmasını ve otomatik olarak oturum açılmasını sağlayabilirsiniz.

Burada netcat aracı echo ile pipe edilen verinin TCP 7777. porta yazılmasını sağlamak için kullanılmış. TCP 7777’yi hangi prosesin dinlediğini görmek için lsof komutundan faydalandığımızda:

PID numarası 771 olan tcpserver adından bir binary olduğunu görüyoruz. Bu binary’iyi hangi prosesin çalıştırdığını ya da dinlendiğini görmek için ise ps aracını aşağıdaki gibi çalıştırabiliriz:

TCP soketine gelen verilerin /usr/bin/pardus-lightdm-greeter-listener programına yönlendirildiğini görüyorum. Bu yapı bir systemd servisi ile (pardus-lightdm-greeter-listener.service) ayakta tutuluyor. Yani 7777. porta bir veri akışı olduğunda bu veri pardus-lightdm-greeter-listener programının başlatılmasında kullanılıyor. Bu program aslında bir bash betiği. Betiğin içinde kullanıcı hesabını oluşturan add_user() alt programının kodları ise aşağıdaki gibi:

Bu alt program incelendiğinde ali-candan ve ali-candan-qr isimli olmak üzere iki tane kullanıcı hesabı oluşturuyor ve gereki hesap ayarlarını (ev dizini, erişim izinleri, grup ayarları vb) yapıyor.

İkinci useradd komutuna baktığımızda ilkinden farklı olarak parola tanımının $defpass ile yapıldığını görebiliriz. Bu diğerinden farklı olarak ali-candan-qr kullanıcı adlı hesaba kullanıcı adı ile aynı ($defpass=”$user”) olan bir parolanın tanımlanmasını sağlıyor.

İstenilen hesabın oluşturulması ve oturumunun açılması için tcpserver’a veri akıtmak yerine veriyi dorudan bu betiğe göndermek de mümkün. Aynı sonucu yaratıyor. Buradaki tcp soket yaklaşımının nedeni uzaktan (ağ tabanlı) kullanıcı oluşturma/oturum açma isteği olabilir.

Betiğin tamamını incelediğimizde oturum açma işlemi için greeter_login() adındaki alt programa kullanıcı adı ve parolanın parametre geçildiğini görüyoruz. Aslında bu alt program /usr/share/pardus/pardus-lightdm-greeter/cli.py ile sembolik olarak bağlı /usr/bin/sshlogin‘in kendisi. cli.py’a sembolik link içeren bir diğer dosya da /usr/bin/pardus-login konumunda bulunuyor.

Sonuç olarak; yalnızca var olan bir kullanıcının oturumunu açmak için sshlogin ve diğer sembolik aracıları devreden çıkartarak aşağıdaki komut da çalıştırılabilir. Buradan yola çıkarak cli.py modülünün lightdm aracılığıyla oturum açmaktan sorumlu olduğunu söyleyebiliriz.

Bu incelemeleri yaptığım sırada şunu farkettim; betik kullanıcı hesaplarını oluşturduktan sonra bazen oturum açmada başarısız oluyor ve tahta siyah ve boş bir ekranda kalıyor. Bu durum systemctl restart lightdm ile greeter’ın yeniden başlatarak çözülüyor fakat “/usr/bin/pardus-lightdm-greeter-listener: satır 90: Masaüstü: komut yok” dan da anlaşılacağı üzere betikde bir hata var (Ocak 2024 itibariyle güncellenmiş bir sürümdeyiz). 90’ı satıra baktığımızda yorum satırının # ile kapatmasının unutulduğunu görüyorum. Ancak bu betiğin çalışmasını etkilemeyecek önemsiz bir hata.

Oturumun açılmasını sağlayan betik parçası aşağıdaki gibi, burada 4 saniye aralıkla iki kez giriş işlemi yaptırılmış. Eğer grafik ekranda “Sabit Kullanıcı (ebaqr) Giriş” seçilmiş ise “$type” == “ebaqrebaqr” şartlı if bloğu, “Kişiye Özel Giriş” seçilmişse “$type” == “ebaqronline” şartlı if blok çalışıyor.

ebaqrebaqr if bloğuna bakacak olursak kullanıcı adı olarak ebaqr, parola olarak ise rastgele üretilen bir parola kullanılıyor.

lightdm tarafında oturum açma sürecinin nasıl işlediğini görmek için cli.py incelediğimizde aşağıdaki gibi kullanıcı adı ve parolanın json biçimine dönüştürülerek /var/lib/lightdm/pardus-greeter dosyasına append yani ekleme modunda yazdığını görüyoruz.

/var/lib/lightdm/pardus-greeter konumuna gittiğimizde ise bu dosyanın aslında bir named pipe (FIFO) olduğu anlaşılıyor. Bu pipe yukarıdakine benzer (tcpserver) şekilde prosesler arasında iletişim kurmak için kullanılan bir linux yöntemi. ls -la çıktısındaki p (pipe) takısından bunu anlayabiliriz. lightdm-greeter yani oturum açma ekranı aktif olduğunuda bu pipe’da mevcut oluyor. Kullanıcı oturum açtığında ise DELETE_SELF işlemi ile kendini siliyor (root@etahta:/var/lib/lightdm# inotifywait -m pardus-greeter ile görülebilir). Bu aynı zamanda önceki kod parçasında görüleceği üzere os.path.exists işlevi ile lightdm-greeter’ın etkin olup olmadığını sınamak için kullanılmış.

Görebildiğimiz gibi lighdm oturum açacak kullanıcıyı buradan kabul ediyor. Bu FIFO pipe’ı ise module/daemon.py tarafından dinleniyor ve aşağıda kod parçasından görüleceği üzer ekrandaki kullanıcı parola kutularını doldurarak lightdm.login() işlevini çalıştırıyor.

module/gtkwindow.py içinde tanımlanan login_handler() işlevi de son iş olarak self.kill_windowmanager() metodunu çalıştırarak Greeter’ı yok ediyor.

Açılışta başlatılan betikler

Grafik oturumun başlangıcında yürütelen yapılandırmalardan birisi olan /etc/xdg/autostart/newpassword.desktop içeriği incelendiğinde /usr/bin/newpassword.sh betiğini çalıştırdığı görülebilir. Betik $HOME/.config/np konumundaki dosyanın varlığını kontrol ederek kullanıcıya sifredegistir diyalog penceresini görüntülüyor. Bu betiğin içeriği aşağıdaki gibi:

Eğer kullanıcı sifredegistir binary’isini kullanarak bir parola tanımlarsa $HOME/.config/np (muhtemelen no password) konumunda boş bir dosya oluşturuluyor.

Yazar: Özgür Koca

Yazar - Tankado.com