Share via


削除されたオブジェクトの復元

Windows Server 2003 には、"削除されたオブジェクトの復元" 機能が含まれています。

削除されたオブジェクトの復元を有効にするには、少なくとも 1 つの doメイン コントローラーを Windows Server 2003 以降のバージョンの Windows でメイン実行している必要があります。 既定では、削除されたオブジェクトはメイン管理者のみが復元できますが、これは他のユーザーに委任できます。

削除されたオブジェクトの復元には、次の制限事項が適用されます。

  • オブジェクトの廃棄の有効期間が経過すると、オブジェクトは完全に削除されるため、オブジェクトの廃棄の有効期間の有効期限が切れた場合は、オブジェクトを復元できません。
  • doメイン やアプリケーション パーティションなど、名前付けコンテキストのルートに存在するオブジェクトは復元できません。
  • スキーマ オブジェクトを復元できません。 スキーマ オブジェクトは削除しないでください。
  • 削除されたコンテナーを復元することはできますが、コンテナーの下のツリー構造を手動で再構築する必要があるため、削除前にコンテナー内にあった削除済みオブジェクトの復元は困難です。

削除されたオブジェクトを復元するために必要なアクセス許可

オブジェクトが削除されると、オブジェクトセキュリティ記述子は保持されます。 所有者はセキュリティ記述子から識別できますが、セキュリティ上の理由から、削除されたオブジェクトの復元は管理者のみが許可メイン。 Doメイン管理者は、ユーザーまたはグループに "Reanimate Tombstone" 制御アクセス権を付与することで、削除オブジェクトを他のユーザーやグループに復元する権限を付与できます。 "Reanimate Tombstone" コントロール アクセス権は、名前付けコンテキスト ルートで付与されます。 オブジェクトとその属性に対する読み取りアクセス許可を持つユーザーのみが、オブジェクトの削除後にオブジェクトとアクセス可能な属性の読み取りを許可されます。

Note

ユーザーにこのアクセス許可を付与すると、ユーザーが通常アクセス権を持たないリソースにアクセスできるアカウント オブジェクトを復元できる可能性があるため、セキュリティ上のリスクが発生する可能性があります。 アカウントを復元することで、ユーザーは基本的に、アカウントの復元時にアカウントの初期パスワードを設定する必要があるため、このアカウントを制御できます。

 

削除されたオブジェクトを完全に復元するには、ユーザーは次の操作を行う必要があります。

  • "Reanimate Tombstone" コントロール アクセス権を持っている、またはグループのメンバーである。

  • 更新が必要な必須属性ごとに書き込みアクセス権を持つ。

  • 相対識別名 (RDN) への書き込みアクセス権を持っている。

  • 更新する必要がある各省略可能な属性への書き込みアクセス権を持っている。

  • 復元されたオブジェクトのオブジェクト クラスに対するコピー先コンテナーに対する子作成権限を持つ。

    Note

    isDeleted 属性は、復元操作中は検証されません。 "削除されたオブジェクト" コンテナーに対する削除子アクセス許可も検証されません。

     

削除されたオブジェクトの復元

削除されたオブジェクトを復元するには、まずオブジェクトが Deleted Objects コンテナーに配置されている必要があります。 削除されたオブジェクトの取得の詳細については、「削除されたオブジェクトの取得」を参照してください

オブジェクトが配置されている場合は、1 回の LDAP 操作で次の操作を完了する必要があります。 これには、LDAP_Standard EditionRVER_SHOW_DELETED_OID コントロールでldap_modify_ext_s関数を使用する必要があります。

  • isDeleted 属性値を削除します。 isDeleted 属性値は、FAL Standard Edition に設定せず、削除する必要があります。
  • オブジェクトの識別名を置き換えて、削除済みオブジェクト コンテナー以外のコンテナーに移動します。 通常はオブジェクトを格納できる任意のコンテナーを指定できます。 オブジェクトの前のコンテナーの識別名は、削除されたオブジェクトの lastKnownParent 属性にあります。 lastKnownParent 属性は、オブジェクトが Windows Server 2003 doメイン コントローラーで削除された場合にのみ設定されます。 したがって、lastKnownParent 属性の内容が不正確である可能性があります。
  • 削除中にクリアされたオブジェクトの必須属性を復元します。

Note

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