Share via


삭제된 개체 복원

Windows Server 2003에는 "삭제된 개체 복원" 기능이 포함되어 있습니다.

삭제된 개체 복원을 사용하도록 설정하려면 도메인에 있는 하나 이상의 도메인 컨트롤러가 Windows Server 2003 이상 버전의 Windows에서 실행되어야 합니다. 기본적으로 도메인 관리자만 삭제된 개체를 복원할 수 있지만 다른 사용자에게 위임할 수 있습니다.

삭제된 개체 복원에는 다음과 같은 제한 사항이 적용됩니다.

  • 삭제 표시 수명이 만료되면 개체가 영구적으로 삭제되므로 개체의 삭제 표시 수명이 만료된 경우 개체를 복원할 수 없습니다.
  • 도메인 또는 애플리케이션 파티션과 같은 명명 컨텍스트의 루트에 있는 개체는 복원할 수 없습니다.
  • 스키마 개체는 복원할 수 없습니다. 스키마 개체는 삭제해서는 안 됩니다.
  • 삭제된 컨테이너를 복원할 수 있지만 삭제하기 전에 컨테이너에 있던 삭제된 개체의 복원은 컨테이너 아래의 트리 구조를 수동으로 재구성해야 하기 때문에 어렵습니다.

삭제된 개체를 복원하는 데 필요한 권한

개체가 삭제되면 개체 보안 설명자가 유지됩니다. 소유자는 보안 설명자에서 식별할 수 있지만 보안상의 이유로 도메인 관리자만 삭제된 개체를 복원할 수 있습니다. 도메인 관리자는 사용자에게 "삭제 표시 다시 애니메이션" 제어 권한을 부여하여 삭제 개체를 다른 사용자 및 그룹에 복원할 수 있는 권한을 부여할 수 있습니다. "삭제 표시 다시 애니메이션" 컨트롤 액세스 권한은 명명 컨텍스트 루트에 부여됩니다. 개체 및 해당 특성에 대한 읽기 액세스 권한이 있는 사용자만 개체를 삭제한 후 개체 및 액세스 가능한 특성을 읽을 수 있습니다.

참고

사용자에게 이 권한을 부여하는 것은 사용자가 일반적으로 액세스할 수 없는 리소스에 대한 액세스 권한이 있는 계정 개체를 복원하도록 허용할 수 있기 때문에 보안 위험이 될 수 있습니다. 계정을 복원하면 계정이 복원될 때 사용자가 계정의 초기 암호를 설정해야 하므로 사용자는 기본적으로 이 계정을 제어할 수 있습니다.

 

삭제된 개체를 완전히 복원하려면 사용자는 다음을 수행해야 합니다.

  • "삭제 표시 다시 애니메이션" 컨트롤 액세스 권한이 있는 그룹의 구성원이거나 구성원이어야 합니다.

  • 업데이트가 필요한 각 필수 특성에 대한 쓰기 액세스 권한이 있습니다.

  • RDN(상대 고유 이름)에 대한 쓰기 권한이 있습니다.

  • 업데이트해야 하는 각 선택적 특성에 대한 쓰기 액세스 권한이 있습니다.

  • 복원된 개체의 개체 클래스에 대한 대상 컨테이너에 대한 자식 만들기 권한이 있습니다.

    참고

    isDeleted 특성은 복원 작업 중에 확인되지 않습니다. "삭제된 개체" 컨테이너에 대한 삭제-자식 권한도 확인되지 않습니다.

     

삭제된 개체 복원

삭제된 개체를 복원하려면 먼저 개체가 Deleted Objects 컨테이너에 있어야 합니다. 삭제된 개체를 검색하는 방법에 대한 자세한 내용은 삭제 된 개체 검색을 참조하세요.

개체가 있는 경우 단일 LDAP 작업에서 다음 작업을 완료해야 합니다. 이렇게 하려면 LDAP_SERVER_SHOW_DELETED_OID 컨트롤과 함께 ldap_modify_ext_s 함수를 사용해야 합니다.

  • isDeleted 특성 값을 제거합니다. isDeleted 특성 값은 FALSE로 설정하지 않고 제거해야 합니다.
  • 개체가 지운 개체 컨테이너가 아닌 다른 컨테이너로 이동되도록 개체의 고유 이름을 바꿉 있습니다. 일반적으로 개체를 포함할 수 있는 컨테이너일 수 있습니다. 개체의 이전 컨테이너의 고유 이름은 삭제된 개체의 lastKnownParent 특성에서 찾을 수 있습니다. lastKnownParent 특성은 Windows Server 2003 도메인 컨트롤러에서 개체가 삭제된 경우에만 설정됩니다. 따라서 lastKnownParent 특성의 내용이 부정확할 수 있습니다.
  • 삭제하는 동안 지워진 개체에 대한 필수 특성을 복원합니다.

참고

개체가 복원될 때 objectCategory 특성을 설정할 수도 있지만 필수는 아닙니다. objectCategory 값을 지정하지 않으면 개체의 objectClass에 대한 기본 objectCategory가 사용됩니다.

 

개체가 복원된 후 삭제되기 전과 마찬가지로 액세스할 수 있습니다. 이 시점에서 중요한 모든 선택적 특성을 복원해야 합니다. 디렉터리의 다른 개체에서 개체에 대한 참조도 복원해야 합니다.

보안 조치로 사용자 개체는 복원될 때 사용하지 않도록 설정됩니다. 사용자 개체를 사용할 수 있도록 선택적 특성을 복원한 후 사용자 개체를 사용하도록 설정해야 합니다.

삭제된 개체를 복원하는 방법을 보여 주는 자세한 내용과 코드 예제는 아래 RestoreDeletedObject 함수를 참조하세요.

RestoreDeletedObject

다음 C++ 코드 예제에서는 삭제된 개체를 복원하는 방법을 보여줍니다.

//***************************************************************************
//
//  RestoreDeletedObject()
//
//  Restores a deleted object. 
//
//  pwszDeletedDN - Contains the fully qualified distinguished name of the 
//  deleted object.
//
//  pwszDestContainerDN - Contains the fully qualified distinguished name of 
//  the folder that the deleted object should be moved to.
//
//  Returns S_OK if successful or an HRESULT or LDAP error code otherwise.
//
//***************************************************************************

HRESULT RestoreDeletedObject(LPCWSTR pwszDeletedDN, LPCWSTR pwszDestContainerDN)
{
    if((NULL == pwszDeletedDN) || (NULL == pwszDestContainerDN))
    {
        return E_POINTER;
    }
    
    HRESULT hr = E_FAIL;

    // Build the new distinguished name.
    LPWSTR pwszNewDN = new WCHAR[lstrlenW(pwszDeletedDN) + lstrlenW(pwszDestContainerDN) + 1];
    if(pwszNewDN)
    {
        wcscpy_s(pwszNewDN, pwszDeletedDN);

        // Search for the first 0x0A character. This is the delimiter in the deleted object name.
        LPWSTR pwszChar;
        for(pwszChar = pwszNewDN; *pwszChar; pwszChar = CharNextW(pwszChar))
        {
            if(('\\' == *pwszChar) && ('0' == *(pwszChar + 1)) && ('A' == *(pwszChar + 2)))
            {
                break;
            }
            
        }

        if(0 != *pwszChar)
        {
            // Truncate the name string at the delimiter.
            *pwszChar = 0;

            // Add the last known parent DN to complete the DN.
            wcscat_s(pwszNewDN, L",");
            wcscat_s(pwszNewDN, pwszDestContainerDN);

            PLDAP ld;

            // Initialize LDAP.
            ld = ldap_init(NULL, LDAP_PORT);
            if(NULL != ld) 
            {
                ULONG ulRC;
                ULONG version = LDAP_VERSION3;

                // Set the LDAP version.
                ulRC = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
                if(LDAP_SUCCESS == ulRC)
                {
                    // Establish a connection with the server.
                    ulRC = ldap_connect(ld, NULL);
                    if(LDAP_SUCCESS == ulRC)
                    {                    
                        // Bind to the LDAP server.
                        ulRC = ldap_bind_s(ld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
                        if(LDAP_SUCCESS == ulRC)
                        {
                            // Setup the new values.
                            LPWSTR rgNewVals[] = {pwszNewDN, NULL};

                            /*
                            Remove the isDeleted attribute. This cannot be set 
                            to FALSE or the restore operation will not work.
                            */
                            LDAPModW modIsDeleted = { LDAP_MOD_DELETE, L"isDeleted", NULL };

                            /*
                            Set the new DN, in effect, moving the deleted 
                            object to where it resided before the deletion.
                            */
                            LDAPModW modDN = { LDAP_MOD_REPLACE, L"distinguishedName", rgNewVals };
                            
                            // Initialize the LDAPMod structure.
                            PLDAPModW ldapMods[] = 
                            {
                                &modIsDeleted,
                                &modDN,
                                NULL
                            };

                            /*
                            Use the LDAP_SERVER_SHOW_DELETED_OID control to 
                            modify deleted objects.
                            */
                            LDAPControlW showDeletedControl;
                            showDeletedControl.ldctl_oid = LDAP_SERVER_SHOW_DELETED_OID_W;
                            showDeletedControl.ldctl_value.bv_len = 0;
                            showDeletedControl.ldctl_value.bv_val = NULL;
                            showDeletedControl.ldctl_iscritical = TRUE;

                            // Initialzie the LDAPControl structure
                            PLDAPControlW ldapControls[] = { &showDeletedControl, NULL };

                            /*
                            Modify the specified attributes. This must performed 
                            in one step, which is why the LDAP APIs must be used 
                            to restore a deleted object.
                            */
                            ulRC = ldap_modify_ext_sW(ld, (PWCHAR)pwszDeletedDN, ldapMods, ldapControls, NULL);
                            if(LDAP_SUCCESS == ulRC)
                            {
                                hr = S_OK;
                            }
                            else if(LDAP_ALREADY_EXISTS == ulRC)
                            {
                                /*
                                An object already exists with the specified name 
                                in the specified target container. At this point, 
                                a new name must be selected.
                                */
                            }
                        }
                    }
                }

                if(LDAP_SUCCESS != ulRC)
                {
                    hr = ulRC;
                    
                    OutputDebugString(ldap_err2string(ulRC));
                }

                // Release the LDAP session.
                ldap_unbind(ld);
            }
        }
        else
        {
            /*
            If the end of the string is reached before the delimiter is found, just 
            end and fail.
            */
            hr = E_INVALIDARG;
        }
    
        delete pwszNewDN;
    }
    else
    {
        hr = E_OUTOFMEMORY;
    }

    return hr;
}