टी एल; डॉ
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
आपको सिस्टम से पूछना होगा कि क्या उपयोगकर्ता ने अनुमति लिखी है। एकमात्र विश्वसनीय तरीका यह है कि उपयोगकर्ता के प्रभावी यूआईडी, प्रभावी gid और अनुपूरण ग्रिड को स्विच किया जाए और access(W_OK)सिस्टम कॉल (यहां तक कि कुछ सिस्टम / कॉन्फ़िगरेशन पर कुछ सीमाएं) का उपयोग करें।
और ध्यान रखें कि किसी फाइल को लिखने की अनुमति नहीं होना जरूरी नहीं है कि आप उस पथ पर फ़ाइल की सामग्री को संशोधित नहीं कर सकते हैं।
लम्बी कहानी
आइए विचार करें कि एक $ उपयोगकर्ता के लिए लिखने के लिए क्या उपयोग होता है /foo/file.txt(कोई भी नहीं /fooऔर /foo/file.txtसहानुभूति नहीं है) तक पहुंच है ?
उसे जरुरत है:
- के लिए खोज का उपयोग
/(कोई ज़रूरत नहीं read)
- के लिए खोज का उपयोग
/foo(कोई ज़रूरत नहीं read)
- तक पहुँच लिखो
/foo/file.txt
आप पहले से ही देख सकते हैं कि दृष्टिकोण (जैसे @ lcd047 के या @ apaul के ) इस बात का केवल अनुमति जाँच file.txtकाम नहीं करेगा क्योंकि वे कह सकते हैं file.txtलिखने योग्य है, भले ही उपयोगकर्ता के लिए खोज की अनुमति नहीं है /या /foo।
और एक दृष्टिकोण जैसे:
sudo -u "$user" find / -writeble
या तो काम नहीं करेगा क्योंकि यह उन निर्देशिकाओं में फ़ाइलों की रिपोर्ट नहीं करेगा, जिन्हें उपयोगकर्ता ने पढ़ा नहीं है (जैसा findकि $userउनकी सामग्री को सूचीबद्ध नहीं किया जा सकता है) भले ही वह उन्हें लिख सकता है।
यदि हम ACLs, केवल-पढ़ने के लिए फ़ाइल सिस्टम, FS झंडे (जैसे अपरिवर्तनीय), अन्य सुरक्षा उपायों (apparmor, SELinux, जो विभिन्न प्रकार के लेखन में भी अंतर कर सकते हैं) के बारे में भूल जाते हैं और केवल पारंपरिक अनुमति और स्वामित्व विशेषताओं पर ध्यान केंद्रित करते हैं, तो दी गई (खोज या लिख) अनुमति, यह पहले से ही काफी जटिल है और इसके साथ व्यक्त करना कठिन है find।
आप की जरूरत है:
- यदि फ़ाइल आपके पास है, तो आपको स्वामी की अनुमति चाहिए (या uid 0 है)
- यदि फ़ाइल आपके स्वामित्व में नहीं है, लेकिन समूह आपका एक है, तो आपको समूह के लिए उस अनुमति की आवश्यकता है (या आपके पास 0 है)।
- यदि यह आपके स्वामित्व में नहीं है, और आपके किसी समूह में नहीं है, तो अन्य अनुमतियाँ लागू होती हैं (जब तक कि आपका यूआईडी 0 नहीं है)।
में findवाक्य रचना, यहाँ uid 1 और GIDs 1 और 2 के एक उपयोगकर्ता के साथ एक उदाहरण के रूप में, कि हो सकता है:
find / -type d \
\( \
-user 1 \( -perm -u=x -o -prune \) -o \
\( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) -o -type l -o \
-user 1 \( ! -perm -u=w -o -print \) -o \
\( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
यह एक निर्देशिका है कि उपयोगकर्ता के लिए और फ़ाइलों के अन्य प्रकार के लिए खोज सही नहीं है prunes (symlinks के रूप में वे प्रासंगिक नहीं हैं), लिखने का उपयोग के लिए जाँच करता है।
यदि आप निर्देशिकाओं के लिए लेखन पहुँच पर विचार करना चाहते हैं:
find / -type d \
\( \
-user 1 \( -perm -u=x -o -prune \) -o \
\( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user 1 \( ! -perm -u=w -o -print \) -o \
\( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
या $userउपयोगकर्ता डेटाबेस से प्राप्त एक मनमाना और उसके समूह की सदस्यता के लिए:
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" \( -perm -u=x -o -prune \) -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( ! -perm -u=w -o -print \) -o \
\( -group $groups \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
(है कि कुल में 3 प्रक्रियाओं है: id, sedऔर find)
यहां सबसे अच्छा होगा कि पेड़ को जड़ के रूप में उतारा जाए और प्रत्येक फाइल के लिए उपयोगकर्ता के रूप में अनुमतियों की जांच की जाए।
find / ! -type l -exec sudo -u "$user" sh -c '
for file do
[ -w "$file" ] && printf "%s\n" "$file"
done' sh {} +
(यह एक findप्रक्रिया प्लस एक है sudoऔर shहर कुछ हजार फाइलों को प्रोसेस करती है, [और printfआमतौर पर शेल में निर्मित होती है)।
या साथ perl:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
(कुल 3 की प्रक्रिया: find, sudoऔर perl)।
या साथ zsh:
files=(/**/*(D^@))
USERNAME=$user
for f ($files) {
[ -w $f ] && print -r -- $f
}
(कुल में प्रक्रिया, लेकिन मेमोरी में पूरी फ़ाइल सूची संग्रहीत करता है)
वे समाधान access(2)सिस्टम कॉल पर निर्भर करते हैं। एक्सेस सिस्टम को एक्सेस की अनुमति के लिए जांचने के लिए सिस्टम एल्गोरिदम को पुन: प्रस्तुत करने के बजाय, हम सिस्टम को उसी एल्गोरिदम (जो खाता अनुमति, एसीएल, अपरिवर्तनीय झंडे, रीड-ओनली फाइल सिस्टम ...) के साथ जांच करने के लिए कह रहा है। ) इसका उपयोग आप लेखन के लिए फ़ाइल खोलने का प्रयास करेंगे, इसलिए आप एक विश्वसनीय समाधान प्राप्त करने के लिए निकटतम हैं।
यहां दिए गए समाधानों का परीक्षण करने के लिए, उपयोगकर्ता, समूह और अनुमतियों के विभिन्न संयोजनों के साथ, आप कर सकते हैं:
perl -e '
for $u (1,2) {
for $g (1,2,3) {
$d1="u${u}g$g"; mkdir$d1;
for $m (0..511) {
$d2=$d1.sprintf"/%03o",$m; mkdir $d2; chown $u, $g, $d2; chmod $m,$d2;
for $uu (1,2) {
for $gg (1,2,3) {
$d3="$d2/u${uu}g$gg"; mkdir $d3;
for $mm (0..511) {
$f=$d3.sprintf"/%03o",$mm;
open F, ">","$f"; close F;
chown $uu, $gg, $f; chmod $mm, $f
}
}
}
}
}
}'
उपयोगकर्ता 1 और 2 और समूह betweem 1, 2, और 3 के बीच भिन्नता है और अनुमतियों के निचले 9 बिट्स तक खुद को सीमित कर रहा है क्योंकि यह पहले से ही 9458694 फाइलें बनाई गई है। निर्देशिका के लिए और फिर फ़ाइलों के लिए फिर से।
कि सभी संभव संयोजन बनाता है u<x>g<y>/<mode1>/u<z>g<w>/<mode2>। यूआईडी 1 और 2 और 2 यूआईडी वाले उपयोगकर्ता के पास पहुंच के लिए लेखन होगा, u2g1/010/u2g3/777लेकिन u1g2/677/u1g1/777उदाहरण के लिए नहीं ।
अब, वे सभी समाधान उन फ़ाइलों के रास्तों की पहचान करने का प्रयास करते हैं जो उपयोगकर्ता लिखने के लिए खोल सकता है, यह उन रास्तों से अलग है जहाँ उपयोगकर्ता सामग्री को संशोधित करने में सक्षम हो सकता है। उस अधिक सामान्य प्रश्न का उत्तर देने के लिए, कई बातों का ध्यान रखना चाहिए:
- $ उपयोगकर्ता के पास लिखने की पहुंच नहीं हो सकती है,
/a/b/fileलेकिन यदि वह मालिक है file(और उसके पास खोज एक्सेस है /a/b, और फ़ाइल सिस्टम केवल-पढ़ने के लिए नहीं है, और फ़ाइल में अपरिवर्तनीय ध्वज नहीं है, और उसे सिस्टम में शेल एक्सेस मिल गई है) तब वह fileस्वयं की पहुंच को बदलने और अनुदान की अनुमति देने में सक्षम होगा ।
- एक ही बात अगर वह मालिक है,
/a/bलेकिन इसके लिए खोज का उपयोग नहीं है।
- $ उपयोगकर्ता के पास पहुंच नहीं हो सकती है
/a/b/fileक्योंकि उसके पास खोज एक्सेस नहीं है /aया नहीं /a/b, लेकिन उस फ़ाइल में /b/c/fileउदाहरण के लिए एक कठिन लिंक हो सकता है , जिस स्थिति में वह /a/b/fileअपने /b/c/fileपथ के माध्यम से इसे खोलकर सामग्री को संशोधित करने में सक्षम हो सकता है।
- बाइंड-माउंट्स के साथ एक ही बात । उसके पास खोज तक पहुँच नहीं हो सकती है
/a, लेकिन /a/bइसमें बाइंड-माउंटेड हो सकता है /c, इसलिए वह fileइसके /c/fileदूसरे रास्ते से लिखने के लिए खोल सकता है।
- उसके पास लिखने की अनुमति नहीं हो सकती है
/a/b/file, लेकिन अगर उसके पास लिखने की पहुंच है, तो वह वहां से /a/bहटा सकता है या नाम बदल fileसकता है और इसे अपने स्वयं के संस्करण के साथ बदल सकता है। वह फ़ाइल की सामग्री को बदल देगा /a/b/fileभले ही वह एक अलग फ़ाइल होगी।
- एक ही बात अगर उसे लिखने की सुविधा मिल गई है
/a(वह नाम बदल सकता /a/bहै /a/c, एक नई /a/bनिर्देशिका बना सकता है और fileउसमें एक नया भी बना सकता है।
उन मार्गों को खोजने के लिए जो $userसंशोधित करने में सक्षम होंगे। 1 या 2 को संबोधित करने के लिए, हम access(2)अब सिस्टम कॉल पर भरोसा नहीं कर सकते । find -permजैसे ही आप मालिक होते हैं, हम निर्देशिकाओं तक खोज पहुंच को संभालने या फ़ाइलों तक पहुंच लिखने के लिए अपने दृष्टिकोण को समायोजित कर सकते हैं:
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" -print -o \
\( -group $groups \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
हम डिवाइस और इनोड नंबरों को रिकॉर्ड करके 3 और 4 को संबोधित कर सकते हैं या सभी फाइल $ उपयोगकर्ता ने उन सभी फ़ाइल रास्तों की अनुमति देने और रिपोर्ट करने की अनुमति दी है जिनके पास देव + इनोड नंबर हैं। इस बार, हम अधिक विश्वसनीय- access(2)आधारित दृष्टिकोण का उपयोग कर सकते हैं :
कुछ इस तरह:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
perl -l -0ne '
($w,$p) = /(.)(.*)/;
($dev,$ino) = stat$p or next;
$writable{"$dev,$ino"} = 1 if $w;
push @{$p{"$dev,$ino"}}, $p;
END {
for $i (keys %writable) {
for $p (@{$p{$i}}) {
print $p;
}
}
}'
5 और 6 पहली नज़र tमें अनुमति के बिट द्वारा जटिल हैं । जब निर्देशिकाओं पर लागू किया जाता है, तो यह प्रतिबंधित विलोपन बिट होता है, जो उपयोगकर्ताओं (निर्देशिका के मालिक की तुलना में अन्य) को उन फ़ाइलों को हटाने या उनका नाम बदलने से रोकता है, जो उनके पास नहीं हैं (भले ही उनके पास निर्देशिका तक पहुंच हो)।
उदाहरण के लिए, अगर हम वापस हमारे पिछले उदाहरण पर जाते हैं, आप के लिए लेखन पहुँच है /a, तो आप का नाम बदलने के लिए सक्षम होना चाहिए /a/bकरने के लिए /a/c, और फिर एक को पुन: /a/bऔर निर्देशिका एक नया fileवहाँ में। लेकिन अगर tबिट सेट है /aऔर आप स्वयं नहीं हैं /a, तो आप इसे केवल तभी कर सकते हैं जब आप स्वयं के हों /a/b। देता है कि:
- यदि आपके पास एक निर्देशिका है, तो 1 के अनुसार, आप अपने आप को लिखने का उपयोग करने के लिए अनुदान दे सकते हैं, और टी बिट लागू नहीं होता है (और आप इसे किसी भी तरह से हटा सकते हैं), इसलिए आप किसी भी फ़ाइल को हटा सकते हैं / नाम बदल सकते हैं या वहां डायर कर सकते हैं, इसलिए किसी भी सामग्री के साथ फिर से लिखने के लिए सभी फ़ाइल पथ आपके हैं।
- यदि आपके पास यह नहीं है, लेकिन आपके पास लिखित पहुंच है, तो:
- या तो
tबिट सेट नहीं है, और आप ऊपर के समान मामले में हैं (सभी फ़ाइल पथ आपके हैं)।
- या यह सेट है और फिर आप उन फ़ाइलों को संशोधित नहीं कर सकते हैं जिनके पास आप नहीं हैं या जिनके पास लिखने की पहुंच नहीं है, इसलिए आपके द्वारा संशोधित किए जा सकने वाले फ़ाइल पथों को खोजने के हमारे उद्देश्य के लिए, यह बिल्कुल भी अनुमति नहीं है।
इसलिए हम 1, 2, 5 और 6 सभी को संबोधित कर सकते हैं:
find / -type d \
\( \
-user "$user" -prune -exec find {} + -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( -type d -o -print \) -o \
\( -group $groups \) \( ! -perm -g=w -o \
-type d ! -perm -1000 -exec find {} + -o -print \) -o \
! -perm -o=w -o \
-type d ! -perm -1000 -exec find {} + -o \
-print
वह और 3 और 4 के लिए समाधान स्वतंत्र हैं, आप पूरी सूची प्राप्त करने के लिए उनके आउटपुट को मर्ज कर सकते हैं:
{
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
perl -0lne '
($w,$p) = /(.)(.*)/;
($dev,$ino) = stat$p or next;
$writable{"$dev,$ino"} = 1 if $w;
push @{$p{"$dev,$ino"}}, $p;
END {
for $i (keys %writable) {
for $p (@{$p{$i}}) {
print $p;
}
}
}'
find / -type d \
\( \
-user "$user" -prune -exec sh -c 'exec find "$@" -print0' sh {} + -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( -type d -o -print0 \) -o \
\( -group $groups \) \( ! -perm -g=w -o \
-type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o -print0 \) -o \
! -perm -o=w -o \
-type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o \
-print0
} | perl -l -0ne 'print unless $seen{$_}++'
जैसा कि आपने अभी तक सब कुछ पढ़ा है, यह स्पष्ट होना चाहिए, इसका हिस्सा कम से कम केवल अनुमतियों और स्वामित्व से संबंधित है, न कि अन्य सुविधाएँ जो लिखने की पहुँच प्रदान कर सकती हैं या प्रतिबंधित कर सकती हैं (केवल पढ़ने के लिए FS, ACLs, अपरिवर्तनीय ध्वज, अन्य सुरक्षा सुविधाएँ ...)। और जैसा कि हम इसे कई चरणों में संसाधित करते हैं, उस जानकारी में से कुछ गलत हो सकती हैं यदि फ़ाइलें / निर्देशिकाएं बनाई जा रही हैं / हटा दी गई हैं / नाम बदला गया है या उनकी अनुमतियाँ / स्वामित्व संशोधित है, जबकि स्क्रिप्ट चल रही है, जैसे लाखों फ़ाइलों के साथ एक व्यस्त फ़ाइल सर्वर पर। ।
पोर्टेबिलिटी नोट
tसिवाय इसके कि सभी कोड मानक है (POSIX, Unix for bit):
-print0GNU एक्सटेंशन अब कुछ अन्य कार्यान्वयनों द्वारा भी समर्थित है। उन findकार्यान्वयनों के साथ जिनमें इसके लिए समर्थन की कमी है, आप -exec printf '%s\0' {} +इसके बजाय उपयोग कर सकते हैं , और इसके -exec sh -c 'exec find "$@" -print0' sh {} +साथ बदल सकते हैं -exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +।
perlPOSIX- निर्दिष्ट कमांड नहीं है, लेकिन व्यापक रूप से उपलब्ध है। आप के perl-5.6.0लिए या ऊपर की जरूरत है -Mfiletest=access।
zshPOSIX- निर्दिष्ट कमांड नहीं है। यही कारण है कि zshकोड ऊपर zsh -3 (1995) और इसके बाद के संस्करण के साथ काम करना चाहिए।
sudoPOSIX- निर्दिष्ट कमांड नहीं है। कोड किसी भी संस्करण के साथ काम करना चाहिए जब तक कि सिस्टम कॉन्फ़िगरेशन perlदिए गए उपयोगकर्ता के रूप में चलने की अनुमति देता है ।