13 /* Windows code to set up the GSSAPI library list. */
15 struct ssh_gss_library ssh_gss_libraries
[2];
16 int n_ssh_gss_libraries
= 0;
17 static int initialised
= FALSE
;
19 const int ngsslibs
= 2;
20 const char *const gsslibnames
[2] = {
21 "GSSAPI32.DLL (MIT Kerberos)",
22 "SECUR32.DLL (Microsoft SSPI)",
24 const struct keyval gsslibkeywords
[] = {
29 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
30 AcquireCredentialsHandleA
,
31 (SEC_CHAR
*, SEC_CHAR
*, ULONG
, PLUID
,
32 PVOID
, SEC_GET_KEY_FN
, PVOID
, PCredHandle
, PTimeStamp
));
33 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
34 InitializeSecurityContextA
,
35 (PCredHandle
, PCtxtHandle
, SEC_CHAR
*, ULONG
, ULONG
,
36 ULONG
, PSecBufferDesc
, ULONG
, PCtxtHandle
,
37 PSecBufferDesc
, PULONG
, PTimeStamp
));
38 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
41 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
42 FreeCredentialsHandle
,
44 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
45 DeleteSecurityContext
,
47 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
48 QueryContextAttributesA
,
49 (PCtxtHandle
, ULONG
, PVOID
));
50 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
52 (PCtxtHandle
, ULONG
, PSecBufferDesc
, ULONG
));
54 typedef struct winSsh_gss_ctx
{
55 unsigned long maj_stat
;
56 unsigned long min_stat
;
57 CredHandle cred_handle
;
59 PCtxtHandle context_handle
;
64 const Ssh_gss_buf gss_mech_krb5
={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
66 const char *gsslogmsg
= NULL
;
68 static void ssh_sspi_bind_fns(struct ssh_gss_library
*lib
);
70 void ssh_gss_init(void)
74 if (initialised
) return;
77 /* MIT Kerberos GSSAPI implementation */
78 /* TODO: For 64-bit builds, check for gssapi64.dll */
79 module
= LoadLibrary("gssapi32.dll");
81 struct ssh_gss_library
*lib
=
82 &ssh_gss_libraries
[n_ssh_gss_libraries
++];
85 lib
->gsslogmsg
= "Using GSSAPI from GSSAPI32.DLL";
87 #define BIND_GSS_FN(name) \
88 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
90 BIND_GSS_FN(delete_sec_context
);
91 BIND_GSS_FN(display_status
);
93 BIND_GSS_FN(import_name
);
94 BIND_GSS_FN(init_sec_context
);
95 BIND_GSS_FN(release_buffer
);
96 BIND_GSS_FN(release_cred
);
97 BIND_GSS_FN(release_name
);
101 ssh_gssapi_bind_fns(lib
);
104 /* Microsoft SSPI Implementation */
105 module
= load_system32_dll("secur32.dll");
107 struct ssh_gss_library
*lib
=
108 &ssh_gss_libraries
[n_ssh_gss_libraries
++];
111 lib
->gsslogmsg
= "Using SSPI from SECUR32.DLL";
113 GET_WINDOWS_FUNCTION(module
, AcquireCredentialsHandleA
);
114 GET_WINDOWS_FUNCTION(module
, InitializeSecurityContextA
);
115 GET_WINDOWS_FUNCTION(module
, FreeContextBuffer
);
116 GET_WINDOWS_FUNCTION(module
, FreeCredentialsHandle
);
117 GET_WINDOWS_FUNCTION(module
, DeleteSecurityContext
);
118 GET_WINDOWS_FUNCTION(module
, QueryContextAttributesA
);
119 GET_WINDOWS_FUNCTION(module
, MakeSignature
);
121 ssh_sspi_bind_fns(lib
);
125 static Ssh_gss_stat
ssh_sspi_indicate_mech(struct ssh_gss_library
*lib
,
128 *mech
= gss_mech_krb5
;
133 static Ssh_gss_stat
ssh_sspi_import_name(struct ssh_gss_library
*lib
,
134 char *host
, Ssh_gss_name
*srv_name
)
139 if (host
== NULL
) return SSH_GSS_FAILURE
;
141 /* copy it into form host/FQDN */
142 pStr
= dupcat("host/", host
, NULL
);
144 *srv_name
= (Ssh_gss_name
) pStr
;
149 static Ssh_gss_stat
ssh_sspi_acquire_cred(struct ssh_gss_library
*lib
,
152 winSsh_gss_ctx
*winctx
= snew(winSsh_gss_ctx
);
153 memset(winctx
, 0, sizeof(winSsh_gss_ctx
));
155 /* prepare our "wrapper" structure */
156 winctx
->maj_stat
= winctx
->min_stat
= SEC_E_OK
;
157 winctx
->context_handle
= NULL
;
159 /* Specifying no principal name here means use the credentials of
160 the current logged-in user */
162 winctx
->maj_stat
= p_AcquireCredentialsHandleA(NULL
,
164 SECPKG_CRED_OUTBOUND
,
169 &winctx
->cred_handle
,
172 if (winctx
->maj_stat
!= SEC_E_OK
) return SSH_GSS_FAILURE
;
174 *ctx
= (Ssh_gss_ctx
) winctx
;
179 static Ssh_gss_stat
ssh_sspi_init_sec_context(struct ssh_gss_library
*lib
,
181 Ssh_gss_name srv_name
,
183 Ssh_gss_buf
*recv_tok
,
184 Ssh_gss_buf
*send_tok
)
186 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
187 SecBuffer wsend_tok
= {send_tok
->length
,SECBUFFER_TOKEN
,send_tok
->value
};
188 SecBuffer wrecv_tok
= {recv_tok
->length
,SECBUFFER_TOKEN
,recv_tok
->value
};
189 SecBufferDesc output_desc
={SECBUFFER_VERSION
,1,&wsend_tok
};
190 SecBufferDesc input_desc
={SECBUFFER_VERSION
,1,&wrecv_tok
};
191 unsigned long flags
=ISC_REQ_MUTUAL_AUTH
|ISC_REQ_REPLAY_DETECT
|
192 ISC_REQ_CONFIDENTIALITY
|ISC_REQ_ALLOCATE_MEMORY
;
193 unsigned long ret_flags
=0;
195 /* check if we have to delegate ... */
196 if (to_deleg
) flags
|= ISC_REQ_DELEGATE
;
197 winctx
->maj_stat
= p_InitializeSecurityContextA(&winctx
->cred_handle
,
198 winctx
->context_handle
,
202 SECURITY_NATIVE_DREP
,
210 /* prepare for the next round */
211 winctx
->context_handle
= &winctx
->context
;
212 send_tok
->value
= wsend_tok
.pvBuffer
;
213 send_tok
->length
= wsend_tok
.cbBuffer
;
215 /* check & return our status */
216 if (winctx
->maj_stat
==SEC_E_OK
) return SSH_GSS_S_COMPLETE
;
217 if (winctx
->maj_stat
==SEC_I_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
219 return SSH_GSS_FAILURE
;
222 static Ssh_gss_stat
ssh_sspi_free_tok(struct ssh_gss_library
*lib
,
223 Ssh_gss_buf
*send_tok
)
226 if (send_tok
== NULL
) return SSH_GSS_FAILURE
;
228 /* free Windows buffer */
229 p_FreeContextBuffer(send_tok
->value
);
230 SSH_GSS_CLEAR_BUF(send_tok
);
235 static Ssh_gss_stat
ssh_sspi_release_cred(struct ssh_gss_library
*lib
,
238 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
241 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
243 /* free Windows data */
244 p_FreeCredentialsHandle(&winctx
->cred_handle
);
245 p_DeleteSecurityContext(&winctx
->context
);
247 /* delete our "wrapper" structure */
249 *ctx
= (Ssh_gss_ctx
) NULL
;
255 static Ssh_gss_stat
ssh_sspi_release_name(struct ssh_gss_library
*lib
,
256 Ssh_gss_name
*srv_name
)
258 char *pStr
= (char *) *srv_name
;
260 if (pStr
== NULL
) return SSH_GSS_FAILURE
;
262 *srv_name
= (Ssh_gss_name
) NULL
;
267 static Ssh_gss_stat
ssh_sspi_display_status(struct ssh_gss_library
*lib
,
268 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
)
270 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
273 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
275 /* decode the error code */
276 switch (winctx
->maj_stat
) {
277 case SEC_E_OK
: msg
="SSPI status OK"; break;
278 case SEC_E_INVALID_HANDLE
: msg
="The handle passed to the function"
281 case SEC_E_TARGET_UNKNOWN
: msg
="The target was not recognized."; break;
282 case SEC_E_LOGON_DENIED
: msg
="The logon failed."; break;
283 case SEC_E_INTERNAL_ERROR
: msg
="The Local Security Authority cannot"
286 case SEC_E_NO_CREDENTIALS
: msg
="No credentials are available in the"
287 " security package.";
289 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
290 msg
="No authority could be contacted for authentication."
291 "The domain name of the authenticating party could be wrong,"
292 " the domain could be unreachable, or there might have been"
293 " a trust relationship failure.";
295 case SEC_E_INSUFFICIENT_MEMORY
:
296 msg
="One or more of the SecBufferDesc structures passed as"
297 " an OUT parameter has a buffer that is too small.";
299 case SEC_E_INVALID_TOKEN
:
300 msg
="The error is due to a malformed input token, such as a"
301 " token corrupted in transit, a token"
302 " of incorrect size, or a token passed into the wrong"
303 " security package. Passing a token to"
304 " the wrong package can happen if client and server did not"
305 " negotiate the proper security package.";
308 msg
= "Internal SSPI error";
312 buf
->value
= dupstr(msg
);
313 buf
->length
= strlen(buf
->value
);
318 static Ssh_gss_stat
ssh_sspi_get_mic(struct ssh_gss_library
*lib
,
319 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
322 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
323 SecPkgContext_Sizes ContextSizes
;
324 SecBufferDesc InputBufferDescriptor
;
325 SecBuffer InputSecurityToken
[2];
327 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
329 winctx
->maj_stat
= 0;
331 memset(&ContextSizes
, 0, sizeof(ContextSizes
));
333 winctx
->maj_stat
= p_QueryContextAttributesA(&winctx
->context
,
337 if (winctx
->maj_stat
!= SEC_E_OK
||
338 ContextSizes
.cbMaxSignature
== 0)
339 return winctx
->maj_stat
;
341 InputBufferDescriptor
.cBuffers
= 2;
342 InputBufferDescriptor
.pBuffers
= InputSecurityToken
;
343 InputBufferDescriptor
.ulVersion
= SECBUFFER_VERSION
;
344 InputSecurityToken
[0].BufferType
= SECBUFFER_DATA
;
345 InputSecurityToken
[0].cbBuffer
= buf
->length
;
346 InputSecurityToken
[0].pvBuffer
= buf
->value
;
347 InputSecurityToken
[1].BufferType
= SECBUFFER_TOKEN
;
348 InputSecurityToken
[1].cbBuffer
= ContextSizes
.cbMaxSignature
;
349 InputSecurityToken
[1].pvBuffer
= snewn(ContextSizes
.cbMaxSignature
, char);
351 winctx
->maj_stat
= p_MakeSignature(&winctx
->context
,
353 &InputBufferDescriptor
,
356 if (winctx
->maj_stat
== SEC_E_OK
) {
357 hash
->length
= InputSecurityToken
[1].cbBuffer
;
358 hash
->value
= InputSecurityToken
[1].pvBuffer
;
361 return winctx
->maj_stat
;
364 static Ssh_gss_stat
ssh_sspi_free_mic(struct ssh_gss_library
*lib
,
371 static void ssh_sspi_bind_fns(struct ssh_gss_library
*lib
)
373 lib
->indicate_mech
= ssh_sspi_indicate_mech
;
374 lib
->import_name
= ssh_sspi_import_name
;
375 lib
->release_name
= ssh_sspi_release_name
;
376 lib
->init_sec_context
= ssh_sspi_init_sec_context
;
377 lib
->free_tok
= ssh_sspi_free_tok
;
378 lib
->acquire_cred
= ssh_sspi_acquire_cred
;
379 lib
->release_cred
= ssh_sspi_release_cred
;
380 lib
->get_mic
= ssh_sspi_get_mic
;
381 lib
->free_mic
= ssh_sspi_free_mic
;
382 lib
->display_status
= ssh_sspi_display_status
;
387 /* Dummy function so this source file defines something if NO_GSSAPI
390 void ssh_gss_init(void)