Как установить SGID в PHP?

Oct 07 2020

Мне не удается установить бит SGID из PHP.

У меня есть этот каталог:

  4 drwxrwsr-x 12 www-data mygroup  4096 Oct  7 16:05 mydir

Обратите внимание на бит SGID. Итак, если я просто создаю в нем каталог из оболочки с помощью mkdir test, я получаю

  4 drwxr-sr-x  2 myuser   mygroup   4096 Oct  7 16:22 test

Обратите внимание, что бит SGID наследуется. Но я бы хотел, чтобы он был доступен для групповой записи (что umask 22не разрешено мной), поэтому я могу просто chmod 02775 testи совершенно счастлив:

  4 drwxrwsr-x  2 myuser   mygroup   4096 Oct  7 16:22 test

Теперь я хотел бы сделать то же самое из сценария PHP. Естественно, я ожидал, что это сработает:

mkdir("/mydir/test2");
chmod("/mydir/test2", 02775);

Но это не так, и вместо этого я получаю это (SGID сброшен):

  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 16:30 test2

Вот еще пара полезных экспериментов:

mkdir("/mydir/test3");
mkdir("/mydir/test4");
passthru("chmod 02775 '/mydir/test4'");
mkdir("/mydir/test5");
passthru("chmod g+w '/mydir/test5'");

Результаты

  4 drwxr-sr-x  2 www-data mygroup   4096 Oct  7 16:39 test3
  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 16:39 test4
  4 drwxrwxr-x  2 www-data mygroup   4096 Oct  7 17:06 test5

Интересно, что mkdir()только SGID сохранил, но chmod()сбрасывает даже через passthru().

Я знаю, что в руководстве по PHP сказано, chmodчто команда ожидает только трех восьмеричных цифр, но я также прочитал этот вопрос о переполнении стека, и похоже, что руководство содержит устаревшую информацию, а другие могут повлиять на SGID. К тому же это не должно повлиять на passthru()версии? В том же вопросе stackoverflow упоминается что-то о chmod()необходимости быть «последним для вызова» после chown()и chgrp(), но я не использую ни один из них.

Что я делаю неправильно?

Ответы

DanielB Oct 08 2020 at 21:11

Это работает на веб-сервере или просто как сценарий CLI? Если CLI, пользователь или root?

Кроме того, почему каталоги? SGID используется в программных файлах, чтобы позволить пользователю запускать программу / сценарий от имени другого пользователя, например, «sudo». Вы пробовали тестировать это на файлах, а не на каталогах?

Paolo Oct 09 2020 at 12:37

В конце концов, единственный способ, которым я мог найти необходимые мне разрешения, - это извлечь выгоду из правильного поведения mkdir()и избежать вызова, chmod()который, кажется, сбрасывает бит SGID, несмотря ни на что. Единственный способ, которым я могу это сделать, - это изменить маску с помощью umask():

$myumask = umask(2); mkdir("/mydir/test6"); umask($myumask);

Кажется, это работает нормально:

  4 drwxrwsr-x  2 www-data mygroup   4096 Oct  9 14:22 test6

Это оставляет мне вопрос, поднятый в примечании https://www.php.net/manual/en/function.umask.php: все потоки многопоточного веб-сервера используют одну и ту же маску umask , что, очевидно, ведет к нежелательному и непредсказуемому поведению. К счастью, в моем случае я мог убедиться, что все создание каталогов выполняется в однопоточном контексте (по сути, при первом тестовом запуске скрипта), и поэтому я чувствую себя в безопасности. Следовательно, это полезный обходной путь, но не общее решение.