AD RMS Protecting A document Programmatically

Created By Saddam Abu Ghaida and Nicolai Tufar

Hello there,

NOTE : don’t think microsoft will mind if i put some of its code since it is available in Windows SDK samples under ADRMS folder for free, because i used some pieces of code. instead of writing it from scratch, which most of the time i needed to alter them 🙂 . So Thank you Microsoft for the helpful Sample Code and no thank you for the documentation because it is weak and crappy, no offence 

Here you can Download the whole project

I just finished developing a DLL which works as proxy between AD RMS “Active directory Rights management System ” and anybody who wishes to use this DLL to protect office documents programmatically. it took me some time to finalized it because of lack of documentation, and discovered some bugs in Microsoft examples which comes with the windows SDK 7.1.

This DLL will be used Directly from any managed Code or used indirectly through Web Services.

AD RMS is in short a web services which you use to protect unprotect office documents, the client side comes preinstalled in windows 7. Communication with RMS could be done through HTTP which is not recommended or HTTPS. RMS are right driven per user, so it defines who can do what when it comes to office document such as read, edit, print, expiration, forward, reply, … etc. The nice thing about it that you could define your own custom rights if the application that you are doing could understand that right. RMS has been made for office documents but it could cater for all type of documents with programing skills with a lot of cigarettes and coffee :). you can write almost everything in .Net but you need to externalize the functions, or you could write it in C

There is two ways of installing AD RMS. The first one is Production and the second is Pre Production which i use and you should use for development, the only major difference between those two types is the certificates which signs the code, and some registry keys should be changed. but from functionality point of view they are the same.

So when you want to develop anything for RMS you need to do it in Preproduction environment and then give the code for microsoft for signing it with production keys, so that office could understand the document, and being able to protect and unprotect it, because office is signed with production keys :), so to test your app you need to resign Office with preproduction keys. Sounds funny isn’t it :). To test the DLL i wrote the DLL of course, and wrote a client application in C# to use the DLL which was funny because i never had a pleasure of doing such a complicated and challenging application such as this.

What i will share with you today is the core functionality of protecting office documents . The code are pretty documented so i don’t need to go through every function description, you can find the description easily on microsoft website just search for RMS SDK Functions, and you are good to go.

RMS usually protects the documents using XrML templates  which holds the what rights and for whom. Back to the code funny part which is the code 🙂

the DLL has 2 functions only InitParam and ProtectDocument as for init param, it sets the global variables which they will be used in the whole application, which was more convenient for me, and it looks like the following 

DLLAPI void InitParam(PWSTR unprotectedDocFilePath,
        PWSTR protectedDocFilePath,
        PWSTR templateFilePath,
        PWSTR userID, 
        PWSTR manifestFilePath,
        PWSTR UsersRights)
    {
        pwsPlainFile            = unprotectedDocFilePath;
        wcsRmhFilePath            = protectedDocFilePath;
        pwTemplatePath            = templateFilePath;
        pwUsersRightsList        = UsersRights;
        pwUsersRightsListTmp    = UsersRights;
        wszManifestFileName        = manifestFilePath; 
        wszUserId                = userID;

        // if UsersRights has been provided then the protection will be based on this instead of template 
        if (UsersRights != NULL)
        {
            wprintf(L"\nProtect by Users Rights\n");
            ProtectByTemplate = false;
        }
        else 
        {
            wprintf(L"\nProtect by Template\n");
            ProtectByTemplate = true;
        }

        wprintf(L"Unprotected File Path = %s\n"   ,    pwsPlainFile);
        wprintf(L"Protected File Path = %s\n"     ,    wcsRmhFilePath);
        wprintf(L"Template File Path = %s\n"     ,    pwTemplatePath);
        wprintf(L"User name = %s\n"           ,    wszUserId);
        wprintf(L"Manifest file path = %s\n"       ,    wszManifestFileName);
        wprintf(L"UsersRights = %s\n"          ,    pwUsersRightsList);
    }

I Did the print statement for clarification and it is not a part of the code, here i need to describe what is the manifest file. Manifest file is XML file which describes the application and addresses the dependencies. You generate the manifest file using genmanifest utility which comes with Windows SDK binaries. you need the manifest for the  DLL and for the consuming application, which is in my case is C# command line utility, so you pass here the client manifest file, but before u need to to create the MCF  file to be able to generate the manifest using genmanifest utility, which looks like something this

AUTO-GUID
"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\isvtier5appsigningprivkey.dat"

MODULELIST
            REQ HASH "C:\\path of the executable.exe"
            REQ NOHASH %SYSTEMROOT%\\system32\\msdrm.dll

POLICYLIST
            INCLUSION
        PUBLICKEY "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\isvtier5appsigningpubkey.dat"
            EXCLUSION

The Keys which are used here is RMS preproduction Keys.

below is the code for document protection

DLLAPI HRESULT ProtectDocument(char*stTimeUntilSTR)
    {

        HRESULT                   hr                           = E_FAIL;
        DRMHSESSION               hClient                      = NULL;
        DRMHSESSION               hLicenseStorage              = NULL;
        DRMPUBHANDLE              hIssuanceLicense             = NULL;
        DRMENVHANDLE              hEnv                         = NULL;
        DRMHANDLE                 hLib                         = NULL;
        DRMQUERYHANDLE            hQueryHandle                 = NULL;
        DRMQUERYHANDLE            hSubQueryHandle              = NULL;
        DRMHANDLE                 hBoundLicense                = NULL; 
        DRMHANDLE                 hEnablingPrincipal           = NULL; 
        DRMHANDLE                 hEBDecryptor                 = NULL;
        DRMBOUNDLICENSEPARAMS     oParams; 
        DRMID                     idContent; 
        DRMID                     idStandardEP; 
        DRMID                     idNULL; 
        BOOL                      fShared                      = false;
        PWSTR                     wszGUID                      = NULL;
        PWCHAR                    wszRAC                       = NULL;
        PWCHAR                    wszEUL                       = NULL;
        PWCHAR                    wszActivationSvr             = NULL;

        PWCHAR                      wszManifest                  = NULL;
        PWCHAR                    wszClientLicensorCert        = NULL;
        PWCHAR                    wszSignedIssuanceLicense     = NULL;
        BYTE*                     pbEncryptedContent           = NULL;
        BYTE*                     pbDecryptedContent           = NULL;
        PWCHAR                    wszSecurityProviderType      = NULL;
        PWCHAR                    wszSecurityProviderPath      = NULL;
        PWCHAR                    wszMachineCertificate        = NULL;
        PWCHAR                    wszEndUserLicenseCert        = NULL;
        PWCHAR                    wszIdValue                   = NULL;
        PWCHAR                    wszRevocationList            = NULL;
        PWCHAR                      pwszTemplateString           = NULL; 
        UINT                      uiRevocationListLength       = 0;
        UINT                      uiMachineCertLength          = 0;
        UINT                      uiSecurityProviderTypeLength = 0;
        UINT                      uiSecurityProviderPathLength = 0;
        UINT                      uiGUIDLength                 = 0;
        UINT                      uiRACLength                  = 0;
        UINT                      uiClientLicensorCertLength   = 0;
        UINT                      uiEndUserLicenseCertLength   = 0;
        UINT                      uiEUL                        = 0;
        UINT                      uiIdValue                    = 0;
        UINT                      uiEncryptedDataLength        = 0;
        UINT                      uiDecryptedDataLength        = 0;
        UINT                      uiBlockLength                = 0;
        UINT                      uiBlockLengthSize            = 0;
        UINT                      uiDRMDecryptLength           = 0;
        UINT                      uiUnencryptedDataLength       = 0;
        DWORD                      dwBytesWritten               = 0 ;
        DRM_CONTEXT               context;
        DWORD                      pbDecryptedBytesWritten      = 0;

        //this block ment to test the istorage functions
        WCHAR                      *inputDocFile                   = wcsRmhFilePath;
        IStorage *inputStorage = NULL;
        IStorage *outputStorage = NULL;
        IStorage *pstgPriority = 0;

        context.hEvent = NULL;
        context.wszData = NULL;

        //
        // 1. Create a client session
        //
        hr = DRMCreateClientSession( &StatusCallback, 0, DRM_DEFAULTGROUPIDTYPE_WINDOWSAUTH, 
            wszUserId, &hClient );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMCreateClientSession failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        //
        // 2. Call DRMIsActivated to determine if the machine is already activated
        //
        hr = DRMIsActivated( hClient, DRM_ACTIVATE_MACHINE, NULL );
        if ( E_DRM_NEEDS_MACHINE_ACTIVATION == hr )
        {
            //
            // 3. Call DoMachineActivation to activate the machine if 
            // it's not activated
            //
            hr = DoMachineActivation( hClient, wszActivationSvr );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDoMachineActivation failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }
        }
        else if ( hr == S_OK )
        {
            wprintf( L"\nThe machine is already activated.\n" );
        }
        else
        {
            wprintf( L"\nDRMIsActivated returned an unexpected failure: 0x%x. "\
                L"E_DRM_NEEDS_MACHINE_ACTIVATION was expected.\n", hr );
            goto e_Exit;
        }

        //
        // 4. Enumerate the machine certificate
        //
        hr = DRMEnumerateLicense( hClient, DRM_EL_MACHINE, 0, &fShared, &uiMachineCertLength, NULL);
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMEnumerateLicense failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        wszMachineCertificate = new WCHAR[ uiMachineCertLength ];
        if ( NULL == wszMachineCertificate )
        {
            wprintf( L"\nMemory allocation failed for wszMachineCertificate\n" );
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        hr = DRMEnumerateLicense( hClient, DRM_EL_MACHINE, 0, &fShared, &uiMachineCertLength, wszMachineCertificate);
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMEnumerateLicense failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        //
        // 5. Call DRMIsActivated to determine if the user is 
        // already activated. 
        //

        hr = DRMIsActivated( hClient,DRM_ACTIVATE_GROUPIDENTITY, NULL );
        if ( SUCCEEDED( hr ) )
        {
            wprintf( L"\nThe user is already activated.\n" );
        }
        else if ( E_DRM_NEEDS_GROUPIDENTITY_ACTIVATION == hr )
        {
            //
            // 6. Call DoUserActivation to activate the user if the user 
            // is not activated
            //
            hr = DoUserActivation( hClient, wszActivationSvr );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDoUserActivation failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }
        }
        else if ( E_DRM_NEEDS_GROUPIDENTITY_ACTIVATION != hr )
        {
            wprintf( L"\nDRMIsActivated returned an unexpected failure: 0x%x. "\
                L"E_DRM_NEEDS_GROUPIDENTITY_ACTIVATION "\
                L"was expected.\n", hr );
            goto e_Exit;
        }

        //
        // 7. Call DRMEnumerateLicense to get the RAC from the license store
        //

        wprintf( L"\nGet the RAC from the license store : Step 1\n");
        hr = DRMEnumerateLicense( hClient, DRM_EL_SPECIFIED_GROUPIDENTITY, 0, &fShared, &uiRACLength, NULL );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMEnumerateLicense (DRM_EL_SPECIFIED_GROUPIDENTITY) "\
                L"failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }
        wszRAC = new WCHAR[ uiRACLength ];
        if ( NULL == wszRAC )
        {
            wprintf( L"\nMemory allocation for wszRAC failed.\n" );
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        wprintf( L"\nGet the RAC from the license store : Step 2\n");
        hr = DRMEnumerateLicense( hClient, DRM_EL_SPECIFIED_GROUPIDENTITY, 0, &fShared, &uiRACLength, wszRAC );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMEnumerateLicense(DRM_EL_SPECIFIED_GROUPIDENTITY)"\
                L" failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        //
        // 8. Enumerate the client licensor certificates to determine if one
        // has already been acquired. If not, get a client licensor cert.
        //
        hr = DRMEnumerateLicense( hClient, DRM_EL_SPECIFIED_CLIENTLICENSOR, 0, &fShared, 
            &uiClientLicensorCertLength, NULL );

        if ( FAILED( hr ) && ( E_DRM_NO_MORE_DATA != hr ) )
        {
            wprintf( L"\nDRMEnumerateLicense (DRM_EL_SPECIFIED_CLIENTLICENSOR) "\
                L"failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }
        else if ( E_DRM_NO_MORE_DATA == hr )
        {
            // 9. If there are no client licensor certificates, call 
            // DoAcquireClientLicensorCertificate to acquire one

            hr = DoAcquireClientLicensorCertificate( hClient, wszLicensingSvr, wszUserId, &wszClientLicensorCert );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDoAcquireClientLicensorCertificate failed. "\
                    L"hr = 0x%x\n", hr );
                goto e_Exit;
            }
        }
        else
        {
            wprintf( L"\nA client licensor certificate is "\
                L"already in the license store.\n" );

            wszClientLicensorCert = new WCHAR[ uiClientLicensorCertLength ];
            if ( NULL == wszClientLicensorCert )
            {
                wprintf( L"\nMemory allocation of wszClientLicensorCert "\
                    L"failed.\n" );
                hr = E_OUTOFMEMORY;
                goto e_Exit;
            }

            hr = DRMEnumerateLicense( hClient, DRM_EL_SPECIFIED_CLIENTLICENSOR, 0, &fShared, 
                &uiClientLicensorCertLength, wszClientLicensorCert );

            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMEnumerateLicense(DRM_EL_SPECIFIED_CLIENTLICENSOR)"\
                    L" failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }
        }

        //
        // 10. Read the manifest file into a buffer
        //
        wprintf(L"\nRead the manifest file into a buffer\n");
        wprintf(L"\nManifest File Path : %s\n", wszManifestFileName);

        hr = ReadFileToWideString( wszManifestFileName, &wszManifest );
        if ( FAILED( hr ) )
        {
            wprintf(L"\nManifest File Path : ", wszManifestFileName);
            wprintf( L"\nReadFileToWideString failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }
        wprintf(L"\nRead the manifest file into a buffer is done successfuly\n");

        //
        // 11. Get the security provider
        //
        hr = DRMGetSecurityProvider( 0, &uiSecurityProviderTypeLength, NULL, &uiSecurityProviderPathLength, NULL );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMGetSecurityProvider failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        wszSecurityProviderType = new WCHAR[ uiSecurityProviderTypeLength ];
        if ( NULL == wszSecurityProviderType )
        {
            wprintf( L"\nMemory allocation for wszSecurityProviderType "\
                L"failed.\n" );
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        wszSecurityProviderPath = new WCHAR[ uiSecurityProviderPathLength ];
        if ( NULL == wszSecurityProviderPath )
        {
            wprintf( L"\nMemory allocation for wszSecurityProviderPath "\
                L"failed." );
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        hr = DRMGetSecurityProvider( 0, &uiSecurityProviderTypeLength, wszSecurityProviderType, 
            &uiSecurityProviderPathLength, wszSecurityProviderPath );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMGetSecurityProvider failed. hr = 0x%x\n", hr );
            goto e_Exit;
        }

        //
        // 12. Initialize an environment
        //
        hr = DRMInitEnvironment( DRMSECURITYPROVIDERTYPE_SOFTWARESECREP, DRMSPECTYPE_FILENAME, wszSecurityProviderPath,
            wszManifest, wszMachineCertificate, &hEnv, &hLib );
        if ( FAILED( hr ) )
        {
            wprintf( L"\nDRMInitEnvironment failed. hr = 0x%x.\n", hr );
            goto e_Exit;
        }

        //
        // 13. Create an unsigned issuance license from scratch
        //

        if (ProtectByTemplate == true )
        {
            wprintf(L"\nCreate Issuence License form Template\n");
            // get user 
            hr = DRMCreateUser( wszUserId, NULL, L"Windows", &hUser );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCreateUser failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }

            // 13.1 read rights from template
            wprintf(L"\nRead Template File : %s\n",pwTemplatePath);

            hr = ReadFileToWideString(pwTemplatePath,&pwszTemplateString);
            if ( FAILED( hr ) )
            {
                wprintf( L"ReadFileToWideString failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }

            hr = DRMCreateIssuanceLicense( NULL, NULL, NULL, NULL, hUser, pwszTemplateString, NULL, &hIssuanceLicense);
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCreateIssuanceLicense failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }

            //
            // 14. Call DoOfflinePublishing to add policy to the unsigned issuance
            // license and sign the issuance license
            //
            hr = DoOfflinePublishing( wszClientLicensorCert, 
                hEnv,
                wszUserId, 
                hIssuanceLicense,
                &wszGUID, 
                &wszSignedIssuanceLicense,
                NULL,
                convertStringToSystemTime(stTimeUntilSTR)); 
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDoOfflinePublishing failed. hr = 0x%x.\n", hr );
                goto e_Exit;
            }

        }
        else 
        {
            wprintf(L"\nCreate Issuence License for parametrized rights\n");

            hr = DRMCreateIssuanceLicense( NULL, NULL , NULL, NULL, hUser, NULL, NULL, &hIssuanceLicense );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCreateIssuanceLicense failed. hr = 0x%x\n", hr );
                goto e_Exit;
            }

            //
            // 14. Call DoOfflinePublishing to add policy to the unsigned issuance
            // license and sign the issuance license
            //
            wprintf(L"\nDo Offline Publishing\n");
            //Get Current date time

            hr = DoOfflinePublishing( wszClientLicensorCert, 
                hEnv, 
                wszUserId, 
                hIssuanceLicense, 
                &wszGUID, 
                &wszSignedIssuanceLicense,
                pwUsersRightsList,
                convertStringToSystemTime(stTimeUntilSTR)); 
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDoOfflinePublishing failed. hr = 0x%x.\n", hr );
                goto e_Exit;
            }
        }

        // 14.1 Create a new file to write the signed issuance license to.
        if (debugGeneratedFiles == true && pwsSILOutFile != NULL)
        {
            HANDLE hILFile = CreateFile( pwsSILOutFile, GENERIC_WRITE, 0, NULL,    CREATE_ALWAYS, 0, NULL);                      
            if(INVALID_HANDLE_VALUE == hILFile)
            {
                hr = HRESULT_FROM_WIN32(GetLastError());
                CloseHandle(hILFile);
                goto e_Exit;
            }

            wprintf(L"Signed Issuance License file has been created : hILFile = %i\r\n", hILFile);

            size_t uiIssuanceLicenseLgth = (UINT)(sizeof(WCHAR) * wcslen(wszSignedIssuanceLicense));

            wprintf(L"uiIssuanceLicenseLgth = %d\n",uiIssuanceLicenseLgth );

            // 14.2 Write the signed issuence license to the file
            if(!WriteFile(hILFile, wszSignedIssuanceLicense, uiIssuanceLicenseLgth, &dwBytesWritten, NULL))
            {    
                wprintf(L"Writing Signed Issuance License File : hILFile = %i\r\n", hILFile);
                goto e_Exit;
            }

        }

        // 15. Create a license storage session, passing in an environment object 
        // and a library handle (created previously by DRMInitEnvironment), a
        // client session (created previously by DRMCreateClientSession), and 
        // the issuance license string. 
        //
        hr = DRMCreateLicenseStorageSession( hEnv, hLib, hClient, 0, wszSignedIssuanceLicense, &hLicenseStorage ); 
        if(FAILED(hr)) 
        { 
            wprintf(L"\nDRMCreateLicenseStorageSession failed. hr = 0x%x\n", hr);
            goto e_Exit; 
        } 

        //
        // 16. Encrypt the content
        //
        wprintf( L"\uiUnencryptedDataLength = %d\n", uiUnencryptedDataLength );
        hr = DoEncryptContent(  hEnv, 
            hLib, 
            hLicenseStorage, 
            hIssuanceLicense, 
            wszGUID, 
            wszRAC, 
            wszSignedIssuanceLicense, 
            &uiUnencryptedDataLength,
            &uiEncryptedDataLength, 
            &pbEncryptedContent );

        if ( FAILED( hr ) )
        {
            wprintf( L"\nDoEncryptContent failed. hr = 0x%x.\n", hr );
            goto e_Exit;
        }else
        {
            wprintf( L"\uiUnencryptedDataLength = %d\n", uiUnencryptedDataLength );
            wprintf( L"\uiEncryptedDataLength = %d\n", uiEncryptedDataLength );
        }

        //
        // 17. Create an event for the callback function. This event will be 
        // passed as a void pointer to DRMAcquireLicense. DRMAcquireLicense 
        // simply passes back this pointer to the StatusCallback callback 
        // function which knows that it is an event and will thus signal it 
        // when completed. 
        //
        if ( NULL == ( context.hEvent = CreateEvent ( NULL, FALSE, FALSE, NULL ) ) )
        { 
            wprintf(L"\ncontext.hEvent was NULL after the CreateEvent call.\n" ); 
            goto e_Exit; 
        } 

        // 17.2 write data spaces and signed IL
        hr = StgCreateDocfile(inputDocFile, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,0,&inputStorage);

        if (FAILED(hr))
        {
            printf("StgCreateDocfile() failed w/error %08lx\n", hr);
            return hr;
        }

        hr = HrWriteDataspaces(inputStorage,wszSignedIssuanceLicense);

        if (FAILED(hr))
        {
            printf("HrWriteDataspaces() failed w/error %08lx\n", hr);
            return hr;
        }

        // 17.1
        // add the encrypted file to the compound file 
        wprintf( L"\uiUnencryptedDataLength %d\n", uiUnencryptedDataLength );

        hr = AddEncryptedContent(inputStorage, uiUnencryptedDataLength, pbEncryptedContent, uiEncryptedDataLength);

        if ( FAILED( hr ) )
        {
            wprintf( L"\nAddEncryptedContent failed. hr = 0x%x.\n", hr );
            goto e_Exit;
        }

e_Exit:
        //
        // 26. Clean up and free memory
        //
        if ( NULL != hClient )
        {
            hr = DRMCloseSession( hClient );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseSession failed while closing "\
                    L"hClient. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hIssuanceLicense )
        {
            hr = DRMClosePubHandle( hIssuanceLicense );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMClosePubHandle failed while closing "\
                    L"hIssuanceLicense. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hQueryHandle )
        {
            hr = DRMCloseQueryHandle( hQueryHandle );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseQueryHandle failed while closing "\
                    L"hQueryHandle. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hSubQueryHandle )
        {
            hr = DRMCloseQueryHandle( hSubQueryHandle );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseQueryHandle failed while closing "\
                    L"hSubQueryHandle. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hLicenseStorage )
        {
            hr = DRMCloseSession( hLicenseStorage );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseSession failed while closing "\
                    L"hLicenseStorage. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hEnablingPrincipal )
        {
            hr = DRMCloseHandle( hEnablingPrincipal );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseHandle failed while closing "\
                    L"hEnablingPrincipal. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hBoundLicense )
        {
            hr = DRMCloseHandle( hBoundLicense );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseHandle failed while closing "\
                    L"hBoundLicense. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hEBDecryptor )
        {
            hr = DRMCloseHandle( hEBDecryptor );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseHandle failed while closing "\
                    L"hEBDecryptor. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hLib )
        {
            hr = DRMCloseHandle( hLib );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseHandle failed while closing "\
                    L"hLib. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != hEnv )
        {
            hr = DRMCloseEnvironmentHandle( hEnv );
            if ( FAILED( hr ) )
            {
                wprintf( L"\nDRMCloseEnvironmentHandle failed while closing "\
                    L"hEnv. hr = 0x%x\n", hr );
            }
        }
        if ( NULL != context.wszData )
        {
            delete [] context.wszData;
        }
        if ( NULL != context.hEvent )
        {
            CloseHandle( context.hEvent );
        }
        if ( NULL != wszUserId )
        {
            wszUserId = NULL;
            delete [] wszUserId;
        }
        if ( NULL != wszIdValue )
        {
            delete [] wszIdValue;
        }
        if ( NULL != wszActivationSvr )
        {
            delete [] wszActivationSvr;
        }
        if ( NULL != wszLicensingSvr )
        {
            delete [] wszLicensingSvr;
        }
        if ( NULL != wszManifestFileName )
        {
            wszManifestFileName = NULL;
            delete [] wszManifestFileName;
        }
        if ( NULL != wszManifest )
        {
            delete [] wszManifest;
        }
        if ( NULL != wszClientLicensorCert )
        {
            delete [] wszClientLicensorCert;
        }
        if ( NULL != wszEndUserLicenseCert )
        {
            delete [] wszEndUserLicenseCert;
        }
        if ( NULL != wszSecurityProviderType )
        {
            delete [] wszSecurityProviderType;
        }
        if ( NULL != wszSecurityProviderPath )
        {
            delete [] wszSecurityProviderPath;
        }
        if ( NULL != wszMachineCertificate )
        {
            delete [] wszMachineCertificate;
        }
        if ( NULL != pbEncryptedContent )
        {
            delete [] pbEncryptedContent;
        }
        if ( NULL != pbDecryptedContent )
        {
            delete [] pbDecryptedContent;
        }
        if ( NULL != wszSignedIssuanceLicense )
        {
            delete [] wszSignedIssuanceLicense;
        }
        if ( NULL != wszRevocationList )
        {
            delete [] wszRevocationList;
        }
        if ( NULL != wszGUID )
        {
            delete [] wszGUID;
        }
        if ( NULL != wszRAC )
        {
            delete [] wszRAC;
        }
        if ( NULL != wszEUL )
        {
            delete [] wszEUL;
        }

        if ( FAILED( hr ) )
        {
            wprintf( L"\nConsumption failed. hr = 0x%x\n", hr );
        }

        return hr;
    }

There is a lot of header files and C files which i didn’t include because all of them are available in the project file. if any question has been raised regarding the code or RMS SDK, i will be more than happy to answer it. 

Posted in Cryptography, Programming, System Administartion, Technology and tagged , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink. RSS feed for this post. Leave a trackback.

5 Responses to AD RMS Protecting A document Programmatically

  1. Lee says:

    hi, SADDAM
    i already download your project, but i got some errors
    DRMInitEnvironment failed. hr = 0x8004cf19

    Can your give me some suggestions,
    Thank you very much.

  2. Alessio says:

    Hi Saddam, thanks in advance for your help.

    I noticed that in a domain (ad rms server on-premises), the user that protect the document is always set as its owner. If you explicitly set an owner, it will be just another owner (co-owner).
    This implies that if I create a web service that interface itself with the RMS system on the behalf of other user, protecting a document with the rights specified from the clients as input, the user that runs the web server on which the web service sits will always be able to see and un-protect a document. Do you agree? there is no way to avoid that? thanks

    • Saddam Abu Ghaida says:

      hello there,

      you are right, because the owner of the document is being passed through NTLM challenge response so, what i did personally after signing the IIS worker with the production key, i changed the application pool username to a domain user acts as DR for all documents and enabled IIS impersonation, in order to make the owner is the user who issued the protect command and the DR as DR user in case the user left or whatever. and this applies the same if you are protecting from template or pass the verbs through the web services RMS API WRAPPER i hope that helps

  3. Kevin Wang says:

    Hi SADDAM,
    I want to use your code to protect office files. Following error occurs after user activated.

    DRMEnumerateLicense (DRM_EL_SPECIFIED_GROUPIDENTITY) failed. hr = 0x8004cf33

    the error code means E_DRM_NO_MORE_DATA.
    I don’t know what’s the cause. Can you give some suggestions?
    thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

Swedish Greys - a WordPress theme from Nordic Themepark.