Читать «UNIX: взаимодействие процессов» онлайн - страница 242

Уильям Ричард Стивенс

Запустим эту программу, не изменяя размер приемного буфера по сравнению с листингом 15.2. Мы ожидаем, что data_ptr и rbuf будут указывать на переменную oval и rsize будет иметь значение 4 (4 байта в буфере). И действительно, вот что мы видим:

solaris % client2 /tmp/server2 22

&oval = effff740, data_ptr = effff740, rbuf = effff740, rsize = 4

result: 484

Изменим только одну строку в листинге 15.4, уменьшив размер буфера клиента до одного байта. Новый вариант строки 18 будет иметь вид:

arg.rsize = sizeof(long) – 1; /* размер буфера данных */

Запустим новую программу и увидим, что библиотека автоматически выделила место под новый буфер результатов и data_ptr теперь указывает на новый буфер:

solaris % client3 /tmp/server3 33

&oval = effff740, data_ptr = ef620000, rbuf = ef620000, rsize = 4096

result: 1089

Размер выделенного буфера равен 4096 байт, что совпадает с размером страницы в данной системе, который мы узнали в разделе 12.6. Этот пример показывает, что следует всегда обращаться к результатам через указатель data_ptr, а не через переменные, адреса которых были переданы в rbuf. В нашем примере к результату типа «длинное целое» следует обращаться как *(long*)arg.data_ptr, а не oval (что мы делали в листинге 15.2).

Новый буфер выделяется вызовом mmap и может быть возвращен системе с помощью munmap. Клиент может повторно использовать этот буфер при новых вызовах door_call.

Функция door_cred и информация о клиенте

На этот раз мы изменим нашу функцию servproc из листинга 15.3, добавив в нее вызов door_cred для получения информации о пользователе. В листинге 15.5 приведен текст новой процедуры сервера; функции main клиента и сервера не претерпевают изменений по сравнению с листингами 15.2 и 15.3.

Листинг 15.5. Процедура сервера, получающая информацию о клиенте

//doors/server4.c

1  #include "unpipc.h"

2  void

3  servproc(void *cookie, char *dataptr, size_t datasize,

4   door_desc_t *descptr, size_t ndesc)

5  {

6   long arg, result;

7   door_cred_t info;

8   /* получение и вывод информации о клиенте */

9   Door_cred(&info);

10  printf("euid = %ld, ruid = %ld, pid = %ld\n",

11  (long) info.dc_euid, (long) info.dc_ruid, (long) info.dc_pid);

12  arg = *((long *) dataptr);

13  result = arg * arg;

14  Door_return((char *) &result, sizeof(result), NULL, 0);

15 }

Сначала мы запустим программу-клиент и увидим, что действующий и реальный идентификаторы клиента совпадают, как мы и предполагали. Затем мы сменим владельца исполняемого файла на привилегированного пользователя, установим бит SUID и запустим программу снова:

solaris % client4 /tmp/server4 77 первый запуск клиента

result: 5929

solaris % su                      вход под именем привилегированного пользователя

Password:

Sun Microsystems Inc. Sun OS 5.6 Generic August 1997

solaris # cd                     каталог, в котором находится исполняемый файл