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 / lsaprivs / lsaprivs.c next >
C/C++ Source or Header  |  1997-10-05  |  13KB  |  463 lines

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