代码
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 0 , 0
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 0 , 0 ,
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 0 , 0 , 0 , 0 ,
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
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 0 , 0
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 0 , 0 ,
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 0 , 0 , 0 , 0 ,
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