Πώς να επικυρώνει τις πιστοποιήσεις χρήστη σε λειτουργικά συστήματα της Microsoft

Μεταφράσεις άρθρων Μεταφράσεις άρθρων
Αναγν. άρθρου: 180548 - Δείτε τα προϊόντα στα οποία αναφέρεται το συγκεκριμένο άρθρο.
Ανάπτυξη όλων | Σύμπτυξη όλων

Σε αυτήν τη σελίδα

Περίληψη

Μερικές φορές, μπορεί να θέλετε μια εφαρμογή για να επαληθεύσετε ένα του χρήστη το όνομα χρήστη και τον κωδικό πρόσβασης (εφεξής πιστοποιήσεις). Μπορείτε να κάνετε αυτό σε δύο διαφορετικούς τρόπους, ανάλογα με το λειτουργικό σύστημα στο οποίο η εφαρμογή θα εκτελείται.

Αυτό το άρθρο περιγράφει όλους τους συνήθεις τρόπους Για να επαληθεύσετε τις πιστοποιήσεις του χρήστη και τις ειδικές απαιτήσεις για κάθε μέθοδο.

ΣημείωσηΣυλλογή πιστοποιήσεις χρήστη από μια εφαρμογή λειτουργίας χρήστη μπορεί να είναι ενοχλητικά στους χρήστες και να παρέχετε μια οπή δυνατή ασφάλεια σε το εταιρικό περιβάλλον υπολογιστών. Η απαίτηση της ενοποιημένης σύνδεσης (απαίτηση ότι ο χρήστης πρέπει μόνο να απαιτείται να πληκτρολογήσετε τις πιστοποιήσεις τους μία φορά κατά την Προστέθηκε η οθόνη CTRL + ALT + DEL), τις απαιτήσεις του λογότυπου του Microsoft BackOffice για αυτούς τους λόγους πολύ. Είναι σημαντικό να βεβαιωθείτε ότι χρειάζεστε πραγματικά να Συγκεντρώστε τις πιστοποιήσεις και ότι είναι κάποια άλλη μέθοδο επικύρωσης του προγράμματος-πελάτη/διακομιστή δεν είναι πλέον κατάλληλη. Ανατρέξτε στην τεκμηρίωση ασφαλείας στην πλατφόρμα SDK της Για περισσότερες πληροφορίες σχετικά με τις απομιμήσεις και προγραμματισμού τους ασφαλείς διακομιστές.

Περισσότερες πληροφορίες

ΤοΗ σύνδεση χρήστηAPI είναι διαθέσιμο και τεκμηριώνεται από το Windows NT 3.51, και χρησιμοποιείται συνήθως για την επαλήθευση των διαπιστευτηρίων χρήστη. Αυτό το API είναι διαθέσιμο στα Windows NT, τα Windows 2000 και Windows XP. Δυστυχώς, υπάρχουν ορισμένοι περιορισμοί στη χρήση η σύνδεση χρήστη που δεν είναι πάντα εύκολο να ικανοποιήσει.

Η πρώτη και μεγαλύτερες των περιορισμών αυτών είναι ότι τα Windows NT και Windows 2000, το η σύνδεση χρήστη τον οποίο καλεί η διαδικασία πρέπει να έχετε το δικαίωμα SE_TCB_NAME (στο χρήστη Διαχείριση, αυτό είναι το δικαίωμα "Ενεργεί ως μέρος του λειτουργικού συστήματος"). Το Δικαίωμα SE_TCB_NAME είναι πολύ ισχυρή και δεν θα πρέπει να χορηγείται σε οποιοδήποτε απλώς, έτσι ώστε αυτά να εκτελέσετε μια εφαρμογή που χρειάζεται για να επικυρώσετε αυθαίρετος χρήστης Οι πιστοποιήσεις. Η προτεινόμενη μέθοδος είναι να καλέσει η σύνδεση χρήστη από μια υπηρεσία που είναι εκτελούνται στο λογαριασμό τοπικού συστήματος, επειδή ήδη του λογαριασμού τοπικού συστήματος έχει το δικαίωμα SE_TCB_NAME.

ΣημείωσηΗ σύνδεση χρήστη Win32 API δεν απαιτεί δικαιωμάτων TCB Απέτυχε στη Microsoft Windows Server 2003, ωστόσο, για συμβατότητα με προηγούμενη έκδοση, αυτό είναι ακόμα το καλύτερη προσέγγιση.

Στα Windows XP, δεν είναι πλέον απαραίτητη που μια διαδικασία Για να καλέσετε η σύνδεση χρήστη, έχετε το δικαίωμα SE_TCB_NAME. Επομένως, το είναι η απλούστερη μέθοδος για να επικυρώσει τις πιστοποιήσεις του χρήστη στα Windows XP, για να καλέσετε το Η σύνδεση χρήστη API.

Ένα άλλο πρόβλημα με η σύνδεση χρήστη είναι ότι είναι το API δεν εφαρμόζεται για τα Windows 95, Windows 98 ή Windows Millennium Edition.

Μια άλλη επιλογή, μπορείτε να χρησιμοποιήσετε την υπηρεσία παροχής υποστήριξης ασφάλειας Για να κάνετε μια σύνδεση δικτύου στυλ με πιστοποιήσεις χρήστη υπό τον όρο ότι η διασύνδεση (SSPI). Αυτή η μέθοδος επικύρωσης έχει το πλεονέκτημα ότι δεν απαιτούν από όλους τους ειδικούς το δικαίωμα, καθώς και λειτουργεί σε όλες τις εκδόσεις των Windows. Το τελικό αποτέλεσμα της χρήση των υπηρεσιών SSPI για την επικύρωση των πιστοποιήσεων είναι μια σύνδεση που είναι ανάλογη με την κλήση του API η σύνδεση χρήστη με τη σύνδεση LOGON32_LOGON_NETWORK Τύπος. Το μεγαλύτερο μειονέκτημα σε αυτόν τον τύπο σύνδεσης είναι ότι δεν έχετε πρόσβαση απομακρυσμένο δίκτυο πόρους μετά την απομίμηση ενός τύπου σύνδεση στο δίκτυο. Εάν σας εφαρμογή καλεί η σύνδεση χρήστη με τον τύπο σύνδεσης LOGON32_LOGON_INTERACTIVE Για να επιλύσετε τα Windows NT ανικανότητα να εκτελέσει αντιπροσώπευση, τότε το SSPI Επαλήθευση σύνδεσης/μάλλον δεν θα είναι μια βιώσιμη εναλλακτική λύση.

Το δείγμα κώδικα που παρέχεται παρακάτω δείχνει πώς μπορείτε να καλέσετε τις υπηρεσίες SSPI για την εκτέλεση επικύρωση διαπιστευτηρίων.

Για να χρησιμοποιήσετε αυτήν τη μέθοδο στον Windows 95, Windows 98, και τα Windows Millennium Edition, πρέπει επίσης να ενεργοποιήσετε την ασφάλεια NTLM υπηρεσίες ανοίγοντας τον πίνακα ελέγχου, δικτύου, έλεγχος πρόσβασης και, στη συνέχεια, επιλέγοντας Έλεγχος πρόσβασης σε επίπεδο χρήστη.

Στα Windows XP, του μητρώου ForceGuest η τιμή ορίζεται σε 1, από προεπιλογή στο ακόλουθο κλειδί μητρώου:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
Σε έναν υπολογιστή με Windows XP που είναι μέλος μιας ομάδας εργασίας:
  • Εάν είναι ενεργοποιημένη η ForceGuest (Ορισμός 1), θα προσπαθούν πάντα SSPI Για να συνδεθείτε χρησιμοποιώντας το λογαριασμό Guest.
  • Εάν ο λογαριασμός Guest είναι ενεργοποιημένος, θα επιτύχει μια σύνδεση SSPI με το λογαριασμό Guest γιαοποιαδήποτεΟι πιστοποιήσεις χρήστη.
  • Εάν ο λογαριασμός Guest είναι απενεργοποιημένος, θα αποτύχει μια σύνδεση SSPI ακόμη και για έγκυρα διαπιστευτήρια.
  • Εάν απενεργοποιηθεί ForceGuest (ρυθμισμένα στο 0), θα συνδεθείτε SSPI ως ο καθορισμένος χρήστης.
Επιπλέον, εάν ο λογαριασμός Guest είναι ενεργοποιημένος, SSPI σύνδεσης μπορεί να επιτύχει ως Guest πιστοποιήσεις χρήστη που δεν είναι έγκυρες. C δείγμα κώδικα σε αυτό το άρθρο περιγράφει πώς μπορείτε να ελέγξετε το διακριτικό πρόσβασης του περιβάλλοντος ασφαλείας που δημιουργήθηκε. ΤοIsGuestσυνάρτηση Βοήθειας στο δείγμα κώδικα δείχνει πώς μπορείτε να επαληθεύσετε ότι η διαδικασία σύνδεσης Παρουσιάστηκε ως ο συγκεκριμένος χρήστης ή με το λογαριασμό Guest.

Δείγμα κώδικα

///////////////////////////////////////////////////////////////////////////////
//
//  SSPI Authentication Sample
//
//  This program demonstrates how to use SSPI to authenticate user credentials.
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
//  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
//  Copyright (C) 2007.  Microsoft Corporation.  All rights reserved.
///////////////////////////////////////////////////////////////////////////////

#define SECURITY_WIN32
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#include <sspi.h>
#include <lm.h>
#include <lmcons.h>

// Older versions of WinError.h do not have SEC_I_COMPLETE_NEEDED #define.
// So, in such an SDK environment setup, we will include issperr.h which has the
// definition for SEC_I_COMPLETE_NEEDED. Include issperr.h only if
// SEC_I_COMPLETE_NEEDED is not defined.
#ifndef SEC_I_COMPLETE_NEEDED
#include <issperr.h>
#endif

typedef struct _AUTH_SEQ {
   BOOL fInitialized;
   BOOL fHaveCredHandle;
   BOOL fHaveCtxtHandle;
   CredHandle hcred;
   struct _SecHandle hctxt;
} AUTH_SEQ, *PAUTH_SEQ;


// Function pointers
ACCEPT_SECURITY_CONTEXT_FN       _AcceptSecurityContext     = NULL;
ACQUIRE_CREDENTIALS_HANDLE_FN    _AcquireCredentialsHandle  = NULL;
COMPLETE_AUTH_TOKEN_FN           _CompleteAuthToken         = NULL;
DELETE_SECURITY_CONTEXT_FN       _DeleteSecurityContext     = NULL;
FREE_CONTEXT_BUFFER_FN           _FreeContextBuffer         = NULL;
FREE_CREDENTIALS_HANDLE_FN       _FreeCredentialsHandle     = NULL;
INITIALIZE_SECURITY_CONTEXT_FN   _InitializeSecurityContext = NULL;
QUERY_SECURITY_PACKAGE_INFO_FN   _QuerySecurityPackageInfo  = NULL;
QUERY_SECURITY_CONTEXT_TOKEN_FN  _QuerySecurityContextToken = NULL;


#define CheckAndLocalFree(ptr) \
            if (ptr != NULL) \
            { \
               LocalFree(ptr); \
               ptr = NULL; \
            }

#pragma comment(lib, "netapi32.lib")

LPVOID RetrieveTokenInformationClass(
      HANDLE hToken,
      TOKEN_INFORMATION_CLASS InfoClass,
      LPDWORD lpdwSize)
{
   LPVOID pInfo = NULL;
   BOOL fSuccess = FALSE;

   __try
   {
      *lpdwSize = 0;

      //
      // Determine the size of the buffer needed
      //

      GetTokenInformation(
            hToken,
            InfoClass,
            NULL,
            *lpdwSize, lpdwSize);
      if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
      {
         _tprintf(_T("GetTokenInformation failed with %d\n"), GetLastError());
         __leave;
      }

      //
      // Allocate a buffer for getting token information
      //
      pInfo = LocalAlloc(LPTR, *lpdwSize);
      if (pInfo == NULL)
      {
         _tprintf(_T("LocalAlloc failed with %d\n"), GetLastError());
         __leave;
      }

      if (!GetTokenInformation(
            hToken,
            InfoClass,
            pInfo,
            *lpdwSize, lpdwSize))
      {
         _tprintf(_T("GetTokenInformation failed with %d\n"), GetLastError());
         __leave;
      }

      fSuccess = TRUE;
   }
   __finally
   {
      // Free pDomainAndUserName only if failed
      // Otherwise, the caller has to free after use
      if (fSuccess == FALSE)
      {
         CheckAndLocalFree(pInfo);
      }
   }

   return pInfo;
}

PSID GetUserSidFromWellKnownRid(DWORD Rid)
{
    PUSER_MODALS_INFO_2 umi2;
    NET_API_STATUS nas;

    UCHAR SubAuthorityCount;
    PSID pSid = NULL;

    BOOL bSuccess = FALSE; // assume failure

    nas = NetUserModalsGet(NULL, 2, (LPBYTE *)&umi2);

    if (nas != NERR_Success)
    {
        printf("NetUserModalsGet failed with error code : [%d]\n", nas);
        SetLastError(nas);
        return NULL;
    }

    SubAuthorityCount = *GetSidSubAuthorityCount
                       (umi2->usrmod2_domain_id);

    // 
    // Allocate storage for new Sid. account domain Sid + account Rid
    // 

    pSid = (PSID)LocalAlloc(LPTR,
          GetSidLengthRequired((UCHAR)(SubAuthorityCount + 1)));

    if (pSid != NULL)
    {
        if (InitializeSid(
              pSid,
              GetSidIdentifierAuthority(umi2->usrmod2_domain_id),
              (BYTE)(SubAuthorityCount+1)
              ))
        {
            DWORD SubAuthIndex = 0;

            // 
            // Copy existing subauthorities from account domain Sid into
            // new Sid
            // 

            for (; SubAuthIndex < SubAuthorityCount ; SubAuthIndex++)
            {
                *GetSidSubAuthority(pSid, SubAuthIndex) =
                *GetSidSubAuthority(umi2->usrmod2_domain_id,
                                  SubAuthIndex);
            }

            // 
            // Append Rid to new Sid
            // 

            *GetSidSubAuthority(pSid, SubAuthorityCount) = Rid;
        }
    }

    NetApiBufferFree(umi2);

    return pSid;
}

BOOL IsGuest(HANDLE hToken)
{
    BOOL fGuest = FALSE;
    PSID pGuestSid = NULL;
    PSID pUserSid = NULL;
    TOKEN_USER *pUserInfo = NULL;
    DWORD dwSize = 0;

    pGuestSid = GetUserSidFromWellKnownRid(DOMAIN_USER_RID_GUEST);
    if (pGuestSid == NULL)
        return fGuest;

    //
    // Get user information
    //

    pUserInfo = (TOKEN_USER *)RetrieveTokenInformationClass(hToken, TokenUser, &dwSize);
    if (pUserInfo != NULL)
    {
        if (EqualSid(pGuestSid, pUserInfo->User.Sid))
            fGuest = TRUE;
    }

    CheckAndLocalFree(pUserInfo);
    CheckAndLocalFree(pGuestSid);

    return fGuest;
}

///////////////////////////////////////////////////////////////////////////////


void UnloadSecurityDll(HMODULE hModule) {

   if (hModule)
      FreeLibrary(hModule);

   _AcceptSecurityContext      = NULL;
   _AcquireCredentialsHandle   = NULL;
   _CompleteAuthToken          = NULL;
   _DeleteSecurityContext      = NULL;
   _FreeContextBuffer          = NULL;
   _FreeCredentialsHandle      = NULL;
   _InitializeSecurityContext  = NULL;
   _QuerySecurityPackageInfo   = NULL;
   _QuerySecurityContextToken  = NULL;
}


///////////////////////////////////////////////////////////////////////////////


HMODULE LoadSecurityDll() {

   HMODULE hModule;
   BOOL    fAllFunctionsLoaded = FALSE;
   TCHAR   lpszDLL[MAX_PATH];
   OSVERSIONINFO VerInfo;

   //
   //  Find out which security DLL to use, depending on
   //  whether we are on Windows NT or Windows 95, Windows 2000, Windows XP, or Windows Server 2003
   //  We have to use security.dll on Windows NT 4.0.
   //  All other operating systems, we have to use Secur32.dll
   //
   VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
   if (!GetVersionEx (&VerInfo))   // If this fails, something has gone wrong
   {
      return FALSE;
   }

   if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
      VerInfo.dwMajorVersion == 4 &&
      VerInfo.dwMinorVersion == 0)
   {
      lstrcpy (lpszDLL, _T("security.dll"));
   }
   else
   {
      lstrcpy (lpszDLL, _T("secur32.dll"));
   }


   hModule = LoadLibrary(lpszDLL);
   if (!hModule)
      return NULL;

   __try {

      _AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN)
            GetProcAddress(hModule, "AcceptSecurityContext");
      if (!_AcceptSecurityContext)
         __leave;

#ifdef UNICODE
      _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
            GetProcAddress(hModule, "AcquireCredentialsHandleW");
#else
      _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
            GetProcAddress(hModule, "AcquireCredentialsHandleA");
#endif
      if (!_AcquireCredentialsHandle)
         __leave;

      // CompleteAuthToken is not present on Windows 9x Secur32.dll
      // Do not check for the availablity of the function if it is NULL;
      _CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN)
            GetProcAddress(hModule, "CompleteAuthToken");

      _DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN)
            GetProcAddress(hModule, "DeleteSecurityContext");
      if (!_DeleteSecurityContext)
         __leave;

      _FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN)
            GetProcAddress(hModule, "FreeContextBuffer");
      if (!_FreeContextBuffer)
         __leave;

      _FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN)
            GetProcAddress(hModule, "FreeCredentialsHandle");
      if (!_FreeCredentialsHandle)
         __leave;

#ifdef UNICODE
      _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
            GetProcAddress(hModule, "InitializeSecurityContextW");
#else
      _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
            GetProcAddress(hModule, "InitializeSecurityContextA");
#endif
      if (!_InitializeSecurityContext)
         __leave;

#ifdef UNICODE
      _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
            GetProcAddress(hModule, "QuerySecurityPackageInfoW");
#else
      _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
            GetProcAddress(hModule, "QuerySecurityPackageInfoA");
#endif
      if (!_QuerySecurityPackageInfo)
         __leave;


      _QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN)
            GetProcAddress(hModule, "QuerySecurityContextToken");
      if (!_QuerySecurityContextToken)
         __leave;

      fAllFunctionsLoaded = TRUE;

   } __finally {

      if (!fAllFunctionsLoaded) {
         UnloadSecurityDll(hModule);
         hModule = NULL;
      }

   }

   return hModule;
}


///////////////////////////////////////////////////////////////////////////////


BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity,
      PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) {

/*++

 Routine Description:

   Optionally takes an input buffer coming from the server and returns
   a buffer of information to send back to the server.  Also returns
   an indication of whether or not the context is complete.

 Return Value:

   Returns TRUE if successful; otherwise FALSE.

--*/

   SECURITY_STATUS ss;
   TimeStamp       tsExpiry;
   SecBufferDesc   sbdOut;
   SecBuffer       sbOut;
   SecBufferDesc   sbdIn;
   SecBuffer       sbIn;
   ULONG           fContextAttr;

   if (!pAS->fInitialized) {

      ss = _AcquireCredentialsHandle(NULL, _T("NTLM"),
            SECPKG_CRED_OUTBOUND, NULL, pAuthIdentity, NULL, NULL,
            &pAS->hcred, &tsExpiry);
      if (ss < 0) {
         fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss);
         return FALSE;
      }

      pAS->fHaveCredHandle = TRUE;
   }

   // Prepare output buffer
   sbdOut.ulVersion = 0;
   sbdOut.cBuffers = 1;
   sbdOut.pBuffers = &sbOut;

   sbOut.cbBuffer = *pcbOut;
   sbOut.BufferType = SECBUFFER_TOKEN;
   sbOut.pvBuffer = pOut;

   // Prepare input buffer
   if (pAS->fInitialized)  {
      sbdIn.ulVersion = 0;
      sbdIn.cBuffers = 1;
      sbdIn.pBuffers = &sbIn;

      sbIn.cbBuffer = cbIn;
      sbIn.BufferType = SECBUFFER_TOKEN;
      sbIn.pvBuffer = pIn;
   }

   ss = _InitializeSecurityContext(&pAS->hcred,
         pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0,
         SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL,
         0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry);
   if (ss < 0)  {
      // <winerror.h>
      fprintf(stderr, "InitializeSecurityContext failed with %08X\n", ss);
      return FALSE;
   }

   pAS->fHaveCtxtHandle = TRUE;

   // If necessary, complete token
   if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) {

      if (_CompleteAuthToken) {
         ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
         if (ss < 0)  {
            fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss);
            return FALSE;
         }
      }
      else {
         fprintf (stderr, "CompleteAuthToken not supported.\n");
         return FALSE;
      }
   }

   *pcbOut = sbOut.cbBuffer;

   if (!pAS->fInitialized)
      pAS->fInitialized = TRUE;

   *pfDone = !(ss == SEC_I_CONTINUE_NEEDED
         || ss == SEC_I_COMPLETE_AND_CONTINUE );

   return TRUE;
}


///////////////////////////////////////////////////////////////////////////////


BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut,
      PDWORD pcbOut, PBOOL pfDone) {

/*++

 Routine Description:

    Takes an input buffer coming from the client and returns a buffer
    to be sent to the client.  Also returns an indication of whether or
    not the context is complete.

 Return Value:

    Returns TRUE if successful; otherwise FALSE.

--*/

   SECURITY_STATUS ss;
   TimeStamp       tsExpiry;
   SecBufferDesc   sbdOut;
   SecBuffer       sbOut;
   SecBufferDesc   sbdIn;
   SecBuffer       sbIn;
   ULONG           fContextAttr;

   if (!pAS->fInitialized)  {

      ss = _AcquireCredentialsHandle(NULL, _T("NTLM"),
            SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred,
            &tsExpiry);
      if (ss < 0) {
         fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss);
         return FALSE;
      }

      pAS->fHaveCredHandle = TRUE;
   }

   // Prepare output buffer
   sbdOut.ulVersion = 0;
   sbdOut.cBuffers = 1;
   sbdOut.pBuffers = &sbOut;

   sbOut.cbBuffer = *pcbOut;
   sbOut.BufferType = SECBUFFER_TOKEN;
   sbOut.pvBuffer = pOut;

   // Prepare input buffer
   sbdIn.ulVersion = 0;
   sbdIn.cBuffers = 1;
   sbdIn.pBuffers = &sbIn;

   sbIn.cbBuffer = cbIn;
   sbIn.BufferType = SECBUFFER_TOKEN;
   sbIn.pvBuffer = pIn;

   ss = _AcceptSecurityContext(&pAS->hcred,
         pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, 0,
         SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr,
         &tsExpiry);
   if (ss < 0)  {
      fprintf(stderr, "AcceptSecurityContext failed with %08X\n", ss);
      return FALSE;
   }

   pAS->fHaveCtxtHandle = TRUE;

   // If necessary, complete token
   if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) {

      if (_CompleteAuthToken) {
         ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
         if (ss < 0)  {
            fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss);
            return FALSE;
         }
      }
      else {
         fprintf (stderr, "CompleteAuthToken not supported.\n");
         return FALSE;
      }
   }

   *pcbOut = sbOut.cbBuffer;

   if (!pAS->fInitialized)
      pAS->fInitialized = TRUE;

   *pfDone = !(ss == SEC_I_CONTINUE_NEEDED
         || ss == SEC_I_COMPLETE_AND_CONTINUE);

   return TRUE;
}


///////////////////////////////////////////////////////////////////////////////


BOOL WINAPI SSPLogonUser(LPTSTR szDomain, LPTSTR szUser, LPTSTR szPassword) {

   AUTH_SEQ    asServer   = {0};
   AUTH_SEQ    asClient   = {0};
   BOOL        fDone      = FALSE;
   BOOL        fResult    = FALSE;
   DWORD       cbOut      = 0;
   DWORD       cbIn       = 0;
   DWORD       cbMaxToken = 0;
   PVOID       pClientBuf = NULL;
   PVOID       pServerBuf = NULL;
   PSecPkgInfo pSPI       = NULL;
   HMODULE     hModule    = NULL;

   SEC_WINNT_AUTH_IDENTITY ai;

   __try {

      hModule = LoadSecurityDll();
      if (!hModule)
         __leave;

      // Get max token size
      _QuerySecurityPackageInfo(_T("NTLM"), &pSPI);
      cbMaxToken = pSPI->cbMaxToken;
      _FreeContextBuffer(pSPI);

      // Allocate buffers for client and server messages
      pClientBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken);
      pServerBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken);

      // Initialize auth identity structure
      ZeroMemory(&ai, sizeof(ai));
#if defined(UNICODE) || defined(_UNICODE)
      ai.Domain = szDomain;
      ai.DomainLength = lstrlen(szDomain);
      ai.User = szUser;
      ai.UserLength = lstrlen(szUser);
      ai.Password = szPassword;
      ai.PasswordLength = lstrlen(szPassword);
      ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
      ai.Domain = (unsigned char *)szDomain;
      ai.DomainLength = lstrlen(szDomain);
      ai.User = (unsigned char *)szUser;
      ai.UserLength = lstrlen(szUser);
      ai.Password = (unsigned char *)szPassword;
      ai.PasswordLength = lstrlen(szPassword);
      ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif

      // Prepare client message (negotiate) .
      cbOut = cbMaxToken;
      if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone))
         __leave;

      // Prepare server message (challenge) .
      cbIn = cbOut;
      cbOut = cbMaxToken;
      if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
            &fDone))
         __leave;
         // Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED
         // in the case of bad szUser or szPassword.
         // Unexpected Result: Logon will succeed if you pass in a bad szUser and
         // the guest account is enabled in the specified domain.

      // Prepare client message (authenticate) .
      cbIn = cbOut;
      cbOut = cbMaxToken;
      if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut,
            &fDone))
         __leave;

      // Prepare server message (authentication) .
      cbIn = cbOut;
      cbOut = cbMaxToken;
      if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
            &fDone))
         __leave;

      fResult = TRUE;

      {
         HANDLE hToken = NULL;

         if (_QuerySecurityContextToken(&asServer.hctxt, &hToken) == 0)
         {
            if (IsGuest(hToken))
            {
               printf("Logged in as Guest\n");
               fResult = FALSE;
            }
            else
               printf("Logged in as the desired user\n");
            CloseHandle(hToken);
         }
      }


   } __finally {

      // Clean up resources
      if (asClient.fHaveCtxtHandle)
         _DeleteSecurityContext(&asClient.hctxt);

      if (asClient.fHaveCredHandle)
         _FreeCredentialsHandle(&asClient.hcred);

      if (asServer.fHaveCtxtHandle)
         _DeleteSecurityContext(&asServer.hctxt);

      if (asServer.fHaveCredHandle)
         _FreeCredentialsHandle(&asServer.hcred);

      if (hModule)
         UnloadSecurityDll(hModule);

      HeapFree(GetProcessHeap(), 0, pClientBuf);
      HeapFree(GetProcessHeap(), 0, pServerBuf);

   }

   return fResult;
}

//--------------------------------------------------------------------
// The GetConsoleInput function gets an array of characters from the 
// keyboard, while printing only asterisks to the screen.

void GetConsoleInput(TCHAR* strInput, int intMaxChars)
{
	char ch;
	char minChar = ' ';
	minChar++;

	ch = getch();
	while (ch != '\r')
	{
		if (ch == '\b' && strlen(strInput) > 0)
		{
			strInput[strlen(strInput)-1]   = '\0';
			printf("\b \b");
		}
		else if (ch >= minChar && (int)strlen(strInput) < intMaxChars)
		{
			strInput[strlen(strInput)+1] = '\0';
			strInput[strlen(strInput)]   = ch;
			putch('*');
		}
		ch = getch();
	}
	putch('\n');
}

void _tmain(int argc, TCHAR **argv)
{
	TCHAR password[PWLEN+1];

   if (argc != 3) 
	{
		_tprintf(_T("Usage: %s DomainName UserName\n"), argv[0]);
		return;
	}

	_tprintf(_T("Enter password for the specified user : "));
	password[0] = 0;
	GetConsoleInput(password, PWLEN);
	_tprintf(_T("\n"));
   // argv[1] - Domain Name
   // argv[2] - User Name
   if (SSPLogonUser(argv[1], argv[2], password))
   {
      _tprintf(_T("User Credentials are valid\n"));
   }
   else
      _tprintf(_T("User Credentials are NOT valid\n"));
}

Ιδιότητες

Αναγν. άρθρου: 180548 - Τελευταία αναθεώρηση: Πέμπτη, 27 Ιανουαρίου 2011 - Αναθεώρηση: 4.0
Οι πληροφορίες σε αυτό το άρθρο ισχύουν για:
  • Microsoft Win32 Application Programming Interface στις ακόλουθες πλατφόρμες
    • Microsoft Windows 98 Standard Edition
    • Microsoft Windows Millennium Edition
Λέξεις-κλειδιά: 
kbapi kbFAQ kbhowto kbkernbase kbsecurity kbmt KB180548 KbMtel
Μηχανικά μεταφρασμένο
ΣΗΜΑΝΤΙΚΟ: Αυτό το άρθρο είναι προϊόν λογισμικού μηχανικής μετάφρασης της Microsoft και όχι ανθρώπινης μετάφρασης. Η Microsoft σάς προσφέρει άρθρα που είναι προϊόντα ανθρώπινης αλλά και μηχανικής μετάφρασης έτσι ώστε να έχετε πρόσβαση σε όλα τα άρθρα της Γνωσιακής Βάσης μας στη δική σας γλώσσα. Ωστόσο, ένα άρθρο που έχει προκύψει από μηχανική μετάφραση δεν είναι πάντα άριστης ποιότητας. Ενδέχεται να περιέχει λεξιλογικά, συντακτικά ή γραμματικά λάθη, όπως ακριβώς τα λάθη που θα έκανε ένας μη φυσικός ομιλητής επιχειρώντας να μιλήσει τη γλώσσα σας. Η Microsoft δεν φέρει καμία ευθύνη για τυχόν ανακρίβειες, σφάλματα ή ζημίες που προκύψουν λόγω τυχόν παρερμηνειών στη μετάφραση του περιεχομένου ή χρήσης του από τους πελάτες της. Επίσης, η Microsoft πραγματοποιεί συχνά ενημερώσεις στο λογισμικό μηχανικής μετάφρασης.
Η αγγλική έκδοση αυτού του άρθρου είναι η ακόλουθη:180548

Αποστολή σχολίων

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com