Поделиться через


Восстановление удаленных объектов

Windows Server 2003 включает функцию восстановления удаленных объектов.

Чтобы включить восстановление удаленных объектов, необходимо запустить по крайней мере один контроллер домена в домене в Windows Server 2003 или более поздней версии Windows. По умолчанию только администраторы домена могут восстановить удаленные объекты, хотя это можно делегировать другим пользователям.

Следующие ограничения применяются к восстановлению удаленных объектов:

  • Объект не может быть восстановлен, если срок существования могилы для объекта истек, так как время существования могилы истекло, объект окончательно удаляется.
  • Объекты, существующие в корне контекста именования, такие как домен или раздел приложения, не могут быть восстановлены.
  • Объекты схемы не могут быть восстановлены. Объекты схемы никогда не следует удалять.
  • Можно восстановить удаленные контейнеры, но восстановление удаленных объектов, которые находились в контейнере до удаления, сложно, так как структура дерева в контейнере должна быть восстановлена вручную.

Разрешения, необходимые для восстановления удаленного объекта

При удалении объекта дескриптор безопасности объекта сохраняется. Хотя владелец идентифицируется из дескриптора безопасности, только администраторы домена могут восстанавливать удаленные объекты. Администраторы домена могут предоставить разрешение на восстановление объектов для других пользователей и групп, предоставив пользователю или группе право управления доступом "Reanimate Tombstone". Права доступа "Reanimate Tombstone" предоставляются в корневом каталоге контекста именования. Только пользователи, имеющие разрешение на доступ на чтение объекта и его атрибуты, могут читать объект и доступные атрибуты после удаления объекта.

Примечание.

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

 

Чтобы полностью восстановить удаленный объект, пользователь должен:

  • Есть или быть членом группы, которая имеет, "Reanimate Tombstone" управляет доступом.

  • Доступ на запись для каждого обязательного атрибута, требующего обновления.

  • Иметь доступ на запись к относительно различаемого имени (RDN).

  • Иметь доступ на запись к каждому необязательному атрибуту, который необходимо обновить.

  • Имеют права на создание дочерних объектов в целевом контейнере для класса объектов восстановленного объекта.

    Примечание.

    Атрибут isDeleted не проверяется во время операции восстановления. Ни удаляемые дочерние разрешения на контейнер "Удаленные объекты" не будут проверены.

     

Восстановление удаленного объекта

Чтобы восстановить удаленный объект, объект должен сначала находиться в контейнере удаленных объектов. Дополнительные сведения о получении удаленных объектов см. в разделе "Извлечение удаленных объектов".

При обнаружении объекта в рамках одной операции LDAP необходимо выполнить следующие операции. Для этого требуется использование функции ldap_modify_ext_s с элементом управления LDAP_SERVER_SHOW_DELETED_OID.

  • Удалите значение атрибута isDeleted . Значение атрибута isDeleted должно быть удалено, а не задано значение FALSE.
  • Замените различающееся имя объекта таким образом, чтобы он перемещался в контейнер, отличный от контейнера удаленных объектов. Это может быть любой контейнер, который обычно может содержать объект. Различающееся имя предыдущего контейнера объекта можно найти в атрибуте lastKnownParent удаленного объекта. Атрибут lastKnownParent задается только в том случае, если объект был удален на контроллере домена Windows Server 2003. Таким образом, возможно, содержимое атрибута lastKnownParent является неточным.
  • Восстановите обязательные атрибуты для объекта, который был очищен во время удаления.

Примечание.

Атрибут objectCategory также можно задать при восстановлении объекта, но не требуется. Если значение objectCategory не указано, используется объект по умолчанию objectCategory для объекта ObjectClass.

 

После восстановления объекта его можно получить по мере его удаления. На этом этапе необходимо восстановить все необязательные атрибуты, которые важны. Все ссылки на объект из других объектов в каталоге также должны быть восстановлены.

В качестве меры безопасности объекты пользователей отключаются при восстановлении. Пользовательские объекты должны быть включены после восстановления необязательных атрибутов, чтобы разрешить использовать объект пользователя.

Дополнительные сведения и пример кода, демонстрирующий восстановление удаленного объекта, см. в функции 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;
}