Выбрать главу

Наилучшим способом определения необходимого размера возвращаемого буфера для функции GetFileSecurity является двукратный вызов этой функции. Во время первого вызова значение параметра cbSd может быть задано равным 0. После того как буфер выделен, вызовите эту функцию второй раз. Этот принцип применяется в программе 15.4.

Вряд ли следует подчеркивать тот факт, что для выполнения этих операций требуются соответствующие полномочия. Так, для успешного выполнения функции SetFileSecurity необходимо либо иметь полномочия на уровне WRITE_DAC, либо быть владельцем объекта.

Функции GetSecurityDescriptorOwner и GetSecurityDescriptorGroup позволяют извлекать идентификаторы SID из дескриптора безопасности, полученного при помощи функции GetFileSecurity. Для получения ACL следует воспользоваться функцией GetSecurityDescriptorDacl. 

BOOL GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pAcl, LPBOOL lpbDaclDefaulted) 

Параметры этой функции почти полностью совпадают с параметрами функции GetSecurityDescriptorDacl за исключением того, что возвращаются флаги,указывающие на то, действительно ли представлен разграничительный ACL и был ли он установлен по умолчанию или пользователем.

Чтобы иметь возможность интерпретировать список ACL, необходимо выяснить, сколько элементов АСЕ в нем содержится. 

BOOL GetAclInformation(PACL pAcl, LPVOID pAclInformation, DWORD cbAclInfo, ACL INFORMATION CLASS dwAclInfoClass) 

В большинстве случае параметр информационного класса ACL, dwAclInfoClass, равен AclSizeInformation, а параметр pAclInformation представляет собой структуру типа ACL_SIZE_INFORMATION. Другим возможным значением параметра класса является AclRevisionInformation.

В структуру ACL_SIZE_INFORMATION входят три элемента, наиболее важным из которых является AceCount, который указывает, сколько элементов содержится в списке. Чтобы выяснить, достаточно ли велик размер ACL, проверьте значения элементов AclBytesInUse и AclBytesFree структуры ACL_SIZE_INFORMATION.

Функция GetAce извлекает извлекает АСЕ по заданному индексу. 

BOOL GetAce(PACL pAcl, DWORD dwAceIndex, LPVOID *pAce) 

Для получения определенного элемента АСЕ (их общее количество теперь известно) следует указать его индекс. рАсе указывает на структуру АСЕ, в которой имеется элемент под названием Header, содержащий, в свою очередь, элемент АсеТуре. Для проверки типа можно использовать значения ACCESS_ALLOWED_ACE и ACCESS DENIED АСЕ. 

Пример: чтение разрешений на доступ к файлу

Программа 15.4 представляет собой функцию ReadFilePermissions, которая используется программами 15.1 и 15.2. Эта программа методично использует описанные выше функции для извлечения нужной информации. Правильная работа этой программы зависит от того факта, что ACL были созданы с помощью программы 15.3. Функция включена в тот же исходный модуль, что и программа 15.3, поэтому соответствующие объявления не повторяются.

Программа 15.4. ReadFilePermissions: чтение атрибутов безопасности 

DWORD ReadFilePermissions(LPCTSTR lpFileName, LPTSTR UsrNm, LPTSTR GrpNm)

/* Возвращает разрешения на доступ к файлу в стиле UNIX. */

{

 PSECURITY_DESCRIPTOR pSD = NULL;

 DWORD LenNeeded, PBits, iAce;

 BOOL DaclF, AclDefF, OwnerDefF, GroupDefF;

 BYTE DAcl[ACL_SIZE];

 PACL pAcl = (PACL)&DAcl;

 ACL_SIZE_INFORMATION ASizeInfo;

 PACCESS_ALLOWED_ACE pAce;

 BYTE AType;

 HANDLE ProcHeap = GetProcessHeap();

 PSID pOwnerSid, pGroupSid;

 TCHAR RefDomain[2][DOM_SIZE];

 DWORD RefDomCnt[] = {DOM_SIZE, DOM_SIZE);

 DWORD AcctSize[] = {ACCT_NAME_SIZE, ACCT_NAME_SIZE};

 SID_NAME_USE sNamUse[] = {SidTypeUser, SidTypeGroup};

 /* Получить требуемый размер дескриптора безопасности. */

 GetFileSecurity(lpFileName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, pSD, 0, &LenNeeded);

 pSD = HeapAlloc(ProcHeap, HEAP_GENERATE_EXCEPTIONS, LenNeeded);

 GetFileSecurity(lpFileName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, pSD, LenNeeded, &LenNeeded);

 GetSecurityDescriptorDacl(pSD, &DaclF, &pAcl, &AclDefF);

 GetAclInformation(pAcl, &ASizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);

 PBits = 0; /* Вычислить разрешения на доступ на основе ACL. */

 for (iAce = 0; iAce < ASizeInfo.AceCount; iAce++) {

  GetAce(pAcl, iAce, &pAce);

  AType = pAce->Header.AceType;

  if (AType == ACCESS_ALLOWED_ACE_TYPE) PBits |= (0x1 << (8-iAce));

 } 

 /* Определить имя владельца и владеющей группы. */

 GetSecurityDescriptorOwner(pSD, &pOwnerSid, &OwnerDefF);

 GetSecurityDescriptorGroup(pSD, &pGroupSid, &GroupDefF);

 LookupAccountSid(NULL, pOwnerSid, UsrNm, &AcctSize[0], RefDomain[0], &RefDomCnt[0], &sNamUse[0]);

 LookupAccountSid(NULL, pGroupSid, GrpNm, &AcctSize[1], RefDomain[1], &RefDomCnt[1], &sNamUse[1]);

 return PBits;

Пример: изменение разрешений на доступ к файлу

Программа 15.5 является последней в нашем собрании функций, предназначенных для работы со средствами защиты файлов. Эта функция, ChangeFilePermissions, заменяет существующий дескриптор безопасности новым, сохраняя идентификаторы SID пользователя и группы, но создавая новый разграничительный список ACL.

Программа 15.5. ChangeFilePermissions: изменение атрибутов безопасности 

BOOL ChangeFilePermissions(DWORD fPm, LPCTSTR FNm, LPDWORD AceMsk)

/* Изменить разрешения на доступ к существующему файлу. Разрешения на доступ для группы остаются неизменными. */

{

 TCHAR UsrNm[ACCT_NAME_SIZE], GrpNm[ACCT_NAME_SIZE];

 LPSECURITY_ATTRIBUTES pSA;

 PSECURITY_DESCRIPTOR pSD = NULL;

 HANDLE hSecHeap;

 if (_taccess(FNm, 0) != 0) return FALSE;

 ReadFilePermissions(FNm, UsrNm, GrpNm);

 pSA = InitializeUnixSA(fPm, UsrNm, GrpNm, AceMsk, &hSecHeap);

 pSD = pSA->lpSecurityDescriptor;

 SetFileSecurity(FileName, DACL_SECURITY_INFORMATION, pSD);

 HeapDestroy(hSecHeap);

 return TRUE;

Комментарии по поводу разрешений на доступ к файлам

В процессе выполнения этих программ весьма интересно контролировать файловую систему через проводник Windows. Эта служебная программа не в состоянии интерпретировать АСЕ, разрешающие и запрещающие доступ, и не может отображать соответствующие разрешения. В Windows 4.0 проводник, сталкиваясь с такими АСЕ, будет генерировать исключения.

Вместе с тем, использование ACL, разрешающих и запрещающих доступ, необходимо для эмуляции семантики UNIX. Если этим пренебречь, то проводник Windows сможет обеспечить просмотр разрешений. Тогда, например, при коде защиты 0446 пользователь и члены группы смогут осуществлять запись в файл, поскольку это разрешено всем пользователям категории Everyone. В то же время, UNIX действует иначе; пользователю и членам группы эта операция будет запрещена.

Понаблюдайте также за тем, что происходит, когда вы пытаетесь создать защищенный файл на дискете или в другой FAT-системе, а также когда программа выполняется под управлением Windows 9x.