Удобная работа в командной строке

Начнем с повторения

Объект системы - это все, что мы можем встретить в файловой системе - файл, объект, каталог, спецфайл, и так далее. Субъект системы - это процесс. 

Чтобы посмотреть список процессов мы используем команду ps, которая без параметров выведет те процессы, которые связаны с текущим терминалом.

$ ps -e - все процессы в более красивом виде 

ps раньше входила в мозг ядра. Как она работает: она особым образом проглядывает каталог /proc. Там есть прекрасный подкаталог /self,  отвечающий параметрам текущего процесса, в данном случае это процесс ls. 

$ ls /proc/self 

Из команды ps видно все, что мы хотели знать про процессы, а именно - какому пользователю он принадлежит, process id, кто официальный отец этого процесса, сколько времени он работает в системе, с какой командной строкой был запущен. Кстати, эту часть можно просто подменить. Идентификатор процесса, хозяин процесса, идентификатор родительского процесса, переменные окружения.. set выводит все переменные окружения

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

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

Мы сравниваем идентификаторы. Если они равны - применяются права хозяина, не равны - проверяем, член ли группы? Да - права группы, нет - права для остальных.

$ ls -l подтверждает это - для каждого файла выводит тип и выводит 3 триплета. 

Тут есть каталог dir/ - он принадлежит группе cdwriter. Когда мы записываем файл в этот каталог - автоматически группа меняется на ту которой принадлежит каталог

$ date > dir/newfile2 

Казалось бы, файл должен был получить права доступа python и группу python, но нет. Стратегия проверки прав: если идентификатор пользователя совпадает с таковым у файла - исполняется первый триплет, даже если первый триплет плохой (у него меньше прав) - все равно он используется. Если совпали уиды - значит все. Да, rwx триплет - три бита, часто это представляется как восьмеричное трехзначное число. Например:

rwxr-xr-x 7 5 5 - это типично для каталога, для файла типично 6 4 4. 

Использование - запуск файла как программы.

Что такое права на чтение, запись и использование каталога - стоит пояснить.

Каталог - это файловый объект особого вида, содержащий списки файлов и ссылки на них. Чтение каталога - доступ на чтение к списку файлов. Запись - изменение списка файлов.

Использование - возможность получить доступ к иному.

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

Есть доверенный субъект в системе - root - который хотел плевать на ограничения прав доступа, который может делать что угодно, разве что не может запускать незапускаемый файл. Второе его свойство: в системе есть специальный вызов, который позволяет процессу, если ему это разрешено, поменять идентификатор пользователя, если у него есть права.

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

На лекции приводился пример программы ping. Такая программа должна получать дополнительные привелегии при запуске. Это регулируется таким классическим способом: сделать так чтобы конкретный процесс в момент запуска получил другие права: его окружение модифицируется таким образом, что поменяется юзер айди.

ping: в поле для рута вместо бита х стоит буква s: rws, а еще у этого файла есть setuid bit. Если вы запускаете такой процесс - идентификатор пользователя такого процесса будет равен идентификатору пользователя этого файла. Довольно опасная штука. Есть два пути избежать ее, один из них - избегать сет уидных файлов. Это можно сделать, если вспомнить , что в системе есть сет гид - когда можно поменять идентификатор группы.

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

ls -l /usr/bin/sudo - эта программа работает таким же образом. 

Группа wheel - группа системных администраторов. 

Еще одна более простая программа 

ls -l /bin/su 

Имеет точно такие же права

su - root

Программа позволяет переключится на другого пользователя, "-" позволяет получить его окружение. Ничего удивительного, что с точки зрения обычного пользователя он недоступен. Рекомендуется редактировать файл, вызывая программу visudo - он редактирует временный файл, проверяет его на синтаксическую корректность, а только потом записывает, поскольку можно отпилить сук, на котором ты сам сидишь. Если синтаксис ненормальный, то он спросит - «Вы уверены? Вы хорошо прицелились в свою ногу?» Хорошо, значит, еще из повторения.

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

Это относится, например, к файлу passwd - в нем раньше хранились пароли, потом там стали хранить хеши от паролей, потом выяснили, что этот файл доступен всем для чтения. Потом содержимое паролей переложили в другой файл - /etc/shadow, но выяснилось, что и это не очень безопасно.

Какая программа захочет менять /etc/shadow? Если вы хотите поменять пароль себе, то зачем вам доступ к файлу, где лежат пароли всех? Поэтому ребята из Openwall Linux, которые создают очень безопасный дистрибутив linux, конкретно для паролей придумали схему, которая является схемой безопасности tcb - пароли не хранятся в одной куче, а хранятся в таком виде

$ ls -l /etc/tcb 

Обратите внимание на права такого каталога: для рута всем все равно, для члена группы shadow разрешено только использование этого каталога и для всех остальных этот каталог вообще запрещен. В этом каталоге есть подкаталоги, соответствующие всем пользователям заведенным в системе. 

$ ls -la /etc/tcb/python 

Обычный пользователь не может вообще получить доступ к этому файлу. Смотрите:

$ /etc/tcb/python - каталог доступен только пользователю python или групе auth. 

Содержимое этого файла shadow поменять не может никто, так как никто не принадлежит группе shadow. Также есть програма

$ ls -l /usr/bin/passwd 

Если кто-то взломает etc/passwd, который пишет в общий shadow - он может скачать этот файл и модифицировать чужой пароль. Если же он взломает tcb-шную программу - он может поменять пароль только себе. 

Когда целевой файл отгораживается от пользователя каталогом, в который он не может попасть, потому что группы разные - эта технология называется setguid traversal.

Последнее, что очень вскользь хочется повторить, хотя, конечно было бы интересно поговорить подольше. Модель субъект-субъект не очень гибкая. Есть 3 правила доступа и 1 триплет для групп, то есть нельзя сделать файл, который для разных групп будет доступен на разные права. Но все равно это искусственная ситуация - редко когда кому-то такое может пригодиться. Другой более важный недостаток в том, что мы не можем сделать точечные разрешения или запреты, например, всем можно, а Васе Пупкину нельзя. Эти точечные запреты можно смоделировать с помощью групп, но для этого нужно перелопачивать все группы, создавать группу, куда включить отдельных пользователей.. Короче говоря, любое изменение прав доступа для отдельного пользователя с точки зрения субъект-субъектной точки зрения обозначает создание нового пользователя. Поэтому более гибкой считается модель субъект-объектных прав доступа, когда у нас есть еще и уникальные идентификаторы объекта.

Если такую систему наложить на файловую систему - количество таблиц значительно больше, чем вообще файлов. Поэтому никто субъект-объектную модель не делает. 

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

Второй недостаток - активно используя acl можно в них запутаться.  Куча разрешений и запретов накладываются друг на друга, получается в итоге, что откроется каталог, в котором всем все можно. В windows, кстати, единственный способ управления правами доступа - acl, и я не раз видел, что на сетевом диске в результате неправильного использования acl возникают каталоги, доступные всем.

Мы уже и так час потратили на повторение, поэтому сегодняшняя тема - их, собственно, две.

Главная тема - как сделать работу в командной строке поудобнее, потому что я так ловко манипулирую всеми этими утилитами. К сожалению, нам не хватает времени на то, чтобы рассказать, что есть разные виды шелла. Тот шелл, с которым мы работаем по умолчанию - это bash, еще есть zshell - он считается еще круче чем баш. У баша есть много всяких фишек, чтобы работа в командной строке была удобной. Например, подсказка: она цветная, она отслеживает, в каком каталоге мы находимся. python@python  - имя пользователя и имя компьютера Например, я захожу на другой компьютер

george@grep:~> - тут у меня другая подсказка 
$ ls ~ 

Разумеется, настраивается раскраска этой шутка (подсказки). Есть специальные переменные окружения

$PS1 и $PS2 

Подсказку можно переделать, например

$ PS1="\w \u > " - текущий каталог и пользователь 

В документации сказано много того, что можно засунуть в строку подсказки.  Почему $ ls выводит файлы цветными? Он подглядывает, какие файлы: исполняемые, каталоги, еще что-то - и выводит соответствующий цвет. Поначалу ls так не работал, поэтому когда мы вводим ls запускается не ls, а что-то типа

$ ls --color 

Замена одного на другое происходит с помощью alias, например, 

$ ll -  заменяется на $ ls -laptc 

C помощью команды алиас можно что угодно ввести туда, например, вот так

$ alias ndate="date +%Y%m%d" - получили новую команду ndate  

Если вы хотите, чтобы какой-то алиас, который у вас существует, жил всегда, вы его вставляете в 

$ vi .bashrc 

Теперь всякий раз при запуске интерактивного шелла будет запускаться bashrc и будет применяться алиас ndate. Bash_profile же запускается только один раз, когда вы входите в систему, в отличии от bashrc.

Относительно комплишнов: очень удобная штука, я ей пользуюсь на интуитивном уровне. Самый простой способ использования комплишнов - когда мы работаем с файлами. Допустим, я хочу работать с каким-то файлом, например,  CountTuple.py Все хорошо, за исключением факта, что я не хочу набирать все эти буквы.

Я знаю, что он начинается на C:

$ vi C

В момент набора имени файла и нажатия tab произойдет достраивание - комплишн. Чуть более хитрая штука с ситуацией, когда файлы неоднозначно определены, например, хочу запустить KРОССВОРД:

$ dia K - нажимаю таб - ничего не происходит, потому что есть кроссворд маленькими и большими буквами. Набираю две буквы: 
$ dia KР 

Либо выводится список файлов, подозреваемых на комплишн, либо выводится файл, если того, что вы набрали, уже достаточно. Это комплишн имен файлов, который придумали очень давно, который работает во всех шеллах, кроме самых примитивных типа dash. Если я нажимаю ls и tab - он понимает, что ls - это команда, и он мне выдает список команд, начинающихся на ls. Если названия команд большие или вы не помните как они пишутся - комплишн вам в помощь. Достраивание команды: если шелл видит, что у вас первое слово - считает, что это команда. Гораздо интереснее: в продвинутых шеллах шелл может догадаться, что то, что вы набираете - начало параметра

-- tab 

Он видит, что начинается на "--" -  ага, значит это параметры.

На самом деле, современные шеллы содержат в себе еще громадные наборы достраиваний для любых случаев жизни. 

$ rpm -ql ba (таб) - он мне выдал список пакетов при нажатии таб, потому что rpm - программа которая устанавливает пакеты. 

На самом деле даже без комплишнов довольно свободно можно манипулировать именами файлов, если они слишком длинные. Например: вот есть группа каталогов PythonWinter2015-C.old

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

$ echo Py*old 
$ echo K*dia* 

* - любое количество символов ? - один символ

Есть диапазоны:

o[0-9].* —  "о", цифра, точка, что угодно.

В zshell, например, есть более крутые механизмы построения шаблонов. Но вообще, это больше относится к программированию на шелле.

Язык шаблонов

Обратите внимание, что раскрытие шаблонов в список файлов производится шеллом. Программа в качестве параметров получает получившийся список файлов сразу. У баша есть забавный эффект: если он не раскрывает шаблон - он передает его программе в неизменном виде, это неприятно. То есть, если таких файлов нет, то выведен будет шаблон

Например:

$ echo a* 
> --список файлов--
$ echo Aa* 
> Aa* 

Zshell же по умолчанию выдает ошибку, если не найдено совпадений и шаблон не подставился.

Последнее, что хотел рассказать сегодня - управление процессами. Ими можно управлять с помощью kill, также можно управлять посылая команды с клавиатуры. Как манипулировать несколькими процессами, привязанными к одному? Их можно останавливать, присылая им sigstop, им можно продолжать работу. Посылая волшебные сигналы можно переключаться между процессами. Допустим у нас есть что-то типа

{ sleep 2; echo -n "> "; read A; echo "/$A/"; } 

Процесс был запущен не в фоне, он получит что-то на ввод

Если мы запустим его в фоне - он захочет ввести со стандартного ввода, но будучи фоновым он не сможет. Система пошлет ему сигнал sigstop и он будет остановлен.

Допустим, есть два процесса:

$ sleep 600 
$ sleep 1200 

Мы их можем остановить командой stop, либо:

$ job 

Шелл работающим процессам присваивает номера: 1 и 2

$ kill %2 

Мы остановим процесс sleep 1200. Между процессами можно переключаться:

%1 

- задание №1 станет текущим

ctrl+z - оно будет остановлено

%1& -  перейдет в бекграунд

%2 - когда задание связано с работой с терминалом - с терминала можно посылать сигналы.

Это довольно удобно: когда с терминала запускаете много процессов в фоне, а потом между ними переключаетесь, если хотите, например, какой-нибудь прибить.

История

Клавиша вверх - перечисляет все команды, которые мы только что вводили, клавиша вниз - в обратную сторону. Это бы было не так интересно, если бы не команда ctrl+r, которая позволяет искать в истории, например, все команды, которые начинаются на ls. Начинаем набирать команду, продолжаем нажимать ctrl+r и шелл подсказывает команды из истории только такие, в которые входила ls. С этим можно делать хитрые трюки.

Например, если вы хотите последнее слово, которое вы использовали, использовать со следующей командой, то можно нажать esc+_, или alt+. Повторение последнего предыдущего слова удобно, чтобы не писать длинные пути к файлу.

Работа с историей - очень важная вещь, история хранится в специальном файле.

Есть такая технология: написали какую-то команду, потом резко решили выполнить другую, поставили комментарий, выполнили свою команду и история возвращает невыполненные закоментированные команды.

LecturesCMC/LinuxSoftware2017/05_UsingShell/Conspect (последним исправлял пользователь AslanAshabokov 2017-12-28 13:05:25)