Как установить SGID в PHP?
Мне не удается установить бит 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(), но я не использую ни один из них.
Что я делаю неправильно?
Ответы
Это работает на веб-сервере или просто как сценарий CLI? Если CLI, пользователь или root?
Кроме того, почему каталоги? SGID используется в программных файлах, чтобы позволить пользователю запускать программу / сценарий от имени другого пользователя, например, «sudo». Вы пробовали тестировать это на файлах, а не на каталогах?
В конце концов, единственный способ, которым я мог найти необходимые мне разрешения, - это извлечь выгоду из правильного поведения 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 , что, очевидно, ведет к нежелательному и непредсказуемому поведению. К счастью, в моем случае я мог убедиться, что все создание каталогов выполняется в однопоточном контексте (по сути, при первом тестовом запуске скрипта), и поэтому я чувствую себя в безопасности. Следовательно, это полезный обходной путь, но не общее решение.