TL; DR
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
Sie müssen das System fragen, ob der Benutzer über Schreibrechte verfügt. Die einzig zuverlässige Möglichkeit besteht darin, die effektive Benutzer-ID, die effektive Benutzer-ID und die ergänzende Benutzer-ID auf die des Benutzers umzustellen und den access(W_OK)
Systemaufruf zu verwenden (auch wenn dies bei einigen Systemen / Konfigurationen Einschränkungen aufweist).
Beachten Sie außerdem, dass das Fehlen einer Schreibberechtigung für eine Datei nicht unbedingt garantiert, dass Sie den Inhalt der Datei unter diesem Pfad nicht ändern können.
Die längere Geschichte
Lassen Sie uns überlegen , was es zum Beispiel für einen $ Benutzer nimmt Schreibzugriff zu haben , um /foo/file.txt
(unter der Annahme keiner /foo
und /foo/file.txt
Symlinks sind)?
Er braucht:
- Suche nach Zugang zu
/
(keine Notwendigkeit für read
)
- Suche nach Zugang zu
/foo
(keine Notwendigkeit für read
)
- Schreibzugriff auf
/foo/file.txt
Sie können bereits sehen, dass Ansätze (wie @ lcd047 oder @ apaul ), die nur die Berechtigung von überprüfen file.txt
, nicht funktionieren, weil sie sagen könnten, dass sie file.txt
beschreibbar sind, selbst wenn der Benutzer keine Suchberechtigung für /
oder hat /foo
.
Und ein Ansatz wie:
sudo -u "$user" find / -writeble
Funktioniert auch nicht, da keine Dateien in Verzeichnissen gemeldet werden, auf die der Benutzer keinen Lesezugriff hat (da find
ausgeführt wird, weil der $user
Inhalt nicht aufgelistet werden kann), selbst wenn er darauf schreiben kann.
Vergessen wir ACLs, schreibgeschützte Dateisysteme, FS-Flags (wie unveränderlich), andere Sicherheitsmaßnahmen (Apparmor, SELinux, die sogar zwischen verschiedenen Schreibweisen unterscheiden können) und konzentrieren wir uns nur auf traditionelle Berechtigungs- und Eigentumsattribute, um eine zu erhalten mit der erlaubnis (suchen oder schreiben) ist das schon ziemlich kompliziert und schwer auszudrücken find
.
Du brauchst:
- Wenn sich die Datei in Ihrem Besitz befindet, benötigen Sie diese Berechtigung für den Eigentümer (oder haben die UID 0).
- Wenn sich die Datei nicht in Ihrem Besitz befindet, die Gruppe jedoch eine Ihrer ist, benötigen Sie diese Berechtigung für die Gruppe (oder haben die UID 0).
- Wenn es Ihnen nicht gehört und keiner Ihrer Gruppen angehört, gelten die anderen Berechtigungen (es sei denn, Ihre UID ist 0).
In der find
Syntax, hier als Beispiel mit einem Benutzer von UID 1 und GID 1 und 2, wäre das:
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
Dass man Pflaumen die Verzeichnisse der Benutzer suchen haben , nicht direkt für und für andere Arten von Dateien (Symlinks ausgeschlossen , da sie nicht relevant sind), Schecks für den Schreibzugriff.
Wenn Sie auch den Schreibzugriff auf Verzeichnisse in Betracht ziehen möchten:
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
Oder für eine beliebige $user
und deren Gruppenmitgliedschaft, die aus der Benutzerdatenbank abgerufen wird:
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
(das ist 3 - Prozesse insgesamt: id
, sed
und find
)
Am besten ist es, wenn Sie den Baum als root absteigen und die Berechtigungen als Benutzer für jede Datei prüfen.
find / ! -type l -exec sudo -u "$user" sh -c '
for file do
[ -w "$file" ] && printf "%s\n" "$file"
done' sh {} +
(Das ist ein find
Prozess plus eins sudo
und sh
verarbeitet alle paar tausend Dateien [
und printf
wird normalerweise in der Shell erstellt.)
Oder mit perl
:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
(3 Prozesse insgesamt: find
, sudo
und perl
).
Oder mit zsh
:
files=(/**/*(D^@))
USERNAME=$user
for f ($files) {
[ -w $f ] && print -r -- $f
}
(0 Prozess insgesamt, speichert aber die gesamte Dateiliste im Speicher)
Diese Lösungen basieren auf dem access(2)
Systemaufruf. Das heißt, anstatt den Algorithmus zu reproduzieren, den das System verwendet, um nach Zugriffsberechtigungen zu suchen, bitten wir das System, diese Überprüfung mit demselben Algorithmus durchzuführen (der Berechtigungen, ACLs, unveränderliche Flags, schreibgeschützte Dateisysteme berücksichtigt ...). ) Wenn Sie versuchen würden, die Datei zum Schreiben zu öffnen, ist dies die zuverlässigste Lösung.
Um die hier angegebenen Lösungen mit den verschiedenen Kombinationen von Benutzern, Gruppen und Berechtigungen zu testen, können Sie Folgendes tun:
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
}
}
}
}
}
}'
Variieren Sie den Benutzer zwischen 1 und 2 und die Gruppe zwischen 1, 2 und 3 und beschränken Sie sich auf die unteren 9 Bits der Berechtigungen, da bereits 9458694 Dateien erstellt wurden. Das für Verzeichnisse und dann nochmal für Dateien.
Das schafft alle möglichen Kombinationen von u<x>g<y>/<mode1>/u<z>g<w>/<mode2>
. Der Benutzer mit Benutzer-ID 1 und Benutzer-ID 1 und Benutzer-ID 2 hätte beispielsweise Schreibzugriff auf, u2g1/010/u2g3/777
jedoch nicht u1g2/677/u1g1/777
auf.
Alle diese Lösungen versuchen nun, die Pfade der Dateien zu identifizieren, die der Benutzer möglicherweise zum Schreiben öffnet. Dies unterscheidet sich von den Pfaden, unter denen der Benutzer möglicherweise den Inhalt ändern kann. Um diese allgemeinere Frage zu beantworten, gibt es mehrere Dinge zu berücksichtigen:
- $ user hat möglicherweise keinen Schreibzugriff auf,
/a/b/file
aber wenn er Eigentümer ist file
(und Suchzugriff auf /a/b
hat und das Dateisystem nicht schreibgeschützt ist und die Datei nicht das unveränderliche Flag hat und Shell-Zugriff auf das System hat), dann könnte er die Berechtigungen des ändern file
und sich selbst Zugriff gewähren.
- Dasselbe, wenn er es besitzt,
/a/b
aber keinen Suchzugriff darauf hat.
- $ user hat möglicherweise keinen Zugriff auf,
/a/b/file
weil er keinen Suchzugriff auf /a
oder /a/b
hat. Diese Datei verfügt jedoch möglicherweise über einen festen Link /b/c/file
. In diesem Fall kann er den Inhalt möglicherweise ändern, /a/b/file
indem er ihn über seinen /b/c/file
Pfad öffnet .
- Gleiches gilt für Bindemounts . Er kann nicht suchen den Zugang haben
/a
, sondern /a/b
kann sein bind montierte in /c
, so dass er öffnen konnte file
für das Schreiben über seinen /c/file
anderen Weg.
- Er hat möglicherweise keine Schreibrechte für
/a/b/file
, aber wenn er Schreibrechte hat, /a/b
kann er diese entfernen oder umbenennen file
und durch seine eigene Version ersetzen. Er würde den Inhalt der Datei ändern, /a/b/file
selbst wenn dies eine andere Datei wäre.
- Das Gleiche gilt , wenn er Schreibzugriff auf bekam ist
/a
(er umbenennen könnte /a/b
zu /a/c
erstellen Sie ein neues /a/b
Verzeichnis und ein neues file
drin.
Um die Pfade zu finden, die geändert $user
werden könnten. Für Adresse 1 oder 2 können wir uns nicht mehr auf den access(2)
Systemaufruf verlassen . Wir könnten unseren find -perm
Ansatz anpassen , um den Suchzugriff auf Verzeichnisse oder den Schreibzugriff auf Dateien zu übernehmen, sobald Sie der Eigentümer sind:
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
Wir könnten die Adressen 3 und 4 ansprechen, indem wir die Geräte- und Inode-Nummern oder alle Dateien aufzeichnen, für die der Benutzer Schreibrechte besitzt, und alle Dateipfade mit diesen dev + -Inode-Nummern melden. Dieses Mal können wir die zuverlässigeren access(2)
Ansätze verwenden:
So etwas wie:
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 und 6 werden auf den ersten Blick durch das t
bisschen der Berechtigungen kompliziert . Bei der Anwendung auf Verzeichnisse ist dies das eingeschränkte Löschbit, das verhindert, dass Benutzer (außer dem Eigentümer des Verzeichnisses) die Dateien entfernen oder umbenennen, deren Eigentümer sie nicht sind (obwohl sie Schreibzugriff auf das Verzeichnis haben).
Zum Beispiel, wenn wir zurück zu unserem früheren Beispiel gehen, wenn Sie Schreibzugriff haben /a
, dann sollten Sie in der Lage sein , umbenennen /a/b
zu /a/c
, und dann ein neu - /a/b
Verzeichnis und ein neu file
drin. Aber wenn das t
Bit gesetzt ist /a
und Sie es nicht besitzen /a
, können Sie es nur tun, wenn Sie es besitzen /a/b
. Das gibt:
- Wenn Sie ein Verzeichnis gemäß Nummer 1 besitzen, können Sie sich selbst Schreibzugriff gewähren, und das t-Bit wird nicht angewendet (und Sie können es trotzdem entfernen), sodass Sie alle Dateien oder Verzeichnisse dort löschen / umbenennen / neu erstellen können Alle Dateipfade, die sich dort befinden, können mit allen Inhalten überschrieben werden.
- Wenn Sie es nicht besitzen, aber Schreibzugriff haben, dann:
- Entweder ist das
t
Bit nicht gesetzt, und Sie sind im selben Fall wie oben (alle Dateipfade gehören Ihnen).
- oder es ist festgelegt und dann können Sie die Dateien nicht ändern, die Sie nicht besitzen oder auf die Sie keinen Schreibzugriff haben. Um die Dateipfade zu ermitteln, die Sie ändern können, müssen Sie also überhaupt keine Schreibberechtigung besitzen.
So können wir alle von 1, 2, 5 und 6 ansprechen mit:
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
Das und die Lösung für 3 und 4 sind unabhängig, Sie können ihre Ausgabe zusammenführen, um eine vollständige Liste zu erhalten:
{
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{$_}++'
Wie klar sein sollte, wenn Sie bisher alles gelesen haben, befasst sich ein Teil davon zumindest nur mit Berechtigungen und Eigentumsrechten, nicht aber mit den anderen Funktionen, die möglicherweise Schreibzugriff gewähren oder einschränken (schreibgeschütztes FS, ACLs, unveränderliches Flag, andere Sicherheitsfunktionen) ...). Und da wir es in mehreren Schritten verarbeiten, können einige dieser Informationen falsch sein, wenn die Dateien / Verzeichnisse erstellt / gelöscht / umbenannt werden oder ihre Berechtigungen / Eigentümer geändert werden, während das Skript ausgeführt wird, wie auf einem ausgelasteten Dateiserver mit Millionen von Dateien .
Hinweise zur Portabilität
Der gesamte Code ist Standard (POSIX, Unix für t
Bit), außer:
-print0
ist eine GNU-Erweiterung, die jetzt auch von einigen anderen Implementierungen unterstützt wird. Mit find
Implementierungen , die Unterstützung für sie fehlt, können Sie -exec printf '%s\0' {} +
stattdessen und ersetzen -exec sh -c 'exec find "$@" -print0' sh {} +
mit -exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +
.
perl
ist kein POSIX-spezifizierter Befehl, ist aber weit verbreitet. Sie benötigen perl-5.6.0
oder über -Mfiletest=access
.
zsh
ist kein POSIX-angegebener Befehl. Der zsh
obige Code sollte mit zsh-3 (1995) und höher funktionieren.
sudo
ist kein POSIX-angegebener Befehl. Der Code sollte mit jeder Version funktionieren, sofern die Systemkonfiguration die Ausführung perl
als angegebener Benutzer zulässt .