Главная страница

Лекция 1 - Среда исполнения. Среда исполнения введение


Скачать 155.5 Kb.
НазваниеСреда исполнения введение
Дата24.03.2022
Размер155.5 Kb.
Формат файлаdoc
Имя файлаЛекция 1 - Среда исполнения.doc
ТипПрограмма
#412377
страница7 из 7
1   2   3   4   5   6   7

Программа доступа к переменным среды


Эта программа показывает, как переменные среды первоначально расположены в стеке, и что environ и третий аргумент main() указывают на одну и ту же таблицу адресов. Также демонстрируется использование getenv(3C) и putenv(3C).

4 Внешняя переменная environ содержит адрес таблицы, в которой хранятся указатели на все переменные среды.

6 При запуске main значение третьего параметра envp такое же, как и у environ.

10 printenv() печатает значение env и environ, а также адреса из таблицы и строку (имя=значение), расположенную по этому адресу. Останавливается по достижению нулевого адреса.

11 putenv("TZ=PST8PDT") изменяет значение TZ. Адрес, указывающий значение переменной TZ, указывает уже не на стек, а на сегмент данных, т.к. используется строковая константа.

13-14 Переменная WARNING вноситься в среду и печатается содержание среды.

15 Печать значения, возвращенного getenv(3C), в виде строки.

18-30 Описание printenv()

Файл: envex.c $ envex 1 envp contains c0020060 2 environ contains c0020060 3 My environment variables are: 4 (c0020060) = c0020006 -> HOME=/home/jrs 5 (c0020064) = c0020015 -> LOGNAME=jrs 6 (c0020068) = c0020021 -> MAIL=/var/mail/jrs 7 (c002006c) = c0020034 -> PATH=/usr/bin:. 8 (c0020070) = c0020049 -> TZ=EST5EDT 9 10 envp contains c0020060 11 environ contains c0020060 12 My environment variables are: 13 (c0020060) = c0020006 -> HOME=/home/jrs 14 (c0020064) = c0020015 -> LOGNAME=jrs 15 (c0020068) = c0020021 -> MAIL=/var/mail/jrs 16 (c002006c) = c0020034 -> PATH=/usr/bin:. 17 (c0020070) = 80002d98 -> TZ=PST8PDT 18 19 envp contains c0020060 20 environ contains 80006498 21 My environment variables are: 22 (80006498) = c0020006 -> HOME=/home/jrs 23 (8000649c) = c0020015 -> LOGNAME=jrs 24 (800064a0) = c0020021 -> MAIL=/var/mail/jrs 25 (800064a4) = c0020034 -> PATH=/usr/bin:. 26 (800064a8) = 80002d98 -> TZ=PST8PDT 27 (800064ac) = 80002da4 -> WARNING=Don't use envp after putenv() 28 29 value of WARNING is: Don't use envp after putenv()

Замечание: putenv(3C) для новой переменной вызывает malloc(), перемещая таблицу адресов из стека в сегмент данных. Вся таблица перемещается в сегмент данных.

ПРОГРАММА ДОСТУПА К ПЕРЕМЕННЫМ СРЕДЫ 1 #include 2 #include 3 4 extern char **environ; /* system variable */ 5 6 main(int argc, char *argv[], char *envp[]) 7 { 8 void printenv(const char **); 9 10 printenv(envp); 11 putenv("TZ=PST8PDT"); 12 printenv(envp); 13 putenv("WARNING=Don't use envp after putenv()"); 14 printenv(envp); 15 printf("value of WARNING is: %s\n", getenv("WARNING")); 16 } 17 18 void printenv(const char **envp) 19 { 20 char **p; 21 22 printf("envp contains %8x\n", envp); 23 printf("environ contains %8x\n", environ); 24 25 printf("My environment variables are:\n"); 26 /* loop stops on encountering a pointer to a NULL address*/ 27 for (p = environ; *p; p++) 28 printf ("(%8x) = %8x -> %s\n", p, *p, *p); 29 putchar('\n'); 30 }

Использование переменных среды (PATH)


Некоторые переменные среды воздействуют на поведение некоторых программ и библиотечных функций. Так, переменная среды PATH воздействует на поведение shell и функций execvp(2) и execlp(2) (эти функции описаны в разделе руководства 2, которое посвящено системным вызовам, но на самом деле это функции- «обертки» над вызовами execl и execv). Эта переменная среды представляет собой список разделенных двоеточиями имен директорий. При запуске команды, shell и execlp/execvp ищут файл, совпадающий с именем команды, во всех директориях, перечисленных в PATH. Если в разных каталогах лежит несколько одноименных файлов, будет запущен тот файл, который был найден первым, поэтому порядок директорий в PATH важен.

В отличие от командных процессоров DOS, OS/2 и Windows, командные процессоры Unix по умолчанию НЕ ищут исполняемые файлы в текущем каталоге. Если вы хотите, чтобы поиск в текущем каталоге происходил, необходимо добавить имя . или пустую строку в PATH. Это можно сделать командами

$ PATH=$PATH:.

или

$ PATH=$PATH:

Оба примера добавляют текущий каталог в конец PATH, так что он будет просматриваться после остальных директорий, а не перед ними, как в OS/2 и Windows. На самом деле, добавлять текущий каталог в PATH опасно, а в начало PATH это может быть даже недопустимо. Ведь при таком PATH вы можете по ошибке исполнить файл из текущего каталога вместо стандартной команды. Особенно это опасно если вы находитесь в чужом каталоге, содержимое которого вам неизвестно. Если PATH не содержит текущего каталога, то написанные вами программы можно запускать с указанием путевого имени, например:

$ ./a.out

Использование переменных среды (TZ)


Еще одна переменная, которая влияет на поведение многих программ и важных библиотечных функций — это переменная TZ. Системные часы Unix используют Всемирное координированное время (UTC), которое приблизительно соответствует среднему времени по Гринвичу (GMT). Именно такое время возвращает системный вызов time(2) и такое же время используется во многих временных штампах, например во временах создания и модификации файлов. Значение, возвращаемое time(2) определено как число секунд с 0 часов 0 минут 0 секунд по UTC 1 января 1970 года. Разумеется, если часы вашего компьютера идут неточно, time(2) может возвращать ошибочные значения.

Для перевода системного времени и системных временных штампов в местный часовой пояс используются такие функции, как ctime(3C) и localtime(3C). Эти функции определяют «местный часовой пояс» и местные правила перевода летнего-зимнего времени на основании значения переменной среды TZ или содержимого файла /etc/timezone, если переменная TZ не определена. Таким образом, изменяя TZ, можно «переселять» процессы в разные часовые пояса. Это может быть удобно, например, если вы удаленно зашли по ssh(1) на машину, расположенную в другом городе.

Допустимые значения TZ описаны на странице руководства environ(5). Наиболее употребительный формат значения TZ, применяемый в современных Unix-системах — это имя файла в каталоге /usr/share/lib/zoneinfo/ . В поставку Solaris входит обширная база описаний часовых поясов, основанная на так называемой IANA Time Zone Database, содержащая не только смещения от UTC и правила перевода летнего и зимнего времени для практически всех административных часовых поясов в мире, но и исторические изменения указанных сведений. Так, для всех часовых поясов на территории бывшей Российской Империи указано, что до 1919 года время на этих территориях имело смещение от UTC, не кратное часу, потому что отсчитывалось не от Гринвича, а от меридиана Пулковской обсерватории. При изменениях часовых поясов, база данных обновляется. Пользователи Solaris получают эти обновления вместе с остальными обновлениями операционной системы.

В Solaris, описания часовых поясов из IANA Time Zone Databaze компилируются специальной программой zic(1) в небольшие бинарные файлы, которые интерпретируются функциями стандартной библиотеки.

Бит установки идентификатора пользователя и setuid(2)


При входе в систему идентификаторы пользователя и группы устанавливается на основе учетной записи пользователя, например из файла /etc/passwd. Реальные и эффективные идентификаторы для процесса обычно совпадают. Эффективный идентификатор пользователя и список групп доступа (показываемый getgroups(2)) используются для определения прав доступа к файлам. Владелец любого файла, созданного процессом, определяется эффективным идентификатором пользователя, а группа файла — эффективным идентификатором группы.

В Unix, исполняемые файлы могут иметь специальные атрибуты: биты установки идентификатора пользователя или группы (setuid- и setgid-биты). Эти биты устанавливаются с помощью команды chmod(1) или системного вызова chmod(2). Биты setuid и setgid показываются командой ls -l буквой 's' на месте обычного расположения 'x', например:

$ ls -l `which su` -r-sr-xr-x 1 root sys 38656 Oct 21 2011 /usr/bin/su

Если один или оба этих бита установлены, при запуске такого файла, эффективный идентификатор пользователя и/или группы у процесса становится таким же, как и у владельца и/или группы файла с программой. Благодаря этому механизму можно стать «заместителем» или «представителем» привилегированной группы.

Используя программы с setuid-битом, можно получить доступ к файлам и устройствам, которые обычным образом недостижимы. Например, если какой-либо файл данных доступен по чтению и записи только для владельца, другие пользователи не могут получить доступ к этому файлу. Если же владелец этого файла напишет программу доступа к этому файлу и установит setuid-бит, тогда все пользователи данной программы смогут получить доступ к файлу, ранее недостижимому. Патент на механизм установки идентификатора пользователя принадлежит Дэннису Ричи, одному из разработчиков первой версии Unix.

Некоторые стандартные команды ОС UNIX имеют setuid-бит. Например, информация о паролях находится в файле /etc/shadow. Этот файл может читать только владелец — привилегированный пользователь (root). Тем не менее, каждый пользователь может изменить свой пароль. Это возможно, потому что владельцем программы изменения пароля /bin/passwd является root и у этой программы установлен setuid-бит. Другой пример - /sbin/ping. Благодаря этой программе пользователь может отправлять и получать пакеты ICMP ECHO и ECHO REPLY, что требует открытия так называемого «сырого» (raw) сокета. Это недоступно обычному пользователю.

Программа с setuid- или setgid-битом будет иметь эффективный идентификатор отличный от реального либо до конца времени выполнения процесса, либо до применения setuid(2) или setgid(2). С помощью этих системных вызовов, эффективный идентификатор вновь можно сделать равным реальному. setuid(2) или setgid(2) используются в программе, если владелец программы хочет предоставить пользователю возможность быть его «представителем», но в программе есть часть, где нет необходимости в специальных привилегиях.

Суперпользователь может применять setuid(2) для установки идентификатора, равному идентификатору любого пользователя в системе.

Программа /bin/login, запускаемая от имени root использует числовые идентификаторы пользователя и группы, обнаруженные в файле /etc/passwd, как аргументы setuid(2) и setgid(2) для установки реального идентификатора пользователей при входе в систему.

Поскольку суперпользователь может в любой момент стать любым другим пользователям, в традиционных Unix-системах он также имеет другие привилегии, например, возможность читать и писать любые файлы, не обращая внимания на права. В Solaris есть возможность более гибкого управления такими привилегиями, называемая RBAC (Role-Based Access Control, управление доступом основанное на ролях, privileges(5)). Администратор системы может дать привилегию читать файлы, не обращая внимание на права, любому пользователю. Это может быть нужно, например, оператору резервного копирования.


Программа, использующая механизм setuid


Это программа демонстрирует механизм установки идентификатора пользователя. Она имеет setuid-бит и ее владельцем является владелец файла answer. Так как setuid-бит установлен, обучаемые получают право писать в файл преподавателя.

Сопутствующий протокол вывода показывает, что у программы quiz установлен setuid-бит.

6 Открывается файл answer для дозаписи.

10-12 Задается вопрос обучаемым.

13-16 Принимается только ответ a или b.

17 Ответ записывается в файл answer.

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

. Директория, содержащая answer, доступна для записи толькопользователю instr. Никто больше не может создавать или уничтожить там файлы.

. Заметим, что владелец instr может читать/писать в файл answer.

Программа quiz имеет setuid-бит и может быть выполнена кем угодно. Бит setuid может быть установлен командой chmodu+squiz. Если преподаватель просмотрит содержимое файла answer после того, как пользователь с реальным идентификатором 507 закончит исполнение программы quiz, он увидит, что ответ "пользователя 507" записан в файл answer, писать в который разрешено только владельцу.

. Преподаватель просматривает содержимое файла answer.

. Обучаемый пытается просмотреть содержимое файла answer, а затем выполняет программу quiz.

ПРОГРАММА, ИСПОЛЬЗУЮЩАЯ МЕХАНИЗМ УСТАНОВКИ ИДЕНТИФИКАТОРА ПОЛЬЗОВАТЕЛЯ 1 #include 2 #include 3 #include 4 main() 5 { 6 FILE *fp; static char response; 7 if((fp = fopen("answer","a+")) == NULL){ 8 fprintf(stderr,"Cannot open answer\n"); 9 exit(1); 10 } 11 printf("When opening a file,\n"); 12 printf("which id is checked?\n"); 13 printf(" (a)real (b) effective\n"); 14 while( response != 'a' && response != 'b'){ 15 printf("Answer(a/b)? "); 16 scanf("%c%*c", &response); 17 } 18 fprintf(fp,"%5ld:%c\n", getuid(), response); 19 fclose(fp); 20 } Два сеанса работы за двумя терминалами: $ id $ id uid=75(instr) gid=21(unixc) uid=507(stu1) gid=1(other) $ chmod u+s quiz $ ls -ld . quiz answer | cut -c1-24,55- # at both terminals drwxr-xr-x 1 instr . -rw------- 1 instr answer -rwsr-xr-x 1 instr quiz $ cat answer $ cat answer 511:b cat: cannot open answer 503:b $ quiz 505:a When opening a file, 508:b which id is checked? (a)real (b) effective Answer(a/b)? b

Приложение. Разбор опций из командной строки


getopt(3C) - это функция общего назначения для обработки опций командной строки. Командная строка должна удовлетворять следующим правилам:

Общий формат: имя_команды [опции] [другие аргументы]

имя_команды Имя выполняемого файла.

опции Должны начинаться со знака минус. Каждая опция представляет собой один символ. Каждая опция может иметь собственный разделительный минус или несколько опций могут совместно использовать один знак минус. Некоторые опции требуют аргументов. Аргумент может следовать непосредственно за символом опции или быть отделен от нее пробелом. Смотрите intro(1) для сверки с общепринятым синтаксисом командной строки.

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

Пример:

ls -lt /tmp; pr -n file1 file2;

getopt(3C) обычно исполняется в начале программы. Она вызывается в цикле для последовательной обработки опций программы. У getopt(3C) три аргумента:

- Целый argc. Обычно первый аргумент main().

- Указатель на вектор символов argv. Обычно второй аргумент main().

- Указатель на символ (строка параметров). Это строка допустимых опций. Если у опции есть аргументы, то за соответствующим символом строки должно стоять двоеточие.

getopt(3C) возвращает одно из следующих целых значений:

буква верной опции

-1 при обработке первого аргумента не опции

getopt(3C) использует четыре внешних переменных:

optarg указатель на символ. Когда getopt(3C) обрабатывает опцию, у которой есть аргументы, optarg содержит адрес этого аргумента.

optind целое. Когда getopt(3C) возвращает -1, argv[optind] указывает на первый аргумент не-опцию.

opterr целое. Когда getopt(3C) обрабатывает недопустимые опции, сообщение об ошибке выводится на стандартный вывод диагностики. Печать может быть подавлена установкой opterr в ноль.

optopt целое. Когда getopt(3C) возвращает '?', optopt содержит значение недопустимой опции.

Для разбора многобуквенных опций можно использовать функцию getopt_long(3C), которая в этом курсе не рассматривается.

Использование getopt(3C) в программе


6 Создание строки допустимых опций. Опции, за которыми следует двоеточие ":", требуют соответствующих параметров.

7 Объявление флагов необязательных опций.

10 Печать числа входных параметров.

11 Вход в цикл вызова getopt(3C) для просмотра командной строки, возвращается одна опция за один проход цикла.

12 Вход в выбор switch для обработки опций. Обычно флаг устанавливается для указания присутствия конкретной опции. Флаг используется в программе позже.

16,20 Если опции нужен параметр, тогда переменная optarg будет содержать адрес этого параметра. Если этот адрес будет использоваться позже, то он должен быть сохранен в символьном указателе.

24,25 Если обнаружена недопустимая опция, getopt(3C) вернет '?' и выдаст сообщение об ошибке на стандартный вывод диагностики. Выдача сообщения может быть выключена установкой opterr в ноль. optopt содержит значение недопустимой опции.

35-37 Когда getopt(3) возвращает -1, тогда argv[optind] указывает на первый аргумент командной строки, отличный от опции.

Файл: getopt_ex.c $ getopt_ex -db -f abc -c -g hij -d file1 file2 1 argc equals 10 2 getopt_ex: illegal option -- b 3 invalid option is b 4 getopt_ex: illegal option -- c 5 invalid option is c 6 dflg equals 2 7 f_ptr points to abc 8 g_ptr points to hij 9 invalid equals 2 10 optind equals 8 11 next parameter = file1 ИСПОЛЬЗОВАНИЕ getopt(3C) В ПРОГРАММЕ 1 #include 2 #include 3 4 main(int argc, char *argv[]) 5 { 6 char options[ ] = "f:dg:"; /* valid options */ 7 int c, invalid = 0, dflg = 0, fflg = 0, gflg = 0; 8 char *f_ptr, *g_ptr; 9 10 printf("argc equals %d\n", argc); 11 while ((c = getopt(argc, argv, options)) != EOF) { 12 switch (c) { 13 case 'd': 14 dflg++; 15 break; 16 case 'f': 17 fflg++; 18 f_ptr = optarg; 19 break; 20 case 'g': 21 gflg++; 22 g_ptr = optarg; 23 break; 24 case '?': 25 printf("invalid option is %c\n", optopt); 26 invalid++; 27 } 28 } 29 printf("dflg equals %d\n", dflg); 30 if(fflg) 31 printf("f_ptr points to %s\n", f_ptr); 32 if(gflg) 33 printf("g_ptr points to %s\n", g_ptr); 34 printf("invalid equals %d\n", invalid); 35 printf("optind equals %d\n", optind); 36 if(optind < argc) 37 printf("next parameter = %s\n", argv[optind]); 38 }
1   2   3   4   5   6   7


написать администратору сайта