sspi for NTLM or Kerberos

代码
  1 /*
  2 You can get a locally valid logon session (a network logon session) by using SSPI.
  3 Simply specify alternate credentials when you call AcquireCredentialsHandle,
  4 and then after you follow the normal InitializeSecurityContext/AcceptSecurityContext
  5 handshake, you'll end up with a logon session for the user,
  6 without having to have the TCB privilege.
  7 
  8 See the attached example...
  9 
 10 Keith
 11   */
 12 
 13 // this version requires Windows 2000
 14 #define _WIN32_WINNT 0x500
 15 #define UNICODE
 16 #include <windows.h>
 17 #include <stdio.h>
 18 #define SECURITY_WIN32
 19 #include <security.h>
 20 #pragma comment(lib, "secur32.lib")
 21 
 22 // brain-dead error routine that dumps the last error and exits
 23 void _err(const wchar_t* pszFcn, DWORD nErr = GetLastError())
 24 {
 25  
 26     wchar_t szErr[256];
 27     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, nErr, 0,
 28                       szErr, sizeof szErr / sizeof *szErr, 0))
 29          wprintf(L"%s failed: %s", pszFcn, szErr);
 30     else wprintf(L"%s failed: 0x%08X", nErr);
 31     exit(1);
 32 }
 33 
 34 // Upon success, returns a handle to a NETWORK logon session
 35 // for the specified principal (it will *not* have network
 36 // credentials). Call CloseHandle to dispose of it when
 37 // you are finished.
 38 HANDLE _logonUserWithSSPI(wchar_t* pszSSP,
 39                           DWORD grfDesiredAccessToToken,
 40                           wchar_t* pszAuthority,
 41                           wchar_t* pszPrincipal,
 42                           wchar_t* pszPassword) {
 43 
 44     // the following code loads the SSPI interface DLL
 45     // and initializes it, getting a table of function ptrs
 46     HINSTANCE hdll = LoadLibrary(L"security.dll");
 47     if (!hdll)
 48         _err(L"LoadLibrary");
 49     INIT_SECURITY_INTERFACE_W initSecurityInterface =
 50             (INIT_SECURITY_INTERFACE_W)GetProcAddress(hdll,
 51                 SECURITY_ENTRYPOINT_ANSIW);
 52     if (!initSecurityInterface)
 53         _err(L"GetProcAddress");
 54     PSecurityFunctionTable pSSPI = initSecurityInterface();
 55 
 56     // here's where we specify the credentials to verify
 57     SEC_WINNT_AUTH_IDENTITY_EX authIdent = {
 58         SEC_WINNT_AUTH_IDENTITY_VERSION,
 59         sizeof authIdent,
 60         pszPrincipal, lstrlenW(pszPrincipal),
 61         pszAuthority, lstrlenW(pszAuthority),
 62         pszPassword,  lstrlenW(pszPassword),
 63         SEC_WINNT_AUTH_IDENTITY_UNICODE,
 64         00
 65     };
 66 
 67     // get an SSPI handle for these credentials
 68     CredHandle hcredClient;
 69     TimeStamp expiryClient;
 70     SECURITY_STATUS err =
 71         pSSPI->AcquireCredentialsHandle(0, pszSSP,
 72                                         SECPKG_CRED_OUTBOUND,
 73                                         0&authIdent,
 74                                         00,
 75                                         &hcredClient,
 76                                         &expiryClient);
 77     if (err)
 78         _err(L"AcquireCredentialsHandle for client", err);
 79 
 80     // use the caller's credentials for the server
 81     CredHandle hcredServer;
 82     TimeStamp expiryServer;
 83     err = pSSPI->AcquireCredentialsHandle(0, pszSSP,
 84                                           SECPKG_CRED_INBOUND,
 85                                           0000,
 86                                           &hcredServer,
 87                                           &expiryServer);
 88     if (err)
 89         _err(L"AcquireCredentialsHandle for server", err);
 90 
 91     CtxtHandle hctxClient;
 92     CtxtHandle hctxServer;
 93 
 94     // create two buffers:
 95     //    one for the client sending tokens to the server,
 96     //    one for the server sending tokens to the client
 97     // (buffer size chosen based on current Kerb SSP setting
 98     //  for cbMaxToken - you may need to adjust this)
 99     BYTE bufC2S[8000];
100     BYTE bufS2C[8000];
101     SecBuffer sbufC2S = { sizeof bufC2S, SECBUFFER_TOKEN, bufC2S };
102     SecBuffer sbufS2C = { sizeof bufS2C, SECBUFFER_TOKEN, bufS2C };
103     SecBufferDesc bdC2S = { SECBUFFER_VERSION, 1&sbufC2S };
104     SecBufferDesc bdS2C = { SECBUFFER_VERSION, 1&sbufS2C };
105 
106     // don't really need any special context attributes
107     DWORD grfRequiredCtxAttrsClient = ISC_REQ_DATAGRAM;//ISC_REQ_DELEGATE
108     DWORD grfRequiredCtxAttrsServer = ASC_REQ_DATAGRAM;
109 
110     // set up some aliases to make it obvious what's happening
111     PCtxtHandle    pClientCtxHandleIn  = 0;
112     PCtxtHandle    pClientCtxHandleOut = &hctxClient;
113     PCtxtHandle    pServerCtxHandleIn  = 0;
114     PCtxtHandle    pServerCtxHandleOut = &hctxServer;
115     SecBufferDesc* pClientInput  = 0;
116     SecBufferDesc* pClientOutput = &bdC2S;
117     SecBufferDesc* pServerInput  = &bdC2S;
118     SecBufferDesc* pServerOutput = &bdS2C;
119     DWORD          grfCtxAttrsClient = 0;
120     DWORD          grfCtxAttrsServer = 0;
121     TimeStamp      expiryClientCtx;
122     TimeStamp      expiryServerCtx;
123 
124     // since the caller is acting as the server, we need
125     // a server principal name so that the client will
126     // be able to get a Kerb ticket (if Kerb is used)
127     wchar_t szSPN[256]={0};
128     ULONG cchSPN = sizeof szSPN / sizeof *szSPN;
129     GetUserNameEx(NameSamCompatible, szSPN, &cchSPN);
130  
131  //sevice class / host: port / service instance
132  
133 // wcscpy (szSPN, TEXT("192.168.1.11"));
134 // wcscpy (szSPN, TEXT("testwork-AD11.testwork.com"));
135 // wcscpy (szSPN, TEXT("192.168.1.11"));
136 // wcscpy (szSPN, TEXT("TESTWORK\\administrator"));
137 // wcscpy (szSPN, TEXT("..."));
138  printf("%ws\n",szSPN);
139     // perform the authentication handshake, playing the
140     // role of both client *and* server.
141     bool bClientContinue = true;
142     bool bServerContinue = true;
143  int count=1;
144     while (bClientContinue || bServerContinue) {
145   
146         if (bClientContinue) {
147    
148             sbufC2S.cbBuffer = sizeof bufC2S;
149             err = pSSPI->InitializeSecurityContext(
150                 &hcredClient, pClientCtxHandleIn,
151                 szSPN,
152                 grfRequiredCtxAttrsClient,
153                 0, SECURITY_NETWORK_DREP,
154                 pClientInput, 0,
155                 pClientCtxHandleOut,
156                 pClientOutput,
157                 &grfCtxAttrsClient,
158                 &expiryClientCtx);
159             switch (err) {
160                 case 0:
161                     bClientContinue = false;
162                     break;
163                 case SEC_I_CONTINUE_NEEDED:
164                     pClientCtxHandleIn = pClientCtxHandleOut;
165                     pClientInput       = pServerOutput;
166                     break;
167                 default:
168      printf("err=%x\n",err);
169                     _err(L"InitializeSecurityContext", err);
170             }
171         }
172 
173         if (bServerContinue) {
174             sbufS2C.cbBuffer = sizeof bufS2C;
175             err = pSSPI->AcceptSecurityContext(
176                 &hcredServer, pServerCtxHandleIn,
177                 pServerInput,
178                 grfRequiredCtxAttrsServer,
179                 SECURITY_NETWORK_DREP,
180                 pServerCtxHandleOut,
181                 pServerOutput,
182                 &grfCtxAttrsServer,
183                 &expiryServerCtx);
184             switch (err) {
185                 case 0:
186                     bServerContinue = false;
187                     break;
188                 case SEC_I_CONTINUE_NEEDED:
189                     pServerCtxHandleIn = pServerCtxHandleOut;
190                     break;
191                 default:
192                     _err(L"AcceptSecurityContext", err);
193             }
194         }
195   printf("%d bClientContinue %d bServerContinue %d\n",count++,bClientContinue,bServerContinue);
196     }
197     // if everything has gone smoothly, we've now got a logon
198     // session for the client - let's grab the token now
199     pSSPI->ImpersonateSecurityContext(pServerCtxHandleOut);
200     HANDLE htok;
201     if (!OpenThreadToken(GetCurrentThread(),
202                          grfDesiredAccessToToken,
203                          TRUE, &htok))
204         _err(L"OpenThreadToken");
205     pSSPI->RevertSecurityContext(pServerCtxHandleOut);
206 
207     // clean up
208     pSSPI->FreeCredentialsHandle(&hcredClient);
209     pSSPI->FreeCredentialsHandle(&hcredServer);
210     pSSPI->DeleteSecurityContext(pServerCtxHandleOut);
211     pSSPI->DeleteSecurityContext(pClientCtxHandleOut);
212     
213     return htok;
214 }
215 
216 // here's an example of usage
217 void main() {
218     // use "NTLM" or "Kerberos"
219 
220 //Kerbero需要在加入域或者有域环境下才能正确运行
221     HANDLE htok = _logonUserWithSSPI(L"Kerberos",
222                                      TOKEN_QUERY,
223                                      NULL,
224                                      L"administrator",
225                                      L"!QAZsx");
226     if (htok) {
227         // password is valid!
228         CloseHandle(htok);
229     }
230 }
231 
232 
原文地址:https://www.cnblogs.com/ahuo/p/1767293.html