Найти файлы, которые пользователь не может прочитать?

12

Я хочу найти файлы, которые конкретный пользователь не сможет прочитать.

Предположим, что имя пользователя «user123», и они находятся в группе под названием «user123». Я хочу найти файлы, которые, если они принадлежат user123, имеют u + r; в противном случае, если файл является группой user123, он должен иметь g + r; в противном случае он может иметь o + r.

Так как GNU find имеет "-читаемый", я мог бы сделать это:

sudo -u user123 find /start ! -readable -ls

Однако процесс должен запускаться пользователем, который не имеет доступа sudo. Поэтому я попробовал это: (он не проверяет o + r, но это не важно в данный момент)

find /start \( -user user123 ! -perm -u=r  \) -o \( -group user123 ! -perm -g=r  \) -ls

но он перечисляет этот файл:

272118    4 -rw-------   1 user123   user123       3243 Jul  3 19:50 /start/blah/blah/file.txt

Этот файл является единственным файлом, к /startкоторому принадлежит user123 с g=roff. Это как если бы найти интерпретирует -u=rкак -g=r.

Я решил попробовать поменять логику и вместо этого проверить not ( truth ):

find /etc/puppet ! \( \( -user puppet -perm -u=r  \) -o \( -group puppet -perm -g=r \) -o \( -perm -o=r \) \)  -ls

Это работает!

Почему оригинал findпотерпел неудачу? Это ошибка find(маловероятно) или логика неверна?

Обновление: у меня была неправильная логика. Как указано ниже, так как! (A || B || C) == (! A &&! B &&! C) это два эквивалентных утверждения:

find /start ! \( \( -user user123 -perm -u=r \) -o \( -group user123 -perm -g=r \) -o \( ! \( -user user123 -o -group user123 \) -perm -o=r \) \) -ls
find /start ! \( -user user123 -perm -u=r \) ! \( -group user123 -perm -g=r \) ! \( ! \( -user user123 -o -group user123 \) -perm -o=r \) -ls

Моей целью было не проверять пользователя / группу дважды. Что мне действительно нужно, так это более сложная структура if-then-else, которая, вероятно, была бы возможна только при наличии оператора -xor. Я мог бы построить xor из и / или / нет, но он был бы более сложным, чем два решения выше.

TomOnTime
источник
1
Даже вторая логика неверна, потому что она говорит, что puppetимеет доступ к файлу с --wxrwxrwx puppet puppet.
Стефан Шазелас

Ответы:

7

Логика неверна. Вы думаете, что этот файл не должен был быть указан в списке, потому что он принадлежит user123и имеет установленный rбит пользователя . Тем не менее, он указан, потому что он соответствует второму критерию (принадлежит группе user123и rбит группы не установлен).

Ваша вторая версия работает из-за одного из законов де Моргана : отрицание логического ИЛИ группы утверждений логически эквивалентно И отрицанию отдельных утверждений. Другими словами:

 ! ( A || B || C ) == ( !A && !B && !C )

Таким образом, рабочая findищет файл, который

  • Не принадлежит (принадлежит пользователю user123и читается указанным пользователем) И
  • Не принадлежит (принадлежит группе user123и читается указанной группой) И
  • Не для чтения во всем мире.

в то время как первый findищет файл, который

  • Принадлежит пользователю user123и не читается указанным пользователем ИЛИ
  • Принадлежит группе user123и не может быть прочитана указанной группой ИЛИ (если вы ее завершили)
  • Не читаемая во всем мире

Таким образом, файл, соответствующий ЛЮБОМУ из 3 приведенных выше критериев (и не обязательно всех), будет указан, как вы видели.

редактировать

Кстати (после просмотра вашего профиля) я большой поклонник вашей книги О'Рейли :)

Джозеф Р.
источник
Спасибо за анализ. Да, это было неправильное применение закона Моргана. Я пытался сделать, ( !A && !B && !C )но я переместил !внутрь каждой части, которая не действительна. Благодарность!
TomOnTime
PS Я рад, что вы фанат моей книги! Мне интересно, на каком языке вы его читаете.
TomOnTime
@TomOnTime Английский, конечно. Я стараюсь читать любую книгу на языке оригинала, если смогу помочь.
Джозеф Р.
8

Есть еще много вещей, которые необходимо учитывать, чтобы проверить, есть ли у пользователя доступ к файлу по заданному пути:

  • Владелец файла
  • группа файла
  • ACL в файле
  • UID, GID и дополнительные GID пользователя
  • поиск доступа к любому компоненту пути, ведущему к этому файлу.
  • является ли файл символической ссылкой
  • разрешения применяются по-разному для пользователей с идентификатором 0.
  • возможно, больше функций безопасности, таких как SELinux ...

За исключением фактического переключения всех uids и gids на пользовательские и проверки, очень трудно реализовать ту же логику, что и система.

С zsh вы можете сделать (как root):

readable() (
  USERNAME=$u
  [ -r "$REPLY" ]
)
u=some-user
print -rl -- **/*(DoN^+readable)

Или с perl:

find . -print0 | sudo -u some-user perl -Mfiletest=access -l -0ne '
  print unless -r'

То есть в обоих случаях спускайтесь по дереву каталогов, rootно проверяйте доступ к файлу как соответствующий пользователь.

Запуск , find -readableкак some-userне в тех случаях , когда он не сможет пройти мимо каталогов , для которых пользователь не имеет доступа или нет разрешения на чтение (но , возможно , доступ).

Даже если вы рассматриваете только разрешение и владение самим файлом (а не списками ACL или компонентами пути ...), вам нужно как минимум (здесь синтаксис GNU):

u=some-user; g=$(id -G "$u" | sed 's/ / -o -group /g'); IFS=" "
find . ! \( -user "$u" -perm -u=r -o \
          ! -user "$u" \( -group $g \) -perm -g=r -o \
          ! -user "$u" ! \( -group $g \) -perm -o=r \)

Идея заключается в том, что если файл принадлежит пользователю, все остальные разрешения не имеют значения. Если нет, то, если файл принадлежит группе какой-либо из групп пользователей, то разрешение «прочее» не имеет значения.

Стефан Шазелас
источник
1
Хороший вопрос о ACL и других факторах. Единственная правильная оценка на 100% состоит в том, что access()она использует тот же код ядра, что и open(). Таким образом, sudo -u user123 find /start -readableэто лучшее решение, если sudoесть вариант.
TomOnTime
1
@TomOnTime. Ну, нет, если вы используете sudo -u user123 find -readable, он не будет сообщать о файлах в каталогах, которые вы не можете ввести, или в каталогах, которые вы не можете прочитать (поэтому будут ложные негативы и ложные срабатывания). Вот почему я предлагаю использовать zshдля спуска по дереву каталогов как корень и сделать access()( [ -r ... ]) в качестве фактического пользователя (установка $USERNAMEв zshизменениях всех UIDS и GID , как sudoбы).
Стефан Шазелас