Брандмауэры и специальное программное обеспечение 8 Часть 4

Вид материалаРеферат

Содержание


Сценарии rс, часть вторая
Подобный материал:
1   ...   26   27   28   29   30   31   32   33   ...   101

Сценарии rс, часть вторая


Теперь, когда вы получили общее представление об инициализации системы, от ядра и до программы init, я расскажу вам о некоторых деталях этого процесса подробнее. В данном разделе главы я более подробно расскажу о механизме запуска-останова демонов при смене уровней выполнения. Поскольку программа init запускается ядром, она обладает привилегиями суперпользователя. Таким образом, всякий процесс, запущенный из строк 36-42 листинга 7.1, будет запущен на уровне привилегий суперпользователя, если, конечно, он явно не был запущен от имени другого (непривилегированного) пользователя. Если злоумышленнику удастся вставить туда команду запуска программы, сохраняющей коды клавиш, нажимаемых в ответ на приглашение входа в систему, и время от времени отсылающей этот файл по электронной почте на указанный им адрес, то вскоре в распоряжении злоумышленника окажутся имена и пароли всех активных пользователей системы. Если пользователь сможет в одном из каталогов /etc/rc.d/rc[l-5].d/ создать ссылку на какой-нибудь посторонний файл, то во время инициализации системы этот файл может быть запущен на выполнение от имени суперпользователя.


ВНИМАНИЕ

Все файлы, расположенные в каталоге /etc/red/ и его подкаталогах и запускаемые в процессе инициализации системы, выполняются от имени суперпользователя (в дистрибутиве Debian это замечание относится к подкаталогам rc.boot/, rc[0-6].d/ и init.d/, расположенным непосредственно в каталоге /etc). Если это ссылка, то независимо от того, ведет ли она за пределы /etc/rc.d/ или нет, файл, на который она указывает, все равно выполняется от имени суперпользователя. Любые изменения в существующих сценариях или добавления новых могут вступить в силу при следующей перезагрузке или смене уровня выполнения. Вывод очевиден: правом на запись в файлы и каталоги, используемые при инициализации системы, должен обладать только суперпользователь и никто другой.

Далее идет очень короткий обзор некоторых ключевых сценариев, включая один сценарий запуска-останова демона. Обучение чтению сценариев не входит в задачи данного текста, поэтому при возникновении трудностей следует обратиться к книге, посвященной разработке сценариев командной оболочки. Первым будет рассмотрен сценарий /etc/rc.d/rc (см. листинг 7.35). Номера строк в самом сценарии отсутствуют, они добавлены мною для удобства дальнейшего изложения.


Листинг 7.3. Сценарий re (номера строк добавлены искусственно) 1 #\/bin/bash 2#
  1. # гс This file is responsible for starting/stopping
  2. # services when the run!eve! changes.
    5#
  1. # Temporary feature:
  2. # If the action for a particular feature in the new run-level
  3. # is the same as the action in the previous run-level, this
  4. # script will neither start nor start that feature, since that
  1. # would have no effect except to thrash the system for no reason.
  2. # Once all scripts are converted to use start-stop-daemon
  3. # to _start_ their daemons (most of them only use it to kill
  4. # them), this feature can be removed.
  5. #
  6. # $Id: rc.v 1.7 1999/07/14 21:36:04 ray Exp $
    161
  1. # Author: Miquel van Smoorenburg,
  2. # Hacked to bits by Bruce Perens
  3. # Modified for COL by Raymund Will
  4. #
    21
  1. export RC_DEBUG=false
  2. export RC_VERBOSE=true
  3. LOG=/dev/tty12
    25
  1. true() { return 0; }
  2. false() { return 1; }
  3. Echo() {
  1. local a=$l; shift
  2. local o=$l; shift
  3. local i
    32
  1. echo -n "$a" >> $LOG
  2. for i in "$@"; do

35 echo -n " '$i'" >> $LOG

36 done

37 echo "$o" >> $LOG

38 }
39
  1. # check for new-style boot-logger
  2. export SVIBooter=/sbin/booter
  3. [ -x $SVIBooter ] | SVIBooter=false
    43

44 if $SVIBooter test; then
  1. export SVIuseBooter=true
  2. CMDS="add start"
    47
  1. # redirect STDOUT and STDERR
  2. exec - >> $LOG 2>&1
    50
  1. #DEBUGGING
  2. Booter() {
  1. local c=$l; shift
  2. local s
  3. local i

56

57 case "$c" in

58 add)

59 s="$l"; shift
  1. eval "$s" $c
  2. ;;

62 start)
  1. s="$l": shift
  2. eval "$s" $c "$@"

65 case $? in
  1. 0) $SVIBooter ok;;
  2. 1) $SVIBooter fail;;
  3. 2) $SVIBooter skip;;
  4. *) $SVIBooter "N/A" ;;
  1. esac
  2. ;;

72 stop)
  1. s="$l"; shift
  2. Echo "# Booter " "." "$s" $c "$@"

75 eval "$s" $c "$@"

76 ;;

77 *)

78 $SVIBooter $c "$@"

79 ;;

80 esac
  1. }
  2. [ -z "$PREVLEVEL" ] && {PREVLEVEL=N

83 else
  1. SVIuseBooter=false
  2. CMDS="start"
    86
  1. # Set onlcr to avoid staircase effect.
  2. stty onlcr 0>&1
    89

90 Booter() {
  1. local c="$1"; shift
  2. [ "$c" != "start" -a "$c" != "stop" ] && return 0
  3. local s="$l"; shift
  4. Echo "# eval " "." "$s" $c "$@"
  5. eval "$s" $c "$@"

96 }

97 fi
98

99 # Now find out what the current and what the previous run!eve! are.
100
  1. runlevel=$RUNLEVEL
  2. # Get first argument. Set new run!eve! to this argument.
  3. [ -n "$1" ] && runlevel=$l
    104

105 previous=$PREVLEVEL 106
  1. Echo "runlevel=$runlevel previous=$previous" "."
  2. export runlevel previous
    109
  1. RCD=/etc/rc.d
  2. # Is there an re directory for this new runlevel?

112 if [ -d "$RCD/rc$runlevel.d" ]; then

113 avoid="" # A list of start scripts I don't have to run.

114
  1. # First, run the KILL scripts.
  2. if [ "$previous" != N ]; then

117 for i in $RCD/rc$rumevel.d/K[0-9][0-9]*; do
  1. # Check if the script is there.
  2. [ -f "$i" ] || continue
    120

121 suffix=${i#$RCD/rc$runlevel .d/K[0-9][0-9]}
122
  1. # Generate the name of the start script corresponding
  2. # to this stop script, the start script in the previous
  3. # level, and the stop script in the previous level.
  4. # Check these files, and see if the previous level's
  5. # files are links to the ones for this level.
  6. # If they are, this level treats this feature the same
  7. # as the previous level, and I don't have to run these
  8. # files.
  9. stopIt=true
  1. start=$RCD/rc$runlevel.d/S[0-9][0-9]$suffix
  2. previous_start=$RCD/rc$previous.d/S[0-9][0-9]$suffix
  3. previous_stop=$RCD/rc$previous.d/K[0-9][0-9]$suffix
    135

136 if [ -f $previous_stop ] && [ $i -ef $previous_stop ]; then
  1. stopIt=false
  2. if [ -f $start ] || [ -f $previous_start ]: then

139 if [ -f $start ] &&
  1. [ -f $previous_start ] &&
  2. [ $start -ef $previous_start ]; then

142 stopIt=true

143 else

144 avoid=$avoid" "$start

145 fi

146 fi

147 fi
148
  1. # Kill it.
  2. $stopIt && Booter stop $i

151 done

152 fi
153
  1. Booter list "RUNLEVEL Run-level change..."
  2. Booter add_menu "BLANK4"
  3. Booter add_menu "T4 Entering run-level $runlevel:"
  4. for cmd in $CMDS; do
    158
  1. # Now run the START scripts for this runlevel.
  2. for i in $RCD/rc$runlevel.d/S*; do
  1. # Check if the script is there.
  2. [ -f "$i" ] || continue
    163
  1. startIt=true
  2. case " $avoid " in

166 *\ $i\ *) startIt=false;:
  1. esac
  2. if $startIt; then
  1. suffix=${i#$RCD/rc$runlevel.d/S[0-9][0-9]}
  2. previous_start=$RCD/rc$previous.d/S[0-9][0-9]$suffix
  3. stop=$RCD/rc$runlevel .d/K[0-9][0-9]$suffix

172 if [ -f $previous_start ] &&
  1. [ $i -ef $previous_start ] &&
  2. [ ! -f $stop ]; then

175 startlt-false

176 fi

177 fi
178

179 $startlt && Booter $cmd $i

180 done
181

182 if [ "$cmd" != "add" ]; then

183 Booter complete RUNLEVEL

184 else
  1. Booter end
  2. Booter activate RUNLEVEL

187 fi

188 done

189 fi
190

191 [ $SVIuseBooter = false ] && exit 0

192

193

194 if [ $runlevel != 5 ]: then
  1. sleep 1
  2. /usr/bin/chvt 1

197 else
  1. /sbin/booter list "FINAL"
  2. /sbin/booter add_menu "BLANK5"
  3. /sbin/booter add "KDE Starting KDE"
  4. /sbin/booter end
  5. /sbin/booter activate "FINAL"
  6. /sbin/booter item "KDE"
  7. sleep 1
  8. ( trap "" SIGHUP
  1. sleep 10
  2. echo -e "\n\nPlease switch to a different virtual console for login!\n\n"

208 ) > /dev/tty7 &

209 fi
210
  1. Booter quit
  2. # eof /etc/rc.d/rc

Строки, начинающиеся с символа #, считаются комментариями (за исключением самой первой строки, в которой указывается программа, используемая для выполнения команд сценария) и при выполнении сценария игнорируются. В строках 2-117 происходит инициализация переменных, определяются текущий и предыдущий уровни выполнения, а также сравниваются сценарии запуска-останова из соответствующих этим уровням подкаталогов каталога /etc/rc.d.

В строках начиная с 119 и до конца файла сначала выполняются сценарии останова демонов, ненужных на новом уровне выполнения. После этого осуществляется выполнение сценариев запуска демонов, которые должны выполняться на новом уровне, но сейчас не выполняются.

Следующим сценарием, который мы рассмотрим, будет типичный сценарий запуска-останова демона. Множество подобных сценариев расположено в каталоге /etc/re.d/init.d. Большинство таких сценариев очень похожи на сценарий из листинга 7.46.


Листинг 7.4. Сценарий старта-останова демона named
  1. #!/bin/sh
  2. #
  3. # named This shell script takes care of starting and stopping
  4. # named (BIND DNS server).
    5#

6
  1. NAHE=named
  2. DAEMON=/usr/sbin/$NAME
    9

10 # Source function library.

11 . /etc/rc.d/init.d/functions
12
  1. # Source networking configuration.
  2. . /etc/sysconfig/network
    15
  1. # Check that networking is up.
  2. [ ${NETWORKING} = "no" ] && exit 0
    18
  1. [ -r /etc/sysconfig/daemons/$SUBSYS ] || ONBOOT=Yes
  2. [ ! -r /etc/sysconfig/daemons/$SUBSYS ] || . /etc/sysconfig/daemons/$SUBSYS
  3. [ "$ONBOOT" = "no" -a "$PROBABLY" = "booting" ] && exit 0
    22

23 [ -x $DAEMON ] || exit 0

24

25
  1. # See how we were called.
  2. case "$1" in

28 start)

29 [ -e /var/lock/subsys/$SUBSYS ] && exit 1
30

31 [ -f /etc/named.conf ] |] exit 0
32
  1. # Start daemons.
  2. echo -n "Starting BIND DNS server: "
  3. start-stop-daemon -S -n $NAME -x $DAEMON -- $OPTIONS
  4. echo "."
  5. touch /var/lock/subsys/$SUBSYS
  6. ;;
    39

40 stop)

41 [ -e /var/lock/subsys/$SUBSYS ] || exit 0
42
  1. # Stop daemons.
  2. echo -n "Stopping BIND DNS server: "
  3. start-stop-daemon -K -p /var/run/$NAME.pid -n $NAME
  4. echo "."
  5. rm -f /var/lock/subsys/$SUBSYS
  6. ;;
    49

50 restart)

51 [ -e /var/lock/subsys/$SUBSYS ] || exit 0
52
  1. echo -n "Re-starting BIND DNS server: "
  2. start-stop-daemon -K -s 1 -p /var/run/$NAME.pid -n $NAHE
  3. echo "."
  4. ;;
    57

58 *)
  1. echo "Usage: named {start|stop|restart}"
  2. exit 1

61 esac
62

63 exit 0

Как и ранее, строки, начинающиеся с символа #, адресуются читающему сценарий пользователю и при выполнении игнорируются.

В строках 7 и 8 инициализируются некоторые переменные, а строки 11 и 14 включают в исходный текст сценария некоторые глобальные переменные из конфигурационного каталога системы (такой каталог присутствует далеко не во всех комплектах Linux). Строка 17 проверяет, запущена ли сетевая подсистема, и если нет и в случае, если сеть не работает, прекращает выполнение сценария (бессмысленно запускать DNS-сервер в отсутствие сети). Строка 23 позволяет убедиться в том, что файл демона существует и является исполняемым.

После этого выполняется обработка аргумента, переданного в сценарий. Если использован аргумент start, выполняются строки 29-38. Если использован аргумент stop и демон запущен (это проверяется в строке 41), то выполняются строки 44-48. Если аргументом является restart и демон запущен (это проверяется в строке 51), то выполняются строки 53-56, посылающие ему сигнал SIGHUP (1). Этот сигнал предписывает демону заново прочесть свой конфигурационный файл и продолжить работу.

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

Примерно так же работают и все остальные сценарии старта-останова в стиле System V. Детали зависят от дистрибутива, но общий подход везде один и тот же. Инициализация в стиле BSD происходит несколько по-другому: вместо многих небольших сценариев в этой системе используется несколько больших и отсутствует механизм start/stop/restart.