안녕하세요. 아주 오랜만에 글을 쓰게 되었습니다.
인생사 머가 그리 바쁜지, 일은 해도 해도 계속 생기네요 ㅠㅠ;;;

서비스스 뿐만 아니라, 시스템이나 관리자 권한으로 생성한 MMF나 혹은 PIPE를 유저 권한으로
읽거나 하려면 반드시라고 해도 좋을 만큼 권한에 관한 문제가 발생합니다.

   DWORD dwRes;
   PSID pEveryoneSID = NULL, pAdminSID = NULL;
   PACL pACL = NULL;
   PSECURITY_DESCRIPTOR pSD = NULL;
   EXPLICIT_ACCESS ea;
   SID_IDENTIFIER_AUTHORITY SIDAuthWorld SECURITY_WORLD_SID_AUTHORITY;
   SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;

  SECURITY_ATTRIBUTES sa;

   // Create a well-known SID for the Everyone group.
   if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                    SECURITY_WORLD_RID,
                    0, 0, 0, 0, 0, 0, 0,
                    &pEveryoneSID))
   {
       printf("AllocateAndInitializeSid Error %u\n", GetLastError());
       goto Cleanup;
   }

   // Initialize an EXPLICIT_ACCESS structure for an ACE.
   // The ACE will allow Everyone read access to the key.
   ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
   ea.grfAccessPermissions = GENERIC_READ;
   ea.grfAccessMode = SET_ACCESS;
   ea.grfInheritance= NO_INHERITANCE;
   ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
   ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
   ea.Trustee.ptstrName  = (LPTSTR) pEveryoneSID;

   // Create a SID for the BUILTIN\Administrators group.
   if(! AllocateAndInitializeSid(&SIDAuthNT, 2,
                    SECURITY_BUILTIN_DOMAIN_RID,
                    DOMAIN_ALIAS_RID_ADMINS,
                    0, 0, 0, 0, 0, 0,
                    &pAdminSID))
   {
       printf("AllocateAndInitializeSid Error %u\n", GetLastError());
       goto Cleanup;
   }


   // Create a new ACL that contains the new ACEs.
   dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
   if (ERROR_SUCCESS != dwRes)
   {
       printf("SetEntriesInAcl Error %u\n", GetLastError());
       goto Cleanup;
   }

   // Initialize a security descriptor.
   pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
   if (NULL == pSD)
   {
       printf("LocalAlloc Error %u\n", GetLastError());
       goto Cleanup;
   }

   if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
   {
       printf("InitializeSecurityDescriptor Error %u\n", GetLastError());
       goto Cleanup;
   }

   // Add the ACL to the security descriptor.
   if (!SetSecurityDescriptorDacl(pSD,
           TRUE,     // bDaclPresent flag
           pACL,
           FALSE))   // not a default DACL
   {
       printf("SetSecurityDescriptorDacl Error %u\n",
               GetLastError());
       goto Cleanup;
   }

   // Initialize a security attributes structure.
   sa.nLength = sizeof (SECURITY_ATTRIBUTES);
   sa.lpSecurityDescriptor = pSD;
   sa.bInheritHandle = FALSE;

위의 코드는 보안 속성을 생성하는 코드입니다. MSDN에 나온 샘플 일부를 추려서 만든 코드인데요.
큼지막하게 생긴 애들만 주의해 보시고, 수정해 주시면 원하시는 권한을 풀어줄 수 있습니다.

핸들 = ::CreateFileMapping(파일핸들, &sa, ... 나머지 인자들)...

위 코드의 설명은 Users 그룹에 포함된 사용자에게 Read Only 권한을 주도록 만든 것입니다.

프로세스간에 데이터를 공유할 때..
많이 사용되는 방법중에 하나가 공유 메모리(Memory Mapped File)를 사용하는 것이다.
일단 서버에서는 읽고/쓰기 모드로 열어서 내부에서 사용하고..
다른 한쪽 혹은 여러클라이언트 에서는 읽기 전용 모드로 열어서 사용하는 가장 간편한 방법을 사용해보자.
(사용하는 방식은 메모리를 액세스하는것과 동일하다..) 



위 그림처럼, 하나의 메모리 공간을 양쪽에서 액세스 할 수 있도록 제공해주는 점이 탁월한 장점이고,
또한 멀티 쓰레드? 멀티 코어? 와 상관없이...
서버는 읽기/쓰기 규칙을 지키고, 클라이언트는 읽기만 한다면 절대 공유 액세스 위반을 걱정할 필요가 없다.

우선 사용되는 API를 살펴보자. 아래에 해당하는 5개의 API만 사용해도 되며,
CreateFileMapping 함수의 첫번째(hFile) 인자와, 여섯번째(lpName) 인자만 주의하면 특별하게
인자에 신경쓰지 않아도 된다.

HANDLE WINAPI CreateFileMapping(
 __in          HANDLE hFile,
 __in          LPSECURITY_ATTRIBUTES lpAttributes,
 __in          DWORD flProtect,
 __in          DWORD dwMaximumSizeHigh,
 __in          DWORD dwMaximumSizeLow,
 __in          LPCTSTR lpName
);

※ HANDLE hFile
사용자가 이미 만들어 놓은 파일 핸들이나, INVALID_HANDLE_VALUE 를 전달할 수 있으며, INVALID_HANDLE_VALUE 이
전달되었을 경우는 시스템의 페이지 파일을 할당
해서 사용한다.
그러므로, 특별하게 큰 파일을 사용하는 경우가 아니라면 INVALID_HANDLE_VALUE 만으로도 충분하다.

※ LPCTSTR lpName
해당 공유 메모리를 확인하기 위한 고유한 이름을 나타낸다. 일반적인 클라이언트 OS 에서는 별 문제가 없겠지만
서버 OS에 Terminal Service 가 구동중이라면 Prefix 에 따라 그 특성이 달라진다.
모든 세션에서 접근할 수 있으려면 Global\이름 과 같이 Global\ 라는 Prefix를 붙혀주어야 한다.

HANDLE WINAPI OpenFileMapping(
 __in          DWORD dwDesiredAccess,
 __in          BOOL bInheritHandle,
 __in          LPCTSTR lpName
);

LPVOID WINAPI MapViewOfFile(
 __in          HANDLE hFileMappingObject,
 __in          DWORD dwDesiredAccess,
 __in          DWORD dwFileOffsetHigh,
 __in          DWORD dwFileOffsetLow,
 __in          SIZE_T dwNumberOfBytesToMap
);

BOOL WINAPI UnmapViewOfFile(
 __in          LPCVOID lpBaseAddress
);

BOOL WINAPI CloseHandle(
 __in          HANDLE hObject
);




※ 참고로, 서버프로그램이 종료되었을 경우, 클라이언트에서 메모리 맵드 파일의 현황만 가지고는 알수 없다는 단점이 있다.
즉, 서버가 죽어도 클라이언트가 살아서 데이터를 읽는데는 전혀 문제가 없기 때문에.. 이러한 부분은 별도로 확인해 주어야한다.

+ Recent posts