윈도우 접근 제어 관련
보안 디스크립터 : 객체에 관한 보안 정보가 저장되는 곳. (접근 허가/금지 등..)
소유자 SID, 프라이머리 그룹의 SID, ACL(DACL + SACL)를 갖는 구조
ACL (Access Control List) :
ACE 구조체 배열로 DACL과 SACL를 갖음
SACL(System Access Control List) :
시스템 접근 제어 리스트. 객체에 대한 접근 로그를 얻거나 접근시 관리자에게 통지하는 기능을 설정
DACL(Discretionary Access Control List) :
임의 접근 제어 리스트. 읽기, 쓰기 객체에 대한 접근 허가/금지를 트러스티(SID)마다 설정
DACL은 ACL 헤더와 ACE 리스트를 갖는데 각 ACE가 객체에 대해 트러스티에 의한
접근 허가/금지를 명시적으로 정의하는 기본 단위이며
전체 DACL이 대상 객체의 접근 권한 설정 전체를 기술함.
즉, DACL의 ACE는 다음 3가지 정보를 포함함.
1)접근 허가/금지의 플래그, 2)보호하는 접근 권한 종류를 나타내는 마스크 플래그, 3) 제어 대상의 트러스티 SID
SECURITY_DESCRIPTOR 구조체
: 보안 디스크립터의 실체인 구조체
SECURITY_ATTRIBUTES 구조체
: 보안 가능 객체 생성시 사용되며 SECURITY_DESCRIPTOR 구조체의 포인터를 갖음
User ID, Group ID에 대한 SID 및 정보 출력 샘플
#include <windows.h>
#include <tchar.h>
#include <sddl.h>
#include <iostream>
struct SIDTYPENAME
{
SID_NAME_USE type;
const TCHAR* name;
} nametbl[] = {
{SidTypeUser, _T("USER")},
{SidTypeGroup, _T("GROUP")},
{SidTypeDomain, _T("DOMAIN")},
{SidTypeAlias, _T("ALIAS")},
{SidTypeWellKnownGroup, _T("WELL KNOWN GROUP")},
{SidTypeDeletedAccount, _T("DELETED ACCOUNT")},
{SidTypeInvalid, _T("INVALID")},
{SidTypeComputer, _T("COMPUTER")},
{SidTypeUnknown, NULL}
};
void printSIDType(SID_NAME_USE use)
{
SIDTYPENAME* ptr = nametbl;
while (ptr->name != NULL)
{
if (use == ptr->type)
{
_tprintf(ptr->name);
return;
}
ptr++;
}
_tprintf(_T("UNKNOWN"));
}
int main(void)
{
setlocale(LC_ALL, "");
TCHAR sidBuf[512];
SID *pSid = (SID*)sidBuf;
DWORD sidLen = sizeof(sidBuf);
TCHAR domBuf[256];
LPTSTR domName = (LPTSTR)domBuf;
DWORD domLen = sizeof(domBuf);
SID_NAME_USE use;
//LookupAccountName : ID로 SID를 얻음
//LookupAccountSid : SID로 ID를 얻음
//Guest 유저에 대한 SID 획득
if (LookupAccountName(NULL, _T("Guest"), pSid, &sidLen, domName, &domLen, &use))
{
LPTSTR sidString;
//ConvertSidToStringSid : 문자열 SID 획득
if (ConvertSidToStringSid(pSid, &sidString))
{
_tprintf(_T("SID : %s\n"), sidString);
_tprintf(_T("Domain : %s\n"), domName);
_tprintf(_T("Type : ")); printSIDType(use);
_tprintf(_T("\n"));
LocalFree(sidString);
}
}
return 0;
}
프로세스 접근 토큰에 설정된 기본 DACL 출력 프로그램 샘플
#include <windows.h>
#include <tchar.h>
#include <sddl.h>
#include <iostream>
struct SIDTYPENAME
{
SID_NAME_USE type;
const TCHAR* name;
} nametbl[] = {
{SidTypeUser, _T("USER")},
{SidTypeGroup, _T("GROUP")},
{SidTypeDomain, _T("DOMAIN")},
{SidTypeAlias, _T("ALIAS")},
{SidTypeWellKnownGroup, _T("WELL KNOWN GROUP")},
{SidTypeDeletedAccount, _T("DELETED ACCOUNT")},
{SidTypeInvalid, _T("INVALID")},
{SidTypeComputer, _T("COMPUTER")},
{SidTypeUnknown, NULL}
};
void printSIDType( SID_NAME_USE use)
{
SIDTYPENAME *ptr = nametbl;
while (ptr->name != NULL)
{
if (use == ptr->type)
{
_tprintf(ptr->name);
return;
}
ptr++;
}
_tprintf(_T("UNKNOWN"));
}
void printAccessMask(DWORD mask)
{
//접근 권한 종류
if( mask & GENERIC_READ) _tprintf(_T("GENERIC_READ "));
if( mask & GENERIC_WRITE) _tprintf(_T("GENERIC_WRITE "));
if( mask & GENERIC_EXECUTE) _tprintf(_T("GENERIC_EXECUTE "));
if( mask & GENERIC_ALL) _tprintf(_T("GENERIC_ALL "));
if( mask & SYNCHRONIZE) _tprintf(_T("SYNCHRONIZE "));
if( mask & WRITE_OWNER) _tprintf(_T("WRITE_OWNER "));
if( mask & WRITE_DAC) _tprintf(_T("WRITE_DAC "));
if( mask & READ_CONTROL) _tprintf(_T("READ_CONTROL "));
if( mask & DELETE) _tprintf(_T("DELETE "));
}
int main( void)
{
_tprintf(_T("--- Current Default DACL ---\n"));
HANDLE hToken;
//현재 프로세스(GetCurrentProcess())의 접근 토큰(access token)을 열어 토큰 핸들(hToken)을 얻음
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
{
//간단하게 하기 위해 너무 긴 DACL은 미 처리
TCHAR buffer[1024];
TOKEN_DEFAULT_DACL* pDefdacl = (TOKEN_DEFAULT_DACL*)buffer; //DACL(discretionary access control list)
DWORD retlen = 0;
//토큰 핸들(hToken)을 통해 특정 타입의 접근 토큰(access token) 정보를 얻음.
//TokenDefaultDacl을 주어 DACL 전체를 얻어 pDefdacl에 담음
if (GetTokenInformation(hToken, TokenDefaultDacl, pDefdacl, sizeof(buffer), &retlen))
{
if(pDefdacl->DefaultDacl != NULL) //DACL 획득에 성공했다면
{
int count = pDefdacl->DefaultDacl->AceCount; //DACL 안의 ACE 갯수를 얻음
_tprintf(_T("Number of ACEs: %d\n\n"), count);
ACE_HEADER *pHdr = (ACE_HEADER *)&pDefdacl->DefaultDacl[1]; //DACL안의 ACL 헤더를 얻음
for ( int i=0; i<count; i++) //DACL안의 ACE 갯수 만큼 LOOP
{
//ACE가 접근 허가 또는 금지를 사용할 수 있다면
if( pHdr->AceType == ACCESS_ALLOWED_ACE_TYPE || pHdr->AceType == ACCESS_DENIED_ACE_TYPE)
{
if( pHdr->AceType == ACCESS_ALLOWED_ACE_TYPE)
_tprintf(_T("ACE type: Allowed ACE \n")); //접근 허가 ACE
else
_tprintf(_T("ACE type: Denied ACE \n")); //접근 금지 ACE
ACCESS_ALLOWED_ACE *pHdr2 = (ACCESS_ALLOWED_ACE *)pHdr;
//접근 권한 마스크 플래그의 의미 출력
_tprintf(_T("Access mask: ")); printAccessMask(pHdr2->Mask); _tprintf(_T("\n"));
//SID를 문자열로 출력
LPTSTR sidstr;
if(ConvertSidToStringSid((PSID)&pHdr2->SidStart, &sidstr))
{
_tprintf(_T("SID: %s\n"), sidstr);
LocalFree( sidstr);
}
//SID에 대한 이름, 도메인, SID 타입 출력
TCHAR name[128], domain[128];
DWORD namelen = sizeof(name);
DWORD domlen = sizeof(domain);
SID_NAME_USE use;
if (LookupAccountSid(NULL, (PSID)&pHdr2->SidStart, name, &namelen, domain, &domlen, &use))
{
_tprintf(_T("name : %s\n"), name);
_tprintf(_T("domain: %s\n"), domain);
_tprintf(_T("type : ")); printSIDType(use); _tprintf(_T("\n"));
}
else
{
_tprintf(_T("Cannot print a name and a type.\n"));
}
}
else //접근이나 금지 ACE가 아닌 경우
{
_tprintf(_T("Other types of ACE\n"));
}
_tprintf(_T("\n"));
//다음 ACE를 가르키도록 주소 이동
pHdr = (ACE_HEADER *)((char *)pHdr + pHdr->AceSize);
}
} else { //DACL이 아닌 경우
_tprintf(_T("there's no default dacl.\n"));
}
} else {
_tprintf(_T("GetTokenInformation() error: %d.\n"), GetLastError());
}
CloseHandle(hToken);
} else{
_tprintf(_T("OpenProcessToken() error: %d.\n"), GetLastError());
}
return 0;
}
명시적 제어 설정 부분 예제 코드
/*yamoe 사용자에 대해서만 읽기 접근 허가*/
//SECURITY_DESCRIPTOR 구조체 초기화
SECURITY_DESCRIPTO sdesc;
InitializeSecurityDescriptor(&sdesc, SECURITY_DESCRIPTOR_REVISION);
//ACE 엔트리 생성
EXPLICIT_ACCESS ea;
ea.grfAccessPermissions = GENERIC_ALL;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = 0;
ea.Trustee.ptstrName = "yamoe"
BuildTrusteeWithName(&ea.Trustee, ea.Trustee.ptstrName);
//하나의 ACE를 포함한 ACL 신규 생성
PACL *pAcl;
SetEntriesInAcl(1, $ea, NULL, &pAcl);
//ACL을 보안 디스크립터에 설정
SetSecurityDescriptorDacl(&sdesc, TRUE, pAcl, TRUE);
/*빈 DACL 설정 : 완전 접근 금지*/
//SECURITY_DESCRIPTOR 구조체 초기화
SECURITY_DESCRIPTO sdesc;
InitializeSecurityDescriptor(&sdesc, SECURITY_DESCRIPTOR_REVISION);
//빈 ACL 생성
ACL acl;
InitializeAcl(&acl, sizeof(acl), ACL_REVISION);
//ACL을 보안 디스크립터에 설정
SetSecurityDescriptorDacl(&sdesc, TRUE, &acl, TRUE);
/*NULL DACL 설정 : 완전 접근 허가*/
//SECURITY_DESCRIPTOR 구조체 초기화
SECURITY_DESCRIPTO sdesc;
InitializeSecurityDescriptor(&sdesc, SECURITY_DESCRIPTOR_REVISION);
//ACL 포인터에 NULL 지정
//두번째 인자에 TRUE를 넘기는 것이 핵심 사항
SetSecurityDescriptorDacl(&sdesc, TRUE, NULL, TRUE);
프로그램 설치할때 모든 사용자 혹은 특정 사용자에게만 실행 권한 줄때 쓰이는 건가.. 실제 사용 예는 무엇인가?
'C++' 카테고리의 다른 글
MFC 기초 정리 (0) | 2011.01.21 |
---|---|
파일 비동기 IO 조작 (Async IO) (0) | 2011.01.18 |
SEH (Structured Exception Handling) 예외처리 (0) | 2011.01.12 |
윈도우 GUI에서 콘솔(console) 띄우기 (0) | 2011.01.11 |
CRITICAL_SECTION을 사용한 Lock 클래스 예제 (0) | 2011.01.07 |
Design Patterns (디자인 패턴) (0) | 2011.01.06 |
POSA (Pattern-Oriented Software Architecture) (0) | 2011.01.03 |
ACE (ADAPTIVE Communication Environment) (0) | 2011.01.03 |