rwx
, Dosya, Dizin
Bu yazıda, rwx
bayrak yani flag lerinin dosya ve dizinlerde ne anlama
geldiğini örneklerle anlatmaya çalışacağım.
Önceki yazılarda da bahsettiğim gibi Linux üzerinde bir dosya veya dizinin
izinleri 3 farklı kategoride verilmektedir: user yani dosya veya dizine sahip
olan kullanıcının izinleri, group yani dosya veya dizine sahip olan grubun
izinler ve others yani dosyanın ait olduğu kullanıcı ve grup dışında kalan
kişilerin sahip olduğu izinler. Her bir kategoride de 3 farklı, birbirinden
bağımsız izin türü bulunuyordu: r
, w
ve x
. Şimdi bunların anlamına
bakalım.
İzinlerin Kontrol Sırası
Kernel tarafında izinler ilk olarak kullanıcı izni ve sonra grup izni olarak kontrol edilmektedir. İşlem yapmak isteyen kullanıcı, üzerinde işlem yapılmak istenen dosya veya dizinin sahibi ise user izinleri kontrol edilir. Eğer kullanıcı aynı zamanda dosya veya dizinin sahibi olan gruba ait olsa bile tekrar bir kontrol yapılmaz. Yani kabaca şöyle:
if (kullanıcı == dosya/dizin sahibi kullanıcı)
user izinlerini uygula
else if (kullanıcı == dosya/dizin sahibi gruba ait)
group izinlerini uygula
else
others izinlerini uygula
Şimdi bunu göstermek için bir örnek yapalım:
ay@400:~/sys $ echo "Yazı" > yazi.txt
ay@400:~/sys $ ls -l
total 4
-rw-r--r-- 1 ay ay 6 Jul 6 13:52 yazi.txt
ay@400:~/sys $ chmod u-rw yazi.txt
ay@400:~/sys $ ls -l
total 4
----r--r-- 1 ay ay 6 Jul 6 13:52 yazi.txt
ay@400:~/sys $ groups
ay
ay@400:~/sys $ cat yazi.txt
cat: yazi.txt: Permission denied
Yukarıda yazi.txt
isminde bir dosya oluşturuyorum, içinde de Yazı
yazıyor.
Bu dosya ay
kullanıcısına ve ay
grubuna ait. İlk ls
komutu ile ay
kullanıcısının rw
haklarının, ay
grubunun da r
hakkının olduğunu
görebiliyoruz. Hatta sistemdeki herkesin yani others grubunun da okuma hakkı
var. Daha sonra chmod
komutu ile ay
kullanıcısının tüm haklarını elinden
alıyorum. İkinci ls
te bunu görüyoruz, ay
kullanıcısının hiçbir hakkı yok,
---
yazıyor. Fakat ay
grubunun ve aslında sistemdeki tüm kullanıcıların r
yani okuma hakkı var. groups
komutu ile ay
grubuna ait olduğumu görüyorum.
Fakat cat
ile dosyayı okumaya çalıştığımda yetki hatası alıyorum. Aslında
dahil olduğum ay
grubunun okuma hakkı var hatta sistemdeki herkesin yani
others ın bile hakkı var ama ben okuyamıyorum! Neden? Çünkü kernel kontrolü
yukarıda yazdığım pseudo code gibi yapıyor. Ben dosyanın kullanıcısı olduğum
için dosyanın kullanıcıya ait izinlerine tabi oluyorum. Tutup da şunu demiyor:
“Bu kişi aynı zamanda dosyanın ait olduğu grupta, onun izinlerini de
uygulayayım.” Elbette böyle bir durumda gariplikler ortaya çıkabiliyor, eğer
izinleri bu şekilde verirseniz. Yani dosya size ait, siz okuyamıyorsunuz ama
sizin dışınızdaki herkes okuyabiliyor. Kernel others ya da group izinlerine
bakarak size otomatik yetikler vermiyor.
Bu yüzden tipik olarak dosya/dizin izinlerinde izinler kullanıcıdan gruba ve diğerleri kısmına geçerken genelde kısıtlanarak geçer, diğer türlü garip durumlar oluşabiliyor. Bir başka deyişle grubun izinleri kullanıcıdan, diğerlerinin izinleri de gruptan fazla olmuyor.
Şimdi çeşitli minik deneyler üzerinden izinleri anlamaya çalışalım. Dosya
üzerindeki izinler kolay anlaşılıyor fakat dizin üzerinde izinler, özellikle x
izni, biraz karışabiliyor.
Tekrar: Dizin ve inode Kavramı
Önceki yazılarda inode kavramından ve dizinlerin aslında ne olduğundan bahsetmiştim. Bunu iyi anlarsak özellikle dizin izinlerinde işimiz daha kolaylaşacaktır. O yüzden biraz tekrar yapalım.
Şimdi bir dosya yarattığımız zaman, dosyanın içerisinde bir içerik oluyor, dosyanın adı oluyor ve dosya ile ilgili çeşitli bilgiler oluyor: izin bilgileri, yaratılma tarihi gibi şeyler. Bu tarz bilgileri meta data diyebiliriz. Yani bir dosyanın içeriğinin yanında dosya ile ilgili tutulan başka bilgiler de var. Linux, bu bilgileri 3 parçaya bölüyor:
Dosyanın adı
Meta data bilgileri
Dosyanın içeriği
Her bir dosyaya ait bir inode bulunuyor. İşte inode içerisinde dosyaya ait meta data bilgileri tutuluyor. inode içerisinde tutulan bilgilerden biri de dosyanın içeriğinin disk üzerinde nerede olduğu. Bunu C dilindeki pointerlara benzetebiliriz. inode içerisinde adeta dosyanın içindeki verinin diskte nerede olduğunu tutan bir pointer bulunuyor. Dosya adı ise ne inode, ne de dosya içeriğinde tutuluyor.
Linux üzerinde dizin yani klasör dediğimiz şeyler de aslında birer dosyadır,
fakat özel dosyalardır. İçerlerinde ise inode-dosya ismi
çiftleri adeta bir
liste gibi bulunur, dizin dediğimiz özel dosyanın içerisinde bu bilgiler yer
alır. Yani dosyanın ismi adeta dizinin bir özelliğidir. Hemen minik bir örnek
yapalım:
a
├── b.txt
├── c.txt
└── d
└── e.txt
Burada a
isimli bir dizin var. İçinde b.txt
ve c.txt
dosyaları var, bir de
d
isimli bir dizin var. Onun içerisinde de e.txt
bulunuyor.
$ ls -li a
total 4
392227 -rw-r--r-- 1 ay ay 0 Jul 6 17:59 b.txt
392228 -rw-r--r-- 1 ay ay 0 Jul 6 17:59 c.txt
392354 drwxr-xr-x 2 ay ay 4096 Jul 6 17:59 d
Şimdi burada a
nın içerisindeki girdilerin inode sayılarını da görüyoruz. O
halde a
dediğimiz dizinin içerisinde aslında şöyle bir şey yazıyor gibi
düşünebiliriz:
392227 b.txt
392228 c.txt
392354 d
Benzer durum d
için de geçerli:
$ ls -li a/d
total 0
392356 -rw-r--r-- 1 ay ay 0 Jul 6 17:59 e.txt
Benzer şekilde d
dediğimiz dizinin içinde de şöyle bir bilgi var:
392356 e.txt
Şimdi a
nın içeriğini tekrar düşünelim. Linux’ta dosya uzantıları pek anlamlı
değil. Yani b.txt
yerine b
diye de bir metin dosyası oluşturabilirdim. a
nın içeriğine baktığımız zaman bir liste şeklinde inode-dosya ismi
çiftleri
görüyoruz. Peki buradan b
veya d
bir dosya mı, dizin mi hatta daha da
açarsak socket mi anlayabiliyor muyuz? Hayır. Bunun için numarası verilen
inode’a gidip “Kardeş sen nesin?” dememiz gerekiyor. Dosya türüne bakmak, sık
yapılan bir iş. ls
dediğimiz zaman bile dosya türleri gösteriliyor. Özellikle
içeriği fazla olan dizinlerde veya recursive listelemede her girdinin türüne
bakmak için inode’a gitmemiz oldukça maliyetli. Bu yüzden Ext dosya sistemleri
tipik olarak dizin girdisi içerisinde dosya türü ile ilgili de bir bilgi
tutuyor. Benzer bilginin aynısı o dosyanın inode’u içerisinde de yer alıyor.
Fakat kavramları konuşmamız için dizin yapısını sadece inode-dosya ismi
çifti
olarak hayal etmek bizi yanıltmıyor. İşleri basit tutmak için böyle düşünmeye
devam edelim. Girdi türünün dizin içerisinde de tutulmasını işleri hızlandırmak
için bir önbelleğimsi mekanizma olarak hayal edebilirsiniz.
Yukarıdaki organizasyonu şöyle hayal edebiliriz:
Sıradan dosyalar üzerinde read ve write ın ne anlama geldiğini biliyoruz. execute kısmına en son bakalım. İş, dizinlere geldiği zaman daha çok karışıyor.
Ne demiştik, dizinler aslında inode-dosya adı
çifti tutan özel dosyalardır.
Diyelim ki bir dizin üzerinde sadece read hakkımız var ve başka bir hakkımız
yok. Bu durumda ne yapabiliriz? Alabileceğimiz iki bilgi var, içersindeki dizin
ve dosyaların isimleri ve inode bilgileri. a
dizininde sadece r
hakkım
olsun:
$ ls -l
total 4
dr--r-xr-x 3 ay ay 4096 Jul 6 17:59 a
a
nın içerisinde var olanları görebiliyor muyum? E hemen deneyelim:
$ ls -l a
ls: cannot access 'a/b.txt': Permission denied
ls: cannot access 'a/c.txt': Permission denied
ls: cannot access 'a/d': Permission denied
total 0
-????????? ? ? ? ? ? b.txt
-????????? ? ? ? ? ? c.txt
d????????? ? ? ? ? ? d
Hmm, ilginç şeyler oluyor. a
nın içerisinde olan dizin ve dosyaları gördük
fakat erişim hataları da aldık. Yani içinde olanları biliyoruz fakat içerisinde
olan şeylerin bilgileri elimizde yok, ?
işareti olarak geldi. Peki neden?
Çünkü dizin üzerinde execute yani x
hakkımız yok!. Dizinler üzerindeki x
hakkını şuna benzetebiliriz: Dizini okuyarak içerisinde bulunanların adlarını ve
inode bilgilerini aldık. Fakat içerideki şeylerin bilgilerini edinmemiz için her
birinin inode veri yapısına ulaşmamız gerekiyor. İşte bir dizinde execute
hakkımız olmadığı zaman o dizinin altında bulunan inode’lara erişemiyoruz gibi
düşünebiliriz. Örneğin b.txt
nin inode değerini biliyoruz fakat a
dizininde
x
hakkımız olmadığı için bu inode’un içeriğine bakamıyoruz. Dizinler
üzerindeki execute hakkını adeta bir geçiş noktası gibi de düşünebiliriz. O
dizinin içine de giremiyoruz.
$ cd a
bash: cd: a: Permission denied
Şöyle bir benzetme yapabiliriz:
Dizinleri kapısı olan birer oda gibi düşünelim. Bu kapının bir camı var ve
içeride de ışık var. Peki içeride ne var? Dizinin içerisinde bulunan dosya ve
dizinlerin isim ve inode bilgileri. Dizinler üzerinde r
ve x
haklarını şöyle
hayal edebiliriz:
r
YOK,x
YOK: Kapının anahtarı yok, içerideki ışık da kapalı. İçeriye giremiyoruz. Kapının camından baksak da içersi gözükmüyor. Yani dizinin içerisinde ne olduğunu da bilmiyoruz.r
VAR,x
YOK: Kapının anahtarı yok, fakat içerisinin ışığı yanıyor. İçeriye giremiyoruz. Ama kapının camından içeriye bakarsak ne olduğu gözüküyor. Dizinin içerisinde ne var ve nerede duruyor biliyoruz. Ama anahtarımız olmadığı için kapıyı açıp, içeriklere erişemiyoruz.r
YOK,x
VAR: Kapının anahtarı var, fakat içerisi karanlık. İçeride ne olduğunu göremiyoruz. Ama bildiğimiz bir içerik varsa ona devam edebiliyoruz. Yani zifiri karanlık ama yollar açık. Sadece nereye gideceğimizi bilirsek ilerleyebiliriz.r
VAR,x
VAR: Kapının anahtarı var, içerisi de aydınlık. Her şeyi görüp, yolumuza devam edebiliyoruz.
İşte kendimizi dosya sisteminde odalar yani dizinler arasında gezen biri olarak
hayal edersek cd
komutu ile ilgili odaya yani dizine girmeye çalışıyoruz. x
hakkımız yoksa yani odanın anahtarı bize verilmediyse içeriye de giremiyoruz.
Şimdi yukarıdaki örneğe geri dönelim. Sadece r
hakkımız vardı. Odanın içine
bakabildik, ışığı yanıyor ama içeriye giremiyoruz. Dikkatinizi bir şey çekti mi?
İsimle beraber bir bilgi daha var: tür bilgisi yani -
ve d
karakterleri.
Demiştik ki bunlar aslında ilgili inode içerisinde bulunuyor. Bunlara
erişemiyorsak, ls
komutu d
ve -
bilgilerini nerden alıyor? Biraz önce de
belirttiğim gibi aslında dizin içerisinde erişim kolaylığı için bu bilgiler
saklanıyor. Bu sayede r
hakkı ile görebiliyoruz. Yani aslında inode-isim-tür
şeklinde üçlü bir veri seti var gibi düşünebiliriz. Ama bu kısım bence gerçekten
önemli değil. Yani r
hakkı varken tür bilgisi görebiliyor muyuz sorusu bence
çok detay, ana konudan sapmayalım.
O zaman bir de inode bilgisini bulmaya çalışalım içerideki dosya ve dizinlerin.
a
yı okuyabildiğimize göre bu bilgileri alabilmemiz lazım değil mi?
$ ls -il a
ls: cannot access 'a/b.txt': Permission denied
ls: cannot access 'a/c.txt': Permission denied
ls: cannot access 'a/d': Permission denied
total 0
? -????????? ? ? ? ? ? b.txt
? -????????? ? ? ? ? ? c.txt
? d????????? ? ? ? ? ? d
Hmm, inode bilgisi yerine yine ?
aldık, en sağdaki. Niye böyle oldu? Bu ls
komutunun inode bilgisini edinme yöntemi ile ilgili. strace
ile
çalıştırırsanız statx
sistem çağrısını yaptığını görebilirsiniz. Bu çağrı direkt hedef dosya üzerinde
yapılıyor, a/b.txt
gibi. Fakat a
üzerinde x
hakkımız olmadığı için bu
sistem çağrısını ls
komutunun yetkisi yetmiyor. Yani ls
, a
nın kapısından
geçip içeriye ulaşıp bilgileri toplamak istiyor. Ama inode değerini
alabileceğimizi size göstereceğim:
$ find . -name b.txt -printf "%f - %i\n"
b.txt - 392227
find
komutu ile aynı sistemde b.txt
nin inode değerini alabildik. strace
ile bakarsak find
komutunun
stat çağrısı yaptığını
görüyoruz. Burada statx
veya stat
ile ilgili bir çıkarım yapmıyorum. Demek
istediğim şey ls
ve find
farklı birer program olduğu için farklı
davranabiliyorlar. find
komutu, dizin üzerinde execute hakkı olmadan
içerisinde bulunan dosyanın inode bilgisini bize verebiliyor.
Bence zor kısmı atlattık. Dizinde r
hakkımız varsa içeriğini görebiliyoruz ama
x
hakkımız yoksa o içeriklere erişemiyoruz, sadece adını görmüş oluyoruz hatta
dizinin içine de giremiyoruz.
Şimdi a
üzerinde sadece x
hakkımız olsun.
$ ls -l
total 4
d--xr-xr-x 3 ay ay 4096 Jul 6 17:59 a
a
nın içeriğine bakabilir miyiz?
$ ls -l a
ls: cannot open directory 'a': Permission denied
Hayır! Oda benzetmesine devam edelim. a
nın kapıları açık ama içerisi zifiri
karanlık. İçinde ne var bilmiyorum. Ama biz içinde b.txt
olduğunu biliyoruz.
Bunun içeriğine erişebilir miyiz?
$ cat a/b.txt
Ben b.txt nin icerigiyim
Cevabımız evet! Yani a
dan geçip b.txt
ye ulaştım ama b.txt
nin varlığını
bildiğim için.
Benzer şekilde cd a
diyerek de a
nın içine girebiliyorum ama her yer
karanlık. İçeride iken ls
dersem yine hata alıyorum, göremiyorum ki içinde ne
var!
Peki dizinlerdeki w
hakkı nedir. Dizinleri inode-dosya ismi
tutan bir dosya
gibi düşünürsek burada yazma hakkımız varsa bu listeyle de oynayabiliriz demek.
Ne yapabiliriz? Dosya isimlerini değiştirebiliriz. Yeni dosyalar ekleyebiliriz
ve dosya silebiliriz. Dosya silme işi ilginç. Bir dosyayı silmek için o
dosyaya yazma hakkımızın olması gerekmiyor. O dosyanın bulunduğu dizine yazma
hakkımız olsa bu yeterli. Bir dosyayı sildiğimiz zaman diskten silineceği
garanti değil, bu konuya hard ve soft link konusunda değiniriz. Ama bir örnek
yapalım.
a
ya rwx
haklarımı verip içine girdim, b.txt
dosyasından herkesin tüm
haklarını aldım.
$ ls -lah
total 16K
drwxr-xr-x 3 ay ay 4.0K Jul 6 17:59 .
drwxr-xr-x 3 ay ay 4.0K Jul 6 17:59 ..
---------- 1 ay ay 25 Jul 6 19:16 b.txt
-rw-r--r-- 1 ay ay 0 Jul 6 17:59 c.txt
drwxr-xr-x 2 ay ay 4.0K Jul 6 17:59 d
ay@400:~/sys/a $ cat b.txt
cat: b.txt: Permission denied
ay@400:~/sys/a $ echo "yazma denemesi" > b.txt
bash: b.txt: Permission denied
Ne yazabiliyorum ne okuyabiliyorum. Peki silebiliyor muyum? Evet! Silebiliyoruz
çünkü a
ya yazma hakkımız var. rm b.txt
dediğimiz zaman remove write-protected regular file
diyor, dosyada yazma hakkımız olmadığı için emin
misin diyor fakat buna y
dersek çatır çutur siliyor.
a
dizindeki haklarımızı -w-
konumuna getirelim. Bu durumda cd
ile
giremeyiz. Ama uzaktan değişiklikler yapabilir miyiz?
$ ls -l
total 4
d-w-r-xr-x 3 ay ay 4096 Jul 6 19:40 a
ay@400:~/sys $ rm a/c.txt
rm: cannot remove 'a/c.txt': Permission denied
ay@400:~/sys $ touch a/f.txt
touch: cannot touch 'a/f.txt': Permission denied
Hmm, ilginç. a
da w
hakkım var. O yüzden inode-dosya adı
tablosunu
değiştirebiliyorum. Peki neden c.txt
yi silemedim? Çünkü a
da x
hakkım
yok. rm
ile dosya silerken olan birkaç işlem var. a
nın içerisinden c.txt
satırının silindiği doğru fakat c
nin inode’u içerisinde de değişiklik
yapılması gerekiyor, örneğin hard link sayısı 1 eksiltilecek. Fakat a
da x
hakkım olmadığı için c
nin inode’una da erişemiyorum.
O yüzden bir dizinde x
hakkı olmadan w
hakkının olması pratikte anlamlı
olmamaktadır. [1]
Şimdi dosya üzerindeki execute hakkına bakalım. Aşağıdaki gibi bir BASH scripti yazalım:
echo "Merhaba Dunya!"
fakat bu dosyaya x
hakkı vermeyelim:
$ ls -l script.sh
-rw-r--r-- 1 ay ay 34 Jul 6 23:13 script.sh
Bu durumda bu dosyayı çalıştıramıyoruz:
$ ./script.sh
bash: ./script.sh: Permission denied
Fakat bash script.sh
dersek çalışıyor:
$ bash script.sh
Merhaba Dunya!
Bu nasıl oldu? Biz burada aslında bash
programını çalıştırdık fakat ona
argüman olarak script.sh
dosyasını verdik. Yani execute edilen şey aslında
bash
. BASH scriptleri özünde satır satır interpret edildikleri için dolaylı
yoldan çalıştırılmış oldu. Burada dosyanın read
hakkına sahip olması yeterli,
çünkü bash
programı dosyayı okuyabildi. Python scriptlerinde de benzer bir şey
yapabiliriz, python script.py
gibi. Yani interpreted, script tabanlı
dosyalarda ilgili script dilini interpret eden programı çağırabiliriz.
Biraz gıcıklaştıralım. C dilinde aynı yazıyı basan programı yazıp
derleyeyim, printf("Merhaba Dunya!\n")
yani. a.out
şeklinde bir dosya
çıkıyor. Diyelim ki bunda da x
hakkım yok. Scriptlerde olduğu gibi xxx a.out
diyerek bunu çalıştırabilir miyim? xxx
ne olmalı? Aslında evet. Burada da
dynamic loader ı kullanabiliriz. [2] Ama bu konu dışı bir konu:
$ /lib/ld-linux-aarch64.so.1 ~/sys/a.out
Merhaba Dunya!
ld
ile benzer bir işlem gerçekleştirebiliriz. Ben bu denemeleri ARM bir
platformda yaptığım için içinde aarch64
geçiyor.
Özet
Dosya/dizin izinlerine bakılırken sırası ile kullanıcı, grup ve others izinlerine bakılır. Eğer biz ilgili dosya veya dizinin kullanıcısı isek, kullanıcı izinleri bizim için geçerli olur, diğerlerinin ne olduğu önemli olmaz. Eğer değilsek ama grubumuz tutuyorsa bu sefer grup izinleri geçerli olur. Tutan yoksa others oluruz.
Sıradan düz dosyalarda w
hakkı dosyayı yazmamızı, r
hakkı okumamızı, x
hakkı ise çalıştırmamızı sağlar.
Dizinlerde ise işler biraz daha farklı. x
hakkı ile dizinin içinden
geçebiliyoruz. Buna bazen bu yüzden search permission da denebiliyor. w
hakkı ile dizinin içeriği ile oynayabiliyoruz fakat x
hakkı yoksa pek bir
anlamı olmuyor. r
hakkı ile de dizin içeriğini görebiliyoruz.