home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / security / winnt / lsasamp / lsasamp.c < prev    next >
C/C++ Source or Header  |  1996-01-07  |  13KB  |  469 lines

  1. /*++
  2.  
  3. Managing user privileges can be achieved programmatically using the
  4. following steps:
  5.  
  6. 1. Open the policy on the target machine with LsaOpenPolicy(). To grant
  7.    privileges, open the policy with POLICY_CREATE_ACCOUNT and
  8.    POLICY_LOOKUP_NAMES access. To revoke privileges, open the policy with
  9.    POLICY_LOOKUP_NAMES access.
  10.  
  11. 2. Obtain a SID (security identifier) representing the user/group of
  12.    interest. The LookupAccountName() and LsaLookupNames() APIs can obtain a
  13.    SID from an account name.
  14.  
  15. 3. Call LsaAddAccountRights() to grant privileges to the user(s)
  16.    represented by the supplied SID.
  17.  
  18. 4. Call LsaRemoveAccountRights() to revoke privileges from the user(s)
  19.    represented by the supplied SID.
  20.  
  21. 5. Close the policy with LsaClose().
  22.  
  23. To successfully grant and revoke privileges, the caller needs to be an
  24. administrator on the target system.
  25.  
  26. The LSA API LsaEnumerateAccountRights() can be used to determine which
  27. privileges have been granted to an account.
  28.  
  29. The LSA API LsaEnumerateAccountsWithUserRight() can be used to determine
  30. which accounts have been granted a specified privilege.
  31.  
  32. Documentation and header files for these LSA APIs is provided in the
  33. Windows 32 SDK in the MSTOOLS\SECURITY directory.
  34.  
  35. NOTE: These LSA APIs are currently implemented as Unicode only.
  36.  
  37. This sample will grant the privilege SeServiceLogonRight to the account
  38. specified on argv[1].
  39.  
  40. This sample is dependant on these import libs
  41.  
  42.    advapi32.lib (for LsaXxx)
  43.    user32.lib (for wsprintf)
  44.  
  45. This sample will work properly compiled ANSI or Unicode.
  46.  
  47.  
  48.  
  49. You can use domain\account as argv[1]. For instance, mydomain\scott will
  50. grant the privilege to the mydomain domain account scott.
  51.  
  52. The optional target machine is specified as argv[2], otherwise, the
  53. account database is updated on the local machine.
  54.  
  55. The LSA APIs used by this sample are Unicode only.
  56.  
  57. Use LsaRemoveAccountRights() to remove account rights.
  58.  
  59. Scott Field (sfield)    12-Jul-95
  60.  
  61. --*/
  62.  
  63. #ifndef UNICODE
  64. #define UNICODE
  65. #endif // UNICODE
  66.  
  67. #include <windows.h>
  68. #include <stdio.h>
  69.  
  70. #include "ntsecapi.h"
  71.  
  72. NTSTATUS
  73. OpenPolicy(
  74.     LPWSTR ServerName,          // machine to open policy on (Unicode)
  75.     DWORD DesiredAccess,        // desired access to policy
  76.     PLSA_HANDLE PolicyHandle    // resultant policy handle
  77.     );
  78.  
  79. BOOL
  80. GetAccountSid(
  81.     LPTSTR SystemName,          // where to lookup account
  82.     LPTSTR AccountName,         // account of interest
  83.     PSID *Sid                   // resultant buffer containing SID
  84.     );
  85.  
  86. NTSTATUS
  87. SetPrivilegeOnAccount(
  88.     LSA_HANDLE PolicyHandle,    // open policy handle
  89.     PSID AccountSid,            // SID to grant privilege to
  90.     LPWSTR PrivilegeName,       // privilege to grant (Unicode)
  91.     BOOL bEnable                // enable or disable
  92.     );
  93.  
  94. void
  95. InitLsaString(
  96.     PLSA_UNICODE_STRING LsaString, // destination
  97.     LPWSTR String                  // source (Unicode)
  98.     );
  99.  
  100. void
  101. DisplayNtStatus(
  102.     LPSTR szAPI,                // pointer to function name (ANSI)
  103.     NTSTATUS Status             // NTSTATUS error value
  104.     );
  105.  
  106. void
  107. DisplayWinError(
  108.     LPSTR szAPI,                // pointer to function name (ANSI)
  109.     DWORD WinError              // DWORD WinError
  110.     );
  111.  
  112. #define RTN_OK 0
  113. #define RTN_USAGE 1
  114. #define RTN_ERROR 13
  115.  
  116. //
  117. // If you have the ddk, include ntstatus.h.
  118. //
  119. #ifndef STATUS_SUCCESS
  120. #define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
  121. #endif
  122.  
  123. int _cdecl
  124. main(int argc, char *argv[])
  125. {
  126.     LSA_HANDLE PolicyHandle;
  127.     WCHAR wComputerName[256]=L"";   // static machine name buffer
  128.     TCHAR AccountName[256];         // static account name buffer
  129.     PSID pSid;
  130.     NTSTATUS Status;
  131.     int iRetVal=RTN_ERROR;          // assume error from main
  132.  
  133.     if(argc == 1)
  134.     {
  135.         fprintf(stderr,"Usage: %s <Account> [TargetMachine]\n",
  136.             argv[0]);
  137.         return RTN_USAGE;
  138.     }
  139.  
  140.     //
  141.     // Pick up account name on argv[1].
  142.     // Assumes source is ANSI. Resultant string is ANSI or Unicode
  143.     //
  144.     wsprintf(AccountName, TEXT("%hS"), argv[1]);
  145.  
  146.     //
  147.     // Pick up machine name on argv[2], if appropriate
  148.     // assumes source is ANSI. Resultant string is Unicode.
  149.     //
  150.     if(argc == 3) wsprintfW(wComputerName, L"%hS", argv[2]);
  151.  
  152.     //
  153.     // Open the policy on the target machine.
  154.     //
  155.     if((Status=OpenPolicy(
  156.                 wComputerName,      // target machine
  157.                 POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
  158.                 &PolicyHandle       // resultant policy handle
  159.                 )) != STATUS_SUCCESS) {
  160.         DisplayNtStatus("OpenPolicy", Status);
  161.         return RTN_ERROR;
  162.     }
  163.  
  164.     //
  165.     // Obtain the SID of the user/group.
  166.     // Note that we could target a specific machine, but we don't.
  167.     // Specifying NULL for target machine searches for the SID in the
  168.     // following order: well-known, Built-in and local, primary domain,
  169.     // trusted domains.
  170.     //
  171.     if(GetAccountSid(
  172.             NULL,       // default lookup logic
  173.             AccountName,// account to obtain SID
  174.             &pSid       // buffer to allocate to contain resultant SID
  175.             )) {
  176.         //
  177.         // We only grant the privilege if we succeeded in obtaining the
  178.         // SID. We can actually add SIDs which cannot be looked up, but
  179.         // looking up the SID is a good sanity check which is suitable for
  180.         // most cases.
  181.  
  182.         //
  183.         // Grant the SeServiceLogonRight to users represented by pSid.
  184.         //
  185.         if((Status=SetPrivilegeOnAccount(
  186.                     PolicyHandle,           // policy handle
  187.                     pSid,                   // SID to grant privilege
  188.                     L"SeServiceLogonRight", // Unicode privilege
  189.                     TRUE                    // enable the privilege
  190.                     )) == STATUS_SUCCESS)
  191.             iRetVal=RTN_OK;
  192.         else
  193.             DisplayNtStatus("AddUserRightToAccount", Status);
  194.     }
  195.     else {
  196.         //
  197.         // Error obtaining SID.
  198.         //
  199.         DisplayWinError("GetAccountSid", GetLastError());
  200.     }
  201.  
  202.     //
  203.     // Close the policy handle.
  204.     //
  205.     LsaClose(PolicyHandle);
  206.  
  207.     //
  208.     // Free memory allocated for SID.
  209.     //
  210.     if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid);
  211.  
  212.     return iRetVal;
  213. }
  214.  
  215. void
  216. InitLsaString(
  217.     PLSA_UNICODE_STRING LsaString,
  218.     LPWSTR String
  219.     )
  220. {
  221.     DWORD StringLength;
  222.  
  223.     if (String == NULL) {
  224.         LsaString->Buffer = NULL;
  225.         LsaString->Length = 0;
  226.         LsaString->MaximumLength = 0;
  227.         return;
  228.     }
  229.  
  230.     StringLength = wcslen(String);
  231.     LsaString->Buffer = String;
  232.     LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
  233.     LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
  234. }
  235.  
  236. NTSTATUS
  237. OpenPolicy(
  238.     LPWSTR ServerName,
  239.     DWORD DesiredAccess,
  240.     PLSA_HANDLE PolicyHandle
  241.     )
  242. {
  243.     LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  244.     LSA_UNICODE_STRING ServerString;
  245.     PLSA_UNICODE_STRING Server = NULL;
  246.  
  247.     //
  248.     // Always initialize the object attributes to all zeroes.
  249.     //
  250.     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  251.  
  252.     if (ServerName != NULL) {
  253.         //
  254.         // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  255.         //
  256.         InitLsaString(&ServerString, ServerName);
  257.         Server = &ServerString;
  258.     }
  259.  
  260.     //
  261.     // Attempt to open the policy.
  262.     //
  263.     return LsaOpenPolicy(
  264.                 Server,
  265.                 &ObjectAttributes,
  266.                 DesiredAccess,
  267.                 PolicyHandle
  268.                 );
  269. }
  270.  
  271. /*++
  272. This function attempts to obtain a SID representing the supplied
  273. account on the supplied system.
  274.  
  275. If the function succeeds, the return value is TRUE. A buffer is
  276. allocated which contains the SID representing the supplied account.
  277. This buffer should be freed when it is no longer needed by calling
  278. HeapFree(GetProcessHeap(), 0, buffer)
  279.  
  280. If the function fails, the return value is FALSE. Call GetLastError()
  281. to obtain extended error information.
  282.  
  283. Scott Field (sfield)    12-Jul-95
  284. --*/
  285.  
  286. BOOL
  287. GetAccountSid(
  288.     LPTSTR SystemName,
  289.     LPTSTR AccountName,
  290.     PSID *Sid
  291.     )
  292. {
  293.     LPTSTR ReferencedDomain=NULL;
  294.     DWORD cbSid=128;    // initial allocation attempt
  295.     DWORD cbReferencedDomain=16; // initial allocation size
  296.     SID_NAME_USE peUse;
  297.     BOOL bSuccess=FALSE; // assume this function will fail
  298.  
  299.     __try {
  300.  
  301.     //
  302.     // initial memory allocations
  303.     //
  304.     if((*Sid=HeapAlloc(
  305.                     GetProcessHeap(),
  306.                     0,
  307.                     cbSid
  308.                     )) == NULL) __leave;
  309.  
  310.     if((ReferencedDomain=HeapAlloc(
  311.                     GetProcessHeap(),
  312.                     0,
  313.                     cbReferencedDomain
  314.                     )) == NULL) __leave;
  315.  
  316.     //
  317.     // Obtain the SID of the specified account on the specified system.
  318.     //
  319.     while(!LookupAccountName(
  320.                     SystemName,         // machine to lookup account on
  321.                     AccountName,        // account to lookup
  322.                     *Sid,               // SID of interest
  323.                     &cbSid,             // size of SID
  324.                     ReferencedDomain,   // domain account was found on
  325.                     &cbReferencedDomain,
  326.                     &peUse
  327.                     )) {
  328.         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  329.             //
  330.             // reallocate memory
  331.             //
  332.             if((*Sid=HeapReAlloc(
  333.                         GetProcessHeap(),
  334.                         0,
  335.                         *Sid,
  336.                         cbSid
  337.                         )) == NULL) __leave;
  338.  
  339.             if((ReferencedDomain=HeapReAlloc(
  340.                         GetProcessHeap(),
  341.                         0,
  342.                         ReferencedDomain,
  343.                         cbReferencedDomain
  344.                         )) == NULL) __leave;
  345.         }
  346.         else __leave;
  347.     }
  348.  
  349.     //
  350.     // Indicate success.
  351.     //
  352.     bSuccess=TRUE;
  353.  
  354.     } // finally
  355.     __finally {
  356.  
  357.     //
  358.     // Cleanup and indicate failure, if appropriate.
  359.     //
  360.  
  361.     HeapFree(GetProcessHeap(), 0, ReferencedDomain);
  362.  
  363.     if(!bSuccess) {
  364.         if(*Sid != NULL) {
  365.             HeapFree(GetProcessHeap(), 0, *Sid);
  366.             *Sid = NULL;
  367.         }
  368.     }
  369.  
  370.     } // finally
  371.  
  372.     return bSuccess;
  373. }
  374.  
  375. NTSTATUS
  376. SetPrivilegeOnAccount(
  377.     LSA_HANDLE PolicyHandle,    // open policy handle
  378.     PSID AccountSid,            // SID to grant privilege to
  379.     LPWSTR PrivilegeName,       // privilege to grant (Unicode)
  380.     BOOL bEnable                // enable or disable
  381.     )
  382. {
  383.     LSA_UNICODE_STRING PrivilegeString;
  384.  
  385.     //
  386.     // Create a LSA_UNICODE_STRING for the privilege name.
  387.     //
  388.     InitLsaString(&PrivilegeString, PrivilegeName);
  389.  
  390.     //
  391.     // grant or revoke the privilege, accordingly
  392.     //
  393.     if(bEnable) {
  394.         return LsaAddAccountRights(
  395.                 PolicyHandle,       // open policy handle
  396.                 AccountSid,         // target SID
  397.                 &PrivilegeString,   // privileges
  398.                 1                   // privilege count
  399.                 );
  400.     }
  401.     else {
  402.         return LsaRemoveAccountRights(
  403.                 PolicyHandle,       // open policy handle
  404.                 AccountSid,         // target SID
  405.                 FALSE,              // do not disable all rights
  406.                 &PrivilegeString,   // privileges
  407.                 1                   // privilege count
  408.                 );
  409.     }
  410. }
  411.  
  412. void
  413. DisplayNtStatus(
  414.     LPSTR szAPI,
  415.     NTSTATUS Status
  416.     )
  417. {
  418.     //
  419.     // Convert the NTSTATUS to Winerror. Then call DisplayWinError().
  420.     //
  421.     DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
  422. }
  423.  
  424. void
  425. DisplayWinError(
  426.     LPSTR szAPI,
  427.     DWORD WinError
  428.     )
  429. {
  430.     LPSTR MessageBuffer;
  431.     DWORD dwBufferLength;
  432.  
  433.     //
  434.     // TODO: Get this fprintf out of here!
  435.     //
  436.     fprintf(stderr,"%s error!\n", szAPI);
  437.  
  438.     if(dwBufferLength=FormatMessageA(
  439.                         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  440.                         FORMAT_MESSAGE_FROM_SYSTEM,
  441.                         NULL,
  442.                         WinError,
  443.                         GetUserDefaultLangID(),
  444.                         (LPSTR) &MessageBuffer,
  445.                         0,
  446.                         NULL
  447.                         ))
  448.     {
  449.         DWORD dwBytesWritten; // unused
  450.  
  451.         //
  452.         // Output message string on stderr.
  453.         //
  454.         WriteFile(
  455.             GetStdHandle(STD_ERROR_HANDLE),
  456.             MessageBuffer,
  457.             dwBufferLength,
  458.             &dwBytesWritten,
  459.             NULL
  460.             );
  461.  
  462.         //
  463.         // Free the buffer allocated by the system.
  464.         //
  465.         LocalFree(MessageBuffer);
  466.     }
  467. }
  468.  
  469.