Partager via


Restauration d’objets supprimés

Windows Server 2003 inclut la fonctionnalité « restaurer les objets supprimés ».

Pour activer la restauration d’objets supprimés, au moins un contrôleur de domaine du domaine doit s’exécuter sur Windows Server 2003 ou une version ultérieure de Windows. Par défaut, seuls les administrateurs de domaine peuvent restaurer des objets supprimés, bien que cela puisse être délégué à d’autres personnes.

Les limitations suivantes s’appliquent à la restauration des objets supprimés :

  • Impossible de restaurer un objet lorsque la durée de vie de la pierre tombstone a expiré, car lorsque la durée de vie de la pierre tombstone a expiré, l’objet est définitivement supprimé.
  • Les objets qui existent à la racine du contexte d’affectation de noms, tels qu’une partition de domaine ou d’application, ne peuvent pas être restaurés.
  • Les objets de schéma ne peuvent pas être restaurés. Les objets de schéma ne doivent jamais être supprimés.
  • Il est possible de restaurer des conteneurs supprimés, mais la restauration des objets supprimés qui se trouvaient dans le conteneur avant la suppression est difficile, car l’arborescence sous le conteneur doit être reconstruite manuellement.

Autorisations requises pour restaurer un objet supprimé

Lorsqu’un objet est supprimé, le descripteur de sécurité de l’objet est conservé. Bien que le propriétaire soit identifiable à partir du descripteur de sécurité, pour des raisons de sécurité, seuls les administrateurs de domaine sont autorisés à restaurer des objets supprimés. Les administrateurs de domaine peuvent accorder l’autorisation de restaurer des objets supprimés à d’autres utilisateurs et groupes en accordant à l’utilisateur ou au groupe le droit d’accès de contrôle « Réanimater Tombstone ». Le droit d’accès de contrôle « Reanimate Tombstone » est accordé à la racine du contexte d’affectation de noms. Seuls les utilisateurs disposant d’une autorisation d’accès en lecture sur un objet et ses attributs sont autorisés à lire l’objet et les attributs accessibles après la suppression de l’objet.

Notes

L’octroi de cette autorisation à un utilisateur peut constituer un risque pour la sécurité, car cela peut permettre à l’utilisateur de restaurer un objet de compte qui a accès à des ressources auxquelles l’utilisateur n’aurait normalement pas accès. En restaurant un compte, l’utilisateur obtient essentiellement le contrôle de ce compte, car il doit définir le mot de passe initial sur le compte lors de la restauration du compte.

 

Pour restaurer complètement un objet supprimé, l’utilisateur doit :

  • Avoir, ou être membre d’un groupe qui a, le droit d’accès de contrôle « Réanimate Tombstone ».

  • Disposez d’un accès en écriture pour chaque attribut obligatoire qui nécessite une mise à jour.

  • Avoir un accès en écriture au nom unique relatif (RDN).

  • Disposez d’un accès en écriture à chaque attribut facultatif qui doit être mis à jour.

  • Disposez de droits de création d’enfants sur le conteneur de destination pour la classe d’objet de l’objet restauré.

    Notes

    L’attribut isDeleted n’est pas vérifié pendant l’opération de restauration. L’autorisation delete-child sur le conteneur « Objets supprimés » n’est pas vérifiée non plus.

     

Restauration d’un objet supprimé

Pour restaurer un objet supprimé, l’objet doit d’abord se trouver dans le conteneur Objets supprimés. Pour plus d’informations sur la récupération d’objets supprimés, consultez Récupération d’objets supprimés.

Lorsque l’objet a été localisé, les opérations suivantes doivent être effectuées en une seule opération LDAP. Cela nécessite l’utilisation de la fonction ldap_modify_ext_s avec le contrôle LDAP_SERVER_SHOW_DELETED_OID .

  • Supprimez la valeur de l’attribut isDeleted . La valeur de l’attribut isDeleted doit être supprimée, et non définie sur FALSE.
  • Remplacez le nom unique de l’objet afin qu’il soit déplacé vers un conteneur autre que le conteneur Objets supprimés. Il peut s’agir de n’importe quel conteneur qui peut normalement contenir l’objet . Le nom unique du conteneur précédent de l’objet se trouve dans l’attribut lastKnownParent de l’objet supprimé. L’attribut lastKnownParent est défini uniquement si l’objet a été supprimé sur un contrôleur de domaine Windows Server 2003. Par conséquent, il est possible que le contenu de l’attribut lastKnownParent soit inexact.
  • Restaurez les attributs obligatoires pour l’objet qui ont été effacés lors de la suppression.

Notes

L’attribut objectCategory peut également être défini lorsque l’objet est restauré, mais n’est pas obligatoire. Si aucune valeur objectCategory n’est spécifiée, l’objetCategory par défaut pour objectClass de l’objet est utilisé.

 

Une fois l’objet restauré, il est accessible tel qu’il était avant sa suppression. À ce stade, tous les attributs facultatifs importants doivent être restaurés. Toutes les références à l’objet à partir d’autres objets du répertoire doivent également être restaurées.

Par mesure de sécurité, les objets utilisateur sont désactivés lorsqu’ils sont restaurés. Les objets utilisateur doivent être activés après la restauration des attributs facultatifs pour permettre l’utilisation de l’objet utilisateur.

Pour plus d’informations et un exemple de code montrant comment restaurer un objet supprimé, consultez la fonction RestoreDeletedObject ci-dessous.

RestoreDeletedObject

L’exemple de code C++ suivant montre comment restaurer un objet supprimé.

//***************************************************************************
//
//  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;
}