как проверить существование переменной и сравнить ее со строкой в ​​busybox?

Простой ответ: Невозможно заставить ваших пользователей использовать ваш сценарий оболочки.

Причина этого довольно проста; сценарий оболочки - это интерпретируемая программа. Это означает, что bash (или какой-либо другой процесс оболочки) должен прочитать файл для выполнения команд, которые в нем вызываются.

Это, в свою очередь, означает, что пользователь, имеющий разрешение на запуск сценария оболочки, должен иметь разрешение делать все, что делается в сценарии оболочки. В подавляющем большинстве случаев * сценарий оболочки, даже с большим количеством внутренней логики и условных обозначений, при запуске делает то же самое, что и при вводе всего сценария в командную строку, строка за строкой.

Если вы просто пытаетесь помешать необразованным пользователям замедлить работу вашей системы, существует множество способов сделать это , например, то, что предлагает @mikeserv в комментарии к вашему вопросу. Я могу придумать как минимум пять дополнительных способов **, многие из которых можно было бы использовать в комбинации; Важно понимать, что они небезопасны . На самом деле они не запрещают пользователю использовать команду напрямую вместо сценария оболочки, а также не (и не могут) предотвратить создание пользователем собственной копии сценария оболочки ( который он должен иметь права на чтение, чтобы вообще иметь возможность запускать) и изменяет его по своему усмотрению.

Можно написать короткую программу на C для выполнения функции сценария-оболочки, который компилируется в двоичный исполняемый файл, а затем сделать эту программу на C SUID ***, так что это единственный способ пользователь может запустить команду, о которой вы говорите, но это выходит за рамки моей компетенции и моей компетенции.

Другие варианты включают в себя чрезвычайно странные обходные пути (хаки), такие как установка cronjob для изменения вашего файла sudoers, чтобы разрешить запуск команды только в определенное время дня ... но это становится действительно, очень странным и территорией плохих идей.


Я думаю, что стандартный способ сделать это (хотя до сих пор без принуждения технически подкованных пользователей использовать ваш сценарий оболочки) был бы:

(Я сделаю вид, что ограничивающая команда - ] date .)

  1. Убедитесь, что внутри вашего скрипта его вызов date использует абсолютный путь: / bin / date (Вы можете узнать, что это за работает с датой .) Также убедитесь, что ваш сценарий имеет правильный шебанг, чтобы его можно было запустить без необходимости набирать bash ./myscript, но можно просто запустить как . / myscript , и убедитесь, что он доступен для чтения и выполнения всем. ( chmod 555 myscript )
  2. Поместите сценарий оболочки в / usr / local / bin / и переименуйте его как date .
  3. Убедитесь, что у пользователей есть / usr / local / bin в начале их переменной $ PATH . (Просто войдите в систему как пользователь и запустите echo "$ PATH" .) У них уже должно быть это по умолчанию.Он не обязательно должен быть в самом начале, если он находится на их пути до / bin (или независимо от того, где находится исходная команда date ).

Если его нет на пути, вы можете добавить его, запустив: echo 'PATH = "/ usr / local / bin: $ PATH"' | sudo tee /etc/profile.d/my_path_prefix.sh

Теперь каждый раз, когда пользователь пытается запустить команду напрямую, он фактически запускает ваш сценарий оболочки, потому что каталог, в котором находится сценарий оболочки, появляется первым в его $ PATH .


Гораздо более хитрым решением было бы фактически замаскировать исходный двоичный файл, не помещая другую версию ранее в путь для пользователей, а помещая сценарий оболочки вместо самой команды, на прежнем месте. Используйте на свой страх и риск:

  1. Поместите саму команду где-нибудь за пределами обычных каталогов bin , чтобы ни у кого не было ее пути. Вы можете переместить его, например, в / var / local . (Возможно, есть место получше, но это уже взлом, так что это не имеет большого значения, не так ли?)
  2. Убедитесь, что вызов date в вашем сценарии-оболочке указывает на новое местоположение для даты - его абсолютный путь: / var / local / date в моем примере.
  3. Переместите сценарий оболочки в старое расположение date с исходным именем date .

Главное предостережение заключается в том, что каждый раз, когда кто-либо пытается запустить эту команду, включая системные сценарии инициализации, они вместо этого получат ваш сценарий оболочки.

Это просто взлом, и его нельзя квалифицировать как хорошее системное администрирование. Но это возможно, и вы также можете знать, что это можно сделать. Лучшее решение - это то, что я написал выше.


* Исключения из этого связаны с изменением среды и программ, которые ведут себя по-разному, когда они запускаются в интерактивном режиме по сравнению с тем, когда они запускаются из сценария. Однако эти исключения не имеют ничего общего с разрешениями , поэтому они не имеют отношения к этому обсуждению.

** Если вам интересно, спросите о них в комментариях, и я расскажу о них подробнее.

*** НЕ suid root. Если вы это сделаете, просто создайте пользователя, поместите его в группу, которая является единственной, у которой есть разрешение на запуск команды, о которой вы говорите ( chmod 010 или что-то в этом роде), а затем chown ваш недавно скомпилированный двоичный файл оболочки должен принадлежать этому пользователю и установить его бит suid с помощью chmod 4511 .

5
21.07.2016, 00:25
2 ответа

Вы можете использовать старый синтаксис [

if [ -n "$ENV" -a "$ENV" = 'production' ]

(обратите внимание, что я использовал -n , а не ]! -z , потому что он читается проще, но это то же самое).

Или мы можем упростить до еще более старого синтаксиса, заставив строку иметь значение:

if [ "x$ENV" = 'xproduction' ]

Наконец, тест -n может действительно не понадобиться, и вы можете просто выполнить

if [ "$ENV" = 'production' ]
7
27.01.2020, 20:32

[[...]] - конструкция оболочки Korn, также поддерживаемая bash и zsh , но в остальном не стандартный sh (и не поддерживается никакими другими оболочками).

busybox sh основан на ash , который реализует подмножество спецификации POSIX sh (в локали POSIX он по большей части совместим ) с очень небольшим количеством расширений, и, в частности, не с этим.

2019 редактировать . ограниченное подмножество ksh [[...]] теперь также поддерживается в busybox ash при построении с помощью ASH_TEST и ASH_BASH_COMPAT и гораздо большего подмножества в яс .

В любом случае при написании сценария sh вы должны придерживаться спецификации POSIX sh . Скрипты, использующие [[...]] , должны явно вызывать ksh , bash или zsh . bash также в основном является оболочкой, совместимой с POSIX sh, но с гораздо большим количеством расширений (включая это).

Проверка того, что x непусто, а затем равняется production , не имеет большого смысла. Если x == production , то, очевидно, он не пустой.

Выполняйте сравнение строк с помощью оболочки и утилит POSIX, у вас есть несколько вариантов, наиболее очевидные в данном случае:

  • утилита [, известная как test , обычно встраивается в оболочку:

     if ["$ var" = production]; затем 
    echo PROD 
    fi 
     
  • case конструкция:

     case $ var in 
    production) echo PROD ;; 
     "") echo EMPTY ;; 
     *) echo non-PROD ;; 
    esac 
     

Теперь вы можете проверить, что переменная установить (в отличие от непустого) перед разыменованием его, в случае, если была включена опция существительное set -u или set -o nounset или с #! / Bin / sh -u в качестве строки she-bang), иначе ["$ ENV" = production] приведет к завершению работы оболочки, если $ ENV не будет установлено. Для этого вы должны сделать:

if [ "${var+set}" = set ] && [ "$var" = production ]; then
  echo PROD
fi

(вам следует избегать оператора -a [ AND, поскольку он устарел и ненадежен).

Хотя лучший и более канонический способ сделать это:

if [ "${var-}" = production ]; then
  echo PROD
fi

nounset не запускается на $ {var + string} или $ {var-string} расширения. $ {var -} расширяется до содержимого $ var , если переменная установлена, или до пустой строки в противном случае.

Еще несколько примечаний:

$ ENV - это специальная переменная для sh . При запуске в интерактивном режиме он используется как путь к файлу для чтения инициализаций (эквивалент ~ / .bashrc для bash ). Вы не должны использовать его для других целей.

Вы обнаружите, что в некоторых старых публикациях по сценариям оболочки Unix рекомендуется использовать ["x $ var" = xproduction] или [production = "x $ var"] для выполнения сравнение строк. Это было сделано для устранения ошибок в некоторых старых версиях утилиты [ и test , которые сбивали с толку некоторыми значениями $ var , например ! , ( или -n . Это не нужно в современных системах, но кое-что нужно иметь в виду для очень старых систем. В любом случае, случай Конструкция не имеет такой проблемы.

Другие утилиты POSIX, которые могут выполнять сравнение строк, включают expr и awk .

 awk_equal() { awk 'BEGIN{exit(!(""ARGV[1] == ""ARGV[2]))}' "$1" "$2"; }
 expr_equal() { expr "x $1" = "x $2" > /dev/null; }

 if awk_equal "$var" production; then
   echo PROD
 fi
 if expr_equal "$var" production; then
   echo PROD
 fi

Обратите внимание на необходимость добавления "" к значениям с awk , чтобы убедиться, что мы получим сравнение строк (в противном случае 1 будет считаться равным 01 или ] 1e0 ) и x в expr по той же причине, но также для того, чтобы избежать проблем со значениями, являющимися операторами expr .

С обоими awk и expr (по крайней мере, POSIXly), на самом деле они не являются операторами равенства , а являются проверкой того, имеют ли два операнда одинаковый порядок сортировки, что необязательно то же самое. для я Например, в системе May expr_equal ② ③ возвращает истину, потому что ни ②, ни ③ не имеют определенного порядка сортировки.Некоторые реализации awk , такие как gawk , mawk и busybox awk , игнорируют это требование POSIX и вместо этого выполняют простое побайтовое сравнение.

В любом случае,Я не могу придумать какой-либо веской причины, по которой вы бы предпочли их [ или случаю здесь.

12
27.01.2020, 20:32

Теги

Похожие вопросы