Использование GetTokenInformation в Visual Basic 6, чтобы определить, является ли пользователь администратором - PullRequest
2 голосов
/ 04 декабря 2009

Я использую GetTokenInformation как часть кода, который определяет, работает ли текущий поток как администратор.

В любом случае, у меня есть структура TOKEN INFORMATION, которая выглядит следующим образом:

Private Type TOKEN_GROUPS
   GroupCount As Long
   Groups(500) As SID_AND_ATTRIBUTES
End Type

Затем я вызываю GetTokenInformation следующим образом:

res = GetTokenInformation(<Process Handle>, 2, <TOKEN_GROUPS>, _
                            <Token Info Length>, <Buffer Length)

Первый вызов - получить длину буфера, затем я вызываю его снова, чтобы получить информацию о токене.

В любом случае приложение внезапно завершит работу, когда учетная запись, в которой запущено приложение, подключена к домену. По-видимому, размер групп (500) как SID.AND.ATTRIBUTES недостаточен и вызывает переполнение буфера. Я не знаю, почему это так (MSDN говорит, что я должен предоставить ANYSIZE_ARRAY или 1). Увеличение размера групп до 1000 устраняет проблему.

В качестве быстрого исправления , и поскольку у меня нет идеи о том, как получить соответствующий размер групп , я планирую просто переопределить группы, пока вызов не будет успешным.

Вот мой вопрос:

  1. У меня есть предложение On Error, но когда происходит переполнение буфера, On Error не может его перехватить, и мое приложение неожиданно падает. Почему это так?

  2. С учетом приведенного ниже кода

    Закрытый тип TOKEN_GROUPS GroupCount As Long Groups () как SID_AND_ATTRIBUTES 'FAILING 'Groups (1000), поскольку SID_AND_ATTRIBUTES НЕ ОТКАЗЫВАЕТСЯ Тип конца

    Dim X as TOKEN_GROUPS Восстановить Сохранение X.Groups (1000) как ОШИБКА SID_AND_ATTRIBUTES

    res = GetTokenInformation (, 2,,,

    res = GetTokenInformation (, 2,,,

Почему, когда я объявлял Группы как 1000, вызов GetTokenInformation не прерывался, но когда я объявлял "пустые" Группы () и переопределял его до 1000, это сбой?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 05 декабря 2009

Если вы хотите использовать динамически изменяемый массив для Groups, вам понадобится код "пользовательского маршалинга вызовов API". В основном пара CopyMemory's и размер массива

Option Explicit

'--- for OpenProcessToken
Private Const TOKEN_READ                    As Long = &H20008

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pTo As Any, uFrom As Any, ByVal lSize As Long)
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function GetTokenInformation Lib "advapi32.dll" (ByVal TokenHandle As Long, ByVal TokenInformationClass As Long, TokenInformation As Any, ByVal TokenInformationLength As Long, ReturnLength As Long) As Long

Private Type SID_AND_ATTRIBUTES
    Sid             As Long
    Attributes      As Long
End Type

Private Type VB_TOKEN_GROUPS
    GroupCount      As Long
    Groups()        As SID_AND_ATTRIBUTES
End Type


Private Sub Command1_Click()
    Dim hProcessID      As Long
    Dim hToken          As Long
    Dim lNeeded         As Long
    Dim baBuffer()      As Byte
    Dim uGroups         As VB_TOKEN_GROUPS

    hProcessID = GetCurrentProcess()
    If hProcessID <> 0 Then
        If OpenProcessToken(hProcessID, TOKEN_READ, hToken) = 1 Then
            Call GetTokenInformation(hToken, 2, ByVal 0, 0, lNeeded)
            ReDim baBuffer(0 To lNeeded)
            '--- enum TokenInformationClass { TokenUser = 1, TokenGroups = 2, ... }
            If GetTokenInformation(hToken, 2, baBuffer(0), UBound(baBuffer), lNeeded) = 1 Then
                Call CopyMemory(uGroups.GroupCount, baBuffer(0), 4)
                ReDim uGroups.Groups(0 To uGroups.GroupCount - 1)
                Call CopyMemory(uGroups.Groups(0), baBuffer(4), uGroups.GroupCount * Len(uGroups.Groups(0)))
            End If
            Call CloseHandle(hToken)
        End If
        Call CloseHandle(hProcessID)
    End If
End Sub
1 голос
/ 05 декабря 2009

Есть еще один вопрос здесь , который, кажется, решил вызов GetTokenInformation. Скопировано из принятого ответа:

Call GetTokenInformation(hToken, 1, ByVal 0, 0, lNeeded)
ReDim baBuffer(0 To lNeeded)
...
...