Программирование >>  Структура ядра и системные вызовы 

1 ... 75 76 77 [ 78 ] 79 80 81 ... 98


/* RPC-функция: progno=lr-vers=2, proc no=l */ int funcl 2 l (SVCXPRT* xprt) {

cerr funcl 2 l calledXn ;

svc2p->reply(xprt, {xdrproc t)xdr void, 0);

return RPC SUCCESS;

/* RPC-функция: progno=2, vers=l, proc no=l */

int func2 l l (SVCXPRT* xprt)

cerr func2 l l calledXn ;

svc3p->reply{xprt, {xdrproc t)xdr void, 0);

return RPC SUCCESS;

/* синтаксис: test rpc {-s] {<nettype>] */

int main {int argc, cliar* argv[])

chiar* nettype = (argOl) ? argv{l] : netpath ;

/* создать обработчик svclp = new RPC svc ( /* создать обработчик svc2p = new RPC svc ( /* создать обработчик svc3p = new RPC svc (

сервера для progno=l, vers=l */ PROGINUM, VERSINUM, nettype ); сервера для progno=l, vers=2 */ PROGINUM, VERS2NUM, nettype ); сервера для prog no=2, vers=l */ PR0G2NUM, VERSINUM, nettype );

if (!svclp->good() II !svc2p->good() II !svc3p->good()) {

cerr create server handle(s) failedXn ; return 1;

/* зарегистрировать RPC-функцию */

svclp->add proc( PROGINUM, funcl l l );

svclp->add proc( PR0C2NUM, funcl l 2 );

svc2p->add proc( PROGINUM, funcl 2 l );

svc3p->add prod( PROCINUM, func2 l l );

/* ожидать RPC-запросы клиентов для всех серверов */ RPC svc::run(); return 0;

Эта серверная программа берет из командной строки необязательный аргумент, который задает тип транспортного протокола. Если аргумента нет, по умолчанию принимается значение netpath .

Сервер создает три объекта RPC svc - по одному для каждой версии RPC-программы, которой он управляет:

RPCsvc Управляемая программа

Управляемая версия

svdp svc2p svc3p

PROGINUM PROGINUM PROG2NUM

VERSINUM VERS2NUM VERSINUM

Сервер использует созданные объекты для регистрации RPC-функции. Имя функции формируется следующим образом: сначала идет префикс func, затем номер программы, знак подчеркивания, номер версии, опять знак подчеркивания и, наконец, номер процедуры. Так, funcl 2 l означает, что эта функция представляет собой версию 2 процедуры 1 RPC-программы 1.

После регистрации всех этих RPC-функций сервер вызывает функцию RPC svc::run и ожидает клиентские RPC-запросы. При поступлении запроса активизируется функция RPC svc::dispatch, которая, в свою очередь, вызывает одну из зарегистрированных RPC-функций (в соответствии с указанными клиентом номерами программы, версии и процедуры).

Имя профаммы-клиента в нашем примере - test cls. С.

♦include RPC.h finclude test.h

int main(int argc, char* argv[])

if (argc < 2) {

cerr usage: argv[0] <server-host> {<nettype>]\n ; return 1;

char* nettype = (argc > 2) ? argv[2] : netpath ; while (1) { /* client */

unsigned progid, progno, verno, procno;

/* получить требуемые номер программы, номер версии и номер

функции */ do {

cout Enter prog#, ver#, proc#: flush; cin progno verno procno; if (cin.goodO) break; if (cin.eofO) return 0; ) while (1);

/* преобразовать пользовательский номер программы

во внутренний номер */ progid = (progno==l) ? PROGINUM : PR0G2NUM;

RPC cls *clsp = new RPC cls ( argv[1], progid, verno, nettype);



if (!clsp->good()) ( , ,. , л, ,

cerr create client handle(s) failed\n ; ч return 2;

/* вызвать затребованную пользователем RPC-функцию */ if (clsp->call( procno, (xdrproc t)xdr void, 0,

(xdrproc t)xdr void, 0 )

!= RPC SUCCESS) cerr client call RPC function fails\n ;

delete clsp;

return 0;

При вызове клиентской программы в качестве аргумента задается хост-имя сервера и, по желанию, значение nettype. Если аргумент nettype не указан, по умолчанию принимается netpath .

Клиентская программа выполняется в диалоговом режиме и предлагает пользователю ввести номера программы, версии и процедуры каждой вызываемой RPC-функции. Клиентский процесс создает объект RPC cls для каждого полученного таким образом набора номеров и вызывает через него затребованную функцию. Завершается клиентский процесс, когда в потоке ввода встречается признак конца файла.

Эти программы компилируются и запускаются следующим образом (в нашем примере и клиент, и сервер выполняются на машине fruit):

% ОС -DSYSV4 test cls.C RPC.C -о test cls -Isocket -Insl % СС -DSYSV4 test svc.C RPC.C -О test svc -Isocket -Insl % tets svc & [1235]

% test cls fruit

Enter prog#, ver#, proc#: 111

*** funcl l l called

Enter prog#, ver#, proc#: 112

*** funcl l 2 called

Enter prog#, ver#, proc#: 12 1

*** funcl 2 l called

Enter prog#, ver#, proc#: 2 11

*** func2 l l called

Enter prog#, ver#, proc#: 110

Enter prog#, ver#, proof: 4 12

fruit: RPC: Procedure unavailable

client call RPC function fais

Enter prog#, ver#, procf:

В этом случае RPC-функции вызывались в таком порядке: funcl l l, func 1 1 2, func 1 2 1 п func2 l l. Вводом номеров 1 1 О пользователь заставляет клиентскую программу запрашивать у RPC-сервера программу PROGINUM (версия VERS 1 NUM). Для этой операции не задан вывод ответного сообщения. Ввод номеров 4 1 2 - это попытка вызывать несуществующую

RPC-функцию, поэтому и функция RPC cls::call, и клиентская программа test cls. С выдали сообщения об ошибке.

12.7. Аутентификация

Доступ к некоторым RPC-услугам разрешен только определенным пользователям. Поэтому клиентские процессы должны идентифицировать себя серверам, иначе затребованные RPC-функции вызываться не будут. В UNIX-системах есть несколько базовых методов аутентификации, но пользователи могут применять и собственные методы.

К встроенным в UNIX System V.4 методам RPC-аутентификации относятся AUTH NONE, AUTH SYS, AUTH SHORT и AUTH DES. В ONC применяются следующие методы: AUTH NONE, AUTH UNIX (эквивалент AUTH SYS) и AUTH DES. Рассмотрим эти методы подробнее.

Для аутентификации в данных аргумента struct svc req, передаваемого клиентом функции-диспетчеру RPC-сервера, указываются номера целевой функции (номер программы, номер версии и номер процедуры) и аутентификационные данные клиента. Тип struct svc req объявляется следующим образом:

struct svc req (

u long u long u long

struct opaque auth

caddr t

struct svcxprt*

rq prog; /* номер сервисной программы */

rq verS; /* номер сервисного протокола */

rq proc; /* требуемая процедура */

rq cred; /* необработанная

аутентификационная

информация */ rq clntcred; обработанная

аутентификационная

информация только для

чтения */

rq xprt; /* соответствующий механизм

транспортировки */

где тип данных struct opaque auth объявляется в заголовке <rpc/auth.h> следующим образом:

struct opaque auth

enum t. caddr t

u int

oa flavor; oa base; oa length;

/* метод аутентификации */ /* указатель на специальные

аутентификационные данные */ /* размер данных, указанных с

помощью оа base */

о;й5ие ам г.-;оо /7агаг указывается метод аутентификации, исполь-Уемый клиентом. Если значение этого аргумента равно AUTH NONE,



AUTH SYS, AUTH SHORT или AUTH DES, то значения полей opaquejauth::oa base и opaque auth::oa length никакой роли не играют. В поле svc req::rq clntcred указывается запись, в которой содержатся соответствующие аутентификационные данные.

Если в поле opaqueauthr.oaJlavor содержится одно из значений AUTHxxx, то в поле opaque authr.oa base - указатель на определяемую пользователем запись аутентификационных данных, а в поле opaque auth::oa length - размер записи, указанной в поле opaque auth::oa base.

Дальше мы рассмотрим методы RPC-аутентификации, встроенные в UNIX-системы. На их основе пользователи могут создавать собственные методы аутентификации.

12.7.1. Метод AUTH NONE

Этот метод RPC-аутентификации применяется в UNIX System V по умолчанию и в действительности никакой аутентификации не выполняет. Клиент может установить этот метод явно, вызвав API authnone create:

CLIENT* clntp = clnt create(...); if (clntp) {

clntp->cl auth = authnone create0;

clnt call(clntp, ...);

После этого для всех функций-диспетчеров RPC, вызываемых этим клиентом, значение svc req::rq cred.oaJlavor будет равно AUTHNONE. Эти функции должны игнорировать значения svcreqr.rqcred.oabase, svcreqiirqcred.oajength и svc req::rq clntcred.

12.7.2. Метод AUTH SYS (или AUTH UNIX)

В этом методе применяется управление доступом процессов ОС UNIX, т.е. для аутентификации клиентов используются UID и GID процессов. Клиент может установить этот метод явно, вызвав API authsys create default.

CLIENT* clntp = clnt create(...) ; if (clntp) {

clntp->cl auth = authsys create default0

clnt call(clntp, ...);

После этого для всех вызьгеаемых клиентом функций-диспетчеров RPC значение svcreq::rq cred.oaJbvor будет равно AUTH SYS, а поле svc req::rq clntcred будет указывать на запись данных со следующей структурой: struct authsys parms

u int gid t

aip len; aup gids;

/* число элементов в aup gids */ /* дополнительные GID клиента */

u long char* uid t gid t

aup time; aup machname; aup uid; aup guid;

/* время создания аутент. данных */

/* имя машины клиента */

/* эффективный UID клиента */

/* эффективный GID клиента */

Ниже приведен пример серверной функции-диспетчера, которая выполняет аутентификацию клиента:

. й .

int dispatch( struct svc reg* rqstp, SVCXPRT* xtrp ) (

struct authsys parms* ptr; switch (rqstp->Oa flavor) { case AUTH NONE:

break; case AUTH SYS:

ptr = (struct authsys parms*)rqst->rqclntcred; if (ptr->aup uid != 0 (

svcerr systemerr(xtrp); return;

case AUTH DES:

break; default:

svcerr weakauth ( xtrp ); return;

/* выполнить или вызвать реальную RPC-функцию */

В этом примере RPC-сервер пропускает проверку полномочий клиента, если в rqstp->rq cred.oaJlavor указан метод аутентификации AUTH NONE. Если же клиент выбрал метод AUTH SYS, сервер проверяет, является ли действующий UID клиента идентификатором привилегированного пользователя (через аргумент rqstp->rq clntcred.aup uid). Если он таковым не является, сервер вызывает API svcerr systemerr ддя вывода системного сообщения об ошибке. Это просто пример, и реальные пользовательские приложения могут проверять UID и/или GID клиентов так, как считают нужным.

Если для аутентификации клиента не задан ни один из стандартных системных методов, сервер вызывает API svcerrjveakauth, с помощью которого клиенту посылается сообщение об ошибке аутентификации unsupported .

API svcerr weakauth и svcerrsystemerrvmevyi следующие прототипы функций:

void svcerr weakauth ( const SVCXPRT* xtrp ); void svcerrjsystemerr ( const SVCXPRT* xtrp );

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



1 ... 75 76 77 [ 78 ] 79 80 81 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика