|
Программирование >> Структура ядра и системные вызовы
в ONC вместо authsys create default используется API authunix createjde-fault, a константы AUTH SYS и AUTH SHORT заменены константой AUTH UNIX. При этом во всех UNIX-системах применяется один и тот же базовый метод аутентификации, основанный на UID и GID процессов. 12.7.3. Метод AUTH DES Метод аутентификации AUTH SYS прост в использовании, но не надежен, потому что не гарантирует уникальность параметров идентификации клиента (UID и GID) в масштабах Internet. Кроме того, перед RPC-вызовом клиент может запросто изменить данные cl- >cl auth так, чтобы стать кем-то другим. Для устранения этих недостатков был разработан метод AUTH DES, обеспечтаающий более надежную аутентификацию в RPC-приложениях. Прежде чем воспользоваться методом AUTHDES, клиентский процесс должен вызвать API user2netname, чтобы получеть сетевое имя (netname), уникальность которого гарантируется в масштабах Internet. Это имя составляется следующим образом: перед именем домена клиентского процесса добавляется имя операционной системы процесса и действующий UID. Например, если процесс работает на UNIX-машине в домене TJSys.com, а действующий UID процесса - 125, то его сетевым именем будет unix.125@TJSys.com. Это имя уникально, потому то имя домена всегда уникально в Internet. Кроме того, в пределах домена каждый UID должен быть уникальным для всех машин, работающих под управлением одной операционной системы. Так, если домен TJSys.com содержит VMS-машины, на которых также есть пользователь с UID 125, то процесс, созданный этим пользователем, будет иметь сетевое имя vms. 125@TJSys.com. Это имя отличает данный процесс от UNIX-процесса с тем же UID и именем домена. В качестве альтернативы активизации функции user2netname процесс может вызвать API host2netname и получить сетевое тля для машины, на которой он выполняется. Это имя также является уникальным в Internet, однако оно обозначает не пользователя, а машину. Если процесс в npjree-денном выше примере работает на UNIX-машине с именем/га/7, то функция host2netname возвратит сетевое имя unix.fruit@TJSys.com. Решение о том, каким API (user2netname или host2netname) пользоваться, зависргг от того, на каком уровне RPC-приложения должны проводить аутентификацию - на уровне пользователей или машин (уровень выбирают пользователи). API user2netname и host2netname имеют следующий синтаксис: #include <rpc/rpc.h> int user2netname (char netname[MAXNETNAMELEN+1], uid t eUlD, const char* domain); int host2netname (char netname[MAXNETNAMELEN+1], const char* hostnm, const char* domain); Первый аргумент обеих функций - это символьный буфер, минимальный размер которого составляет MAXNETNAME-I-1. Этот буфер предназначен для хранения возвращенного уникального имени процесса. Второй аргумент функции user2nefname - действующий UID процесса, а второй аргумент функции host2netname - имя хост-машины. Третий аргумент в обеих функциях - имя домена. Если значение аргумента domain передается как NULL, подразумевается имя локального домена. г-. При успешном завершении эти функции возвращают 1, ;а; в случае неудачи - 0. Запись данных AUTH DES в клиентском процессе создается с помощью API authdes seccreate. Эта функция имеет следующий прототип: #include <rpc/rpc.h> int authdes seccreate (char netname[MAXNETNAMELEN+1], unsigned window, const char* time host, const des block* ckey); Значение аргумента netname - либо сетевое имя вызывающего процесса, либо сетевое имя его хост-машины. Этот аргумент позволяет идентифицировать клиентский процесс. Аргумент window задает промежуток времени (в секундах), по истечении которого аутентификационная информация клиента, установленная этим вызовом, теряет силу. Если RPC-сервер получит RPC-вызов от клиента; который идентифицирован более чем на window секунд позже, запрос будет отклонен. Аргумент timejiost задает имя машины, с которой будет получено значение текущего времени в момент аутентификации. Обьшно это имя машины целевого RPC-сервера. Если этот аргумент задан как NULL, время клиента и сервера синхронизировать не нужно. Аргумент скеу - это DES-ключ для шифрования мандата клиента (credential). Целевой сервер пользуется этим ключом для дешифровки мандата. Если этот аргумент задан как NULL, операционная система генерирует случайный ключ. Клиент может получить DES-ключ явно, вызвав API key gendes. В случае успешного вьшолнения API authdes seccreate возвращает указатель AUTH*, который указьгеает на зашифрованную аутентификационную информацию клиента, а в случае неудачи - NULL. API key gendes создает DES-ключ для вызывающего процесса. Прототип этой функции выглядит следующим образом: int key gendes (de$ bJoek* скеу); в качестве аргумента функции key gendes используется адрес переменной типа des block. Эта переменная предназначена для хранения сгенерированного DES-ключа. При успешном выполнении функция key gendes возвращает О, а в случае неудачи -I. На стороне RPC-сервера сервер может выбрать зашифрованную аутен-тификационную информацию клиента с помощью API authdes getucred или netname2host. Первая из этих функций используется в том случае, если эта информация представляет собой сетевое имя пользователя (полученное из API user2netname). Этот API расшифровывает и возвращает серверу UID и GID клиента. Если аутентификационная информация клиента - сетевое имя машины (полученное из API host2netname), то вызывается API netname2host, который извлекает имя хост-машины клиента. Ниже приведены прототипы этих функций: #include <rpc/rpc.h> int authdesjgetucred (const struct autlides cred* adc, uid t* uid p, gid t* gid p, short* len p, gid t* gidArray); int netname2host (const char* netname, char* hostname, int len); Значение аргумента adc функции authdesjgetucred получают из аргумента rqstp серверной функции-диспетчера. Это значение записано в поле rqstp-> rq clntcred, содержащем указатель на зашифрованную аутентификационную информацию клиента. Аргументы uid р и gid р - это адреса переменных, содержащих возвращенные UID и GID клиента. Аргумент gidArray - это адрес переменной, в которой хранится возвращаемый массив дополнительных GID, а аргумент len - это размер массива hostname. Значение аргумента netname функции netname2host берется из аргумента rqstp серверной функции-диспетчера. Это значение содержится в поле rqstp-> rqjlntcred- >adcJullname.name. Аргумент hostname - это адрес символьного буфера, в котором хранится возвращенное имя хост-машины клиента. Аргумент len задает максимальный размер буфера, на который указывает аргумент hostname. При успешном выполнении обе эти функции возвращают 1, а в случае неудачи - 0. Отметим, что в классах RPC, которые описаны в разделе 12.5, RPCjclsr.setjauth может вызываться клиентским процессом для того, чтобы установить метод аутентификации AUTH SYS или AUTH DES. Во втором случае аутентификационная информация клиента состоит из его UID и GID. На стороне сервера функция RPC svc::dispatch проверяет каждого клиента, применяя установленный метод аутентификации. Если клиент задал метод AUTH NONE, функция-диспетчер просто пропускает этап проверки. В реальных защищенных RPC-приложениях это недопустимо. Пользователи могут изменить функцию-диспетчер таким образом, чтобы в случае задания клиентом метода AUTH NONE она выставляла флаг ошибки и отказывалась выполнять затребованную RPC-функцию. Если клиент применяет метод AUTH DES, функция-диспетчер вызывает API authdes jetucred ддя извлечения UID и GID клиента. Это допустимо в том случае, когда для создания мандата клиента RPCjcls::set auth вызывает только API user2netname (а не host2netname). Если же в пользовательском приложении для этой цели используется функция host2netname и/или user2netname, то функцию RPC svc::dispatch необходимо соответствующим образом откорректировать. 12.7.4. Получение списка файлов каталога с применением аутентификации Вернемся к примеру, рассмотренному в разделе 12.3.3, и перепишем его, внеся следующие изменения: компилятор rpcgen заменим классами RPC; покажем, как клиентский процесс запрашивает серверный процесс; проиллюстрируем механизм RPC-аутентификации. Файлы RPC.h и ЛРС. С приведены в разделе 12.5. Файл scan2.h создается вручную следующим образом: #ifndef SCAN2 H ♦define SCAN2 H ♦include <rpc/rpc.h> #ifdef cplusplus extern C { ♦endif ♦define MAXNLEN 255 typedef char *name t; typedef struct arg rec *argPtr; struct arg rec ( name t dir name; int Iflag; typedef struct arg rec arg rec; typedef struct dirinfo *infoiist; struct dirinfo { name t name; int uid; long modtime; infolist next; typedef struct dirinfo dirinfo; struct res { int errno; union { infolist list; } res u; typedef struct res res; ♦define SCANPROG {{unsigned long)(0x20000100)) ♦define SCANVER {(unsigned long)(1)) ♦if defined{ STDC ) I I defined( cplusplus) ♦define SCANDIR {{unsigned long){1)) extern res * scandir l(argPtr *, CLIENT *); extern res * scandir l svc(argPtr *, struct svc req *); extern int scanprog l freeresult(SVCXPRT *, xdrproc t, caddr t); ♦else /* K&R С */ ♦define SCANDIR {{unsigned long){1)) extern res * scandir l(); extern res * scandir l svc(); extern int scanprog l freeresult{); ♦endif /* K&R С */ /* XDR-функции */ ♦if defined( extern bool t extern bool t extern bool t extern bool t extern bool t extern bool t STDC ) I I defined ( cplusplU5) xdr name t{XDR *, name t*); xdr argPtr(XDR *, argPtr*); xdr arg rec(XDR *, arg rec*); xdr infolist(XDR *, infolist*); xdr dirinfo(XDR *, dirinfo*); xdr res(XDR *, res*); ♦else /* K&R С */ extern bool t xdr name t{); extern bool t xdr argPtr(); extern bool t xdr arg rec(); extern bool t xdr infolist{) extern bool t xdr dirinfо(); extern bool t xdr res(); ♦endif /* K&R С */ ♦ifdef cplusplus ♦endif ♦encjif /* 1SCAN2 H */ Клиентская программа 5сол с&2. С выглядит следующим образом: ♦include <errno.h> ♦include scan2.h ♦include RPC.h extern int errno; int main{ int argc, char* argv(]) { static res result; infolist nl; if {argcO) { cerr usage: argv(0] host direcoty [<long>]\n ; return 1; /* создать обработчик RPC-клиента */ /*RPC cls cl{ argv[l), SCANPROG, SCANVER, netpath );*/ RPC cls cl( argv[l), SCANPROG, SCANVER, tcp ); if (!cl.good{)) return 1; /* установить метод аутентификации */ cl.set auth{ AOTH DES ); /* запросить РРС-сервер, чтобы проверить, что он работает */ if {cl.call{ О, ,{xdrproc t)xdr void. О, {xdrproc t)xdr void, О ) == RPC SUCCESS) cout << Prog SCANPROG (version SCANVER ) is aliveXn ; else { cerr prog SCANPROG version SCANVER is dead!\n ; return 2; /* выделить память для хранения возвращаемого списка файлов каталога */ struct arg rec *iarg = {struct arg rec*)malloc(sizeof(struct arg rec)); iarg->dir name = argv[2]; установить имя удаленного каталога iarg->lflag =0; установить флаг вывода подробной информации if (argc==4 && sscanf(argv[3], %u ,&{iarg->lflag))!=1) { fprintf(stderr, Invalid argument: %s\n , argv[3]); return 3; /* вызвать RPC-функцию */ if (cl.calK SCANDIR, (xdrproc t)xdr argptr, (caddr t)Siarg, (xdrproc t)xdr res, (caddr t)Sresult) != RPC SUCCESS) cerr client: call RPC failsXn ; return 4;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |