文章編號: 132958 - 上次校閱: 2005年3月1日 - 版次: 3.2

如何管理使用者權限,以程式設計方式在 Windows NT 中

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。

在此頁中

全部展開 | 全部摺疊

結論

在 Windows NT 權限用來提供不同於判別存取控制的存取控制的方法。系統管理員會使用的權限來控制哪些使用者/群組就能操作系統的各種層面。當它變更如系統的時間的系統資源,或關閉系統時,應用程式可能使用的權限。

[使用者管理員] 工具可用來授與和撤銷來自帳號的權限。

Windows NT 3.51 提供可讓開發人員以程式設計的方式管理的權限的功能。這項功能是供透過 LSA (本機安全性授權)。

將受益於 LSA 的應用程式的範例是服務安裝程式。如果 「 服務設定為 [使用者帳戶下執行時,就必須為該帳戶擁有 SeServiceLogonRight 「 登入為服務 」 的權限。本文將告訴您,如何善用 LSA 授與和撤銷從使用者和群組的權限。

其他相關資訊

管理使用者權限也能得到以程式設計方式使用下列步驟執行:
  1. 使用 LsaOpenPolicy() 開啟目標電腦上的原則。若要授予的權限開啟 [POLICY_CREATE_ACCOUNT 和 POLICY_LOOKUP_NAMES 存取的 [原則]。若要撤銷的權限,以 POLICY_LOOKUP_NAMES 存取方式開啟該原則。
  2. 取得表示使用者/群組感興趣的一個 SID (安全性識別元)。LookupAccountName() 和 LsaLookupNames() API 可以取得從帳戶名稱的 SID。
  3. 呼叫 LsaAddAccountRights() 所提供的 SID 代表使用者授與權限。
  4. 呼叫 LsaRemoveAccountRights() 撤銷所提供的 SID 代表使用者的權限。
  5. 關閉具有 LsaClose() 原則。
若要成功授與、 撤銷的權限,呼叫者必須是系統管理員,目標系統上。

LSA API LsaEnumerateAccountRights() 來決定的帳戶已授與哪些權限。

LSA API LsaEnumerateAccountsWithUserRight() 可用來判斷哪些帳戶已授與指定的權限。

對於這些 LSA API 的說明文件和標頭檔中 Windows 32 SDK MSTOOLS\SECURITY 目錄中提供。

Win32 SDK lastest 版本中, 標題會顯示在 mstools\samples\win32\winnt\security\include 目錄中,文件是....\security\lsasamp\lsaapi.hlp。

注意:這些 LSA API 目前實作為 Unicode 只。

這個範例會授與權限 SeServiceLogonRight 來 argv [1] 所指定之帳戶。

這個範例是相依在這些匯入 libs
advapi32.lib (針對 LsaXxx)
user32.lib (針對 wsprintf)
這個範例將工作正確編譯 ANSI 或 Unicode。

範例程式碼

/*++

You can use domain\account as argv[1]. For instance, mydomain\scott will
grant the privilege to the mydomain domain account scott.

The optional target machine is specified as argv[2], otherwise, the
account database is updated on the local machine.

The LSA APIs used by this sample are Unicode only.

Use LsaRemoveAccountRights() to remove account rights.

Scott Field (sfield)    12-Jul-95
--*/ 

#ifndef UNICODE
#define UNICODE
#endif // UNICODE

#include <windows.h>
#include <stdio.h>

#include "ntsecapi.h"

NTSTATUS
OpenPolicy(
    LPWSTR ServerName,          // machine to open policy on (Unicode)
    DWORD DesiredAccess,        // desired access to policy
    PLSA_HANDLE PolicyHandle    // resultant policy handle
    );

BOOL
GetAccountSid(
    LPTSTR SystemName,          // where to lookup account
    LPTSTR AccountName,         // account of interest
    PSID *Sid                   // resultant buffer containing SID
    );

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    );

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString, // destination
    LPWSTR String                  // source (Unicode)
    );

void
DisplayNtStatus(
    LPSTR szAPI,                // pointer to function name (ANSI)
    NTSTATUS Status             // NTSTATUS error value
    );

void
DisplayWinError(
    LPSTR szAPI,                // pointer to function name (ANSI)
    DWORD WinError              // DWORD WinError
    );

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

// 
// If you have the ddk, include ntstatus.h.
// 
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
#endif

int _cdecl
main(int argc, char *argv[])
{
    LSA_HANDLE PolicyHandle;
    WCHAR wComputerName[256]=L"";   // static machine name buffer
    TCHAR AccountName[256];         // static account name buffer
    PSID pSid;
    NTSTATUS Status;
    int iRetVal=RTN_ERROR;          // assume error from main

    if(argc == 1)
    {
        fprintf(stderr,"Usage: %s <Account> [TargetMachine]\n",
            argv[0]);
        return RTN_USAGE;
    }

    // 
    // Pick up account name on argv[1].
    // Assumes source is ANSI. Resultant string is ANSI or Unicode
    // 
    wsprintf(AccountName, TEXT("%hS"), argv[1]);

    // 
    // Pick up machine name on argv[2], if appropriate
    // assumes source is ANSI. Resultant string is Unicode.
    // 
    if(argc == 3) wsprintfW(wComputerName, L"%hS", argv[2]);

    // 
    // Open the policy on the target machine.
    // 
    if((Status=OpenPolicy(
                wComputerName,      // target machine
                POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
                &PolicyHandle       // resultant policy handle
                )) != STATUS_SUCCESS) {
        DisplayNtStatus("OpenPolicy", Status);
        return RTN_ERROR;
    }

    // 
    // Obtain the SID of the user/group.
    // Note that we could target a specific machine, but we don't.
    // Specifying NULL for target machine searches for the SID in the
    // following order: well-known, Built-in and local, primary domain,
    // trusted domains.
    // 
    if(GetAccountSid(
            NULL,       // default lookup logic
            AccountName,// account to obtain SID
            &pSid       // buffer to allocate to contain resultant SID
            )) {
        // 
        // We only grant the privilege if we succeeded in obtaining the
        // SID. We can actually add SIDs which cannot be looked up, but
        // looking up the SID is a good sanity check which is suitable for
        // most cases.

        // 
        // Grant the SeServiceLogonRight to users represented by pSid.
        // 
        if((Status=SetPrivilegeOnAccount(
                    PolicyHandle,           // policy handle
                    pSid,                   // SID to grant privilege
                    L"SeServiceLogonRight", // Unicode privilege
                    TRUE                    // enable the privilege
                    )) == STATUS_SUCCESS)
            iRetVal=RTN_OK;
        else
            DisplayNtStatus("AddUserRightToAccount", Status);
    }
    else {
        // 
        // Error obtaining SID.
        // 
        DisplayWinError("GetAccountSid", GetLastError());
    }

    // 
    // Close the policy handle.
    // 
    LsaClose(PolicyHandle);

    // 
    // Free memory allocated for SID.
    // 
    if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid);

    return iRetVal;
}

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString,
    LPWSTR String
    )
{
    DWORD StringLength;

    if (String == NULL) {
        LsaString->Buffer = NULL;
        LsaString->Length = 0;
        LsaString->MaximumLength = 0;
        return;
    }

    StringLength = wcslen(String);
    LsaString->Buffer = String;
    LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
    LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
}

NTSTATUS
OpenPolicy(
    LPWSTR ServerName,
    DWORD DesiredAccess,
    PLSA_HANDLE PolicyHandle
    )
{
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_UNICODE_STRING ServerString;
    PLSA_UNICODE_STRING Server = NULL;

    // 
    // Always initialize the object attributes to all zeroes.
    // 
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));

    if (ServerName != NULL) {
        // 
        // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
        // 
        InitLsaString(&ServerString, ServerName);
        Server = &ServerString;
    }

    // 
    // Attempt to open the policy.
    // 
    return LsaOpenPolicy(
                Server,
                &ObjectAttributes,
                DesiredAccess,
                PolicyHandle
                );
}

/*++
This function attempts to obtain a SID representing the supplied
account on the supplied system.

If the function succeeds, the return value is TRUE. A buffer is
allocated which contains the SID representing the supplied account.
This buffer should be freed when it is no longer needed by calling
HeapFree(GetProcessHeap(), 0, buffer)

If the function fails, the return value is FALSE. Call GetLastError()
to obtain extended error information.

Scott Field (sfield)    12-Jul-95
--*/ 

BOOL
GetAccountSid(
    LPTSTR SystemName,
    LPTSTR AccountName,
    PSID *Sid
    )
{
    LPTSTR ReferencedDomain=NULL;
    DWORD cbSid=128;    // initial allocation attempt
    DWORD cchReferencedDomain=16; // initial allocation size
    SID_NAME_USE peUse;
    BOOL bSuccess=FALSE; // assume this function will fail

    __try {

    // 
    // initial memory allocations
    // 
    if((*Sid=HeapAlloc(
                    GetProcessHeap(),
                    0,
                    cbSid
                    )) == NULL) __leave;

    if((ReferencedDomain=(LPTSTR)HeapAlloc(
                    GetProcessHeap(),
                    0,
                    cchReferencedDomain * sizeof(TCHAR)
                    )) == NULL) __leave;

    // 
    // Obtain the SID of the specified account on the specified system.
    // 
    while(!LookupAccountName(
                    SystemName,         // machine to lookup account on
                    AccountName,        // account to lookup
                    *Sid,               // SID of interest
                    &cbSid,             // size of SID
                    ReferencedDomain,   // domain account was found on
                    &cchReferencedDomain,
                    &peUse
                    )) {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
            // 
            // reallocate memory
            // 
            if((*Sid=HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        *Sid,
                        cbSid
                        )) == NULL) __leave;

            if((ReferencedDomain=(LPTSTR)HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        ReferencedDomain,
                        cchReferencedDomain * sizeof(TCHAR)
                        )) == NULL) __leave;
        }
        else __leave;
    }

    // 
    // Indicate success.
    // 
    bSuccess=TRUE;

    } // finally
    __finally {

    // 
    // Cleanup and indicate failure, if appropriate.
    // 

    HeapFree(GetProcessHeap(), 0, ReferencedDomain);

    if(!bSuccess) {
        if(*Sid != NULL) {
            HeapFree(GetProcessHeap(), 0, *Sid);
            *Sid = NULL;
        }
    }

    } // finally

    return bSuccess;
}

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    )
{
    LSA_UNICODE_STRING PrivilegeString;

    // 
    // Create a LSA_UNICODE_STRING for the privilege name.
    // 
    InitLsaString(&PrivilegeString, PrivilegeName);

    // 
    // grant or revoke the privilege, accordingly
    // 
    if(bEnable) {
        return LsaAddAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
    else {
        return LsaRemoveAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                FALSE,              // do not disable all rights
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
}

void
DisplayNtStatus(
    LPSTR szAPI,
    NTSTATUS Status
    )
{
    // 
    // Convert the NTSTATUS to Winerror. Then call DisplayWinError().
    // 
    DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
}

void
DisplayWinError(
    LPSTR szAPI,
    DWORD WinError
    )
{
    LPSTR MessageBuffer;
    DWORD dwBufferLength;

    // 
    // TODO: Get this fprintf out of here!
    // 
    fprintf(stderr,"%s error!\n", szAPI);

    if(dwBufferLength=FormatMessageA(
                        FORMAT_MESSAGE_ALLOCATE_BUFFER |
                        FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        WinError,
                        GetUserDefaultLangID(),
                        (LPSTR) &MessageBuffer,
                        0,
                        NULL
                        ))
    {
        DWORD dwBytesWritten; // unused

        // 
        // Output message string on stderr.
        // 
        WriteFile(
            GetStdHandle(STD_ERROR_HANDLE),
            MessageBuffer,
            dwBufferLength,
            &dwBytesWritten,
            NULL
            );

        // 
        // Free the buffer allocated by the system.
        // 
        LocalFree(MessageBuffer);
    }
}
				
/*++
This function enables system access on the account represented by the
supplied SID. An example of such access is the SeLogonServiceRight.

Note: to disable a given system access, simply remove the supplied
access flag from the existing flag, and apply the result to the
account.

If the function succeeds, the return value is STATUS_SUCCESS.
If the function fails, the return value is an NTSTATUS value.

Scott Field (sfield)    14-Jul-95
--*/ 
NTSTATUS
AddSystemAccessToAccount(
   LSA_HANDLE PolicyHandle,
   PSID AccountSid,
   ULONG NewAccess
   )
{
   LSA_HANDLE AccountHandle;
   ULONG PreviousAccess;
   NTSTATUS Status;

   // 
   // open the account object. If it doesn't exist, create a new one
   // 
   if((Status=LsaOpenAccount(
           PolicyHandle,
           AccountSid,
           ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
           &AccountHandle
           )) == STATUS_OBJECT_NAME_NOT_FOUND)
   {
       Status=LsaCreateAccount(
               PolicyHandle,
               AccountSid,
               ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
               &AccountHandle
               );
   }

   // 
   // if an error occurred opening or creating, return
   // 
   if(Status != STATUS_SUCCESS) return Status;

   // 
   // obtain current system access flags
   // 
   if((Status=LsaGetSystemAccessAccount(
           AccountHandle,
           &PreviousAccess
           )) == STATUS_SUCCESS)
   {
       // 
       // Add the specified access to the account
       // 
       Status=LsaSetSystemAccessAccount(
               AccountHandle,
               PreviousAccess | NewAccess
               );
   }

   LsaClose(AccountHandle);

   return Status;
}

/*++
This function grants a privilege to the account represented by the
supplied SID. An example of such a privilege is the
SeBackupPrivilege.

Note: To revoke a privilege, use LsaRemovePrivilegesFromAccount.

If the function succeeds, the return value is STATUS_SUCCESS.
If the function fails, the return value is an NTSTATUS value.

Scott Field (sfield)    13-Jul-95
--*/ 

NTSTATUS
AddPrivilegeToAccount(
   LSA_HANDLE PolicyHandle,
   PSID AccountSid,
   LPWSTR PrivilegeName
   )
{
   PRIVILEGE_SET ps;
   LUID_AND_ATTRIBUTES luidattr;
   LSA_HANDLE AccountHandle;
   LSA_UNICODE_STRING PrivilegeString;
   NTSTATUS Status;

   // 
   // Create a LSA_UNICODE_STRING for the privilege name
   // 
   InitLsaString(&PrivilegeString, PrivilegeName);

   // 
   // obtain the LUID of the supplied privilege
   // 
   if((Status=LsaLookupPrivilegeValue(
           PolicyHandle,
           &PrivilegeString,
           &luidattr.Luid
           )) != STATUS_SUCCESS) return Status;

   // 
   // setup PRIVILEGE_SET
   // 
   luidattr.Attributes=0;
   ps.PrivilegeCount=1;
   ps.Control=0;
   ps.Privilege[0]=luidattr;

   // 
   // open the account object if it doesn't exist, create a new one
   // 
   if((Status=LsaOpenAccount(
           PolicyHandle,
           AccountSid,
           ACCOUNT_ADJUST_PRIVILEGES,
           &AccountHandle
           )) == STATUS_OBJECT_NAME_NOT_FOUND)
   {
       Status=LsaCreateAccount(
               PolicyHandle,
               AccountSid,
               ACCOUNT_ADJUST_PRIVILEGES,
               &AccountHandle
               );
   }

   // 
   // if an error occurred opening or creating, return
   // 
   if(Status != STATUS_SUCCESS) return Status;

   // 
   // add the privileges to the account
   // 
   Status=LsaAddPrivilegesToAccount(
           AccountHandle,
           &ps
           );

   LsaClose(AccountHandle);

   return Status;
}
				

這篇文章中的資訊適用於:
  • Microsoft Win32 Application Programming Interface?應用於:
    • Microsoft Windows NT 3.51 Service Pack 5
    • Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows 2000
關鍵字:?
kbmt kbapi kbhowto kbkernbase kblsa kbsecurity KB132958 KbMtzh
機器翻譯機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:132958? (http://support.microsoft.com/kb/132958/en-us/ )
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。