|
Программирование >> Структура ядра и системные вызовы
/* 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-сервера.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |