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

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


в 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;



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

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