13 /* Windows code to set up the GSSAPI library list. */
15 const int ngsslibs
= 3;
16 const char *const gsslibnames
[3] = {
17 "MIT Kerberos GSSAPI32.DLL",
18 "Microsoft SSPI SECUR32.DLL",
19 "User-specified GSSAPI DLL",
21 const struct keyval gsslibkeywords
[] = {
27 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
28 AcquireCredentialsHandleA
,
29 (SEC_CHAR
*, SEC_CHAR
*, ULONG
, PLUID
,
30 PVOID
, SEC_GET_KEY_FN
, PVOID
, PCredHandle
, PTimeStamp
));
31 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
32 InitializeSecurityContextA
,
33 (PCredHandle
, PCtxtHandle
, SEC_CHAR
*, ULONG
, ULONG
,
34 ULONG
, PSecBufferDesc
, ULONG
, PCtxtHandle
,
35 PSecBufferDesc
, PULONG
, PTimeStamp
));
36 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
39 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
40 FreeCredentialsHandle
,
42 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
43 DeleteSecurityContext
,
45 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
46 QueryContextAttributesA
,
47 (PCtxtHandle
, ULONG
, PVOID
));
48 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS
,
50 (PCtxtHandle
, ULONG
, PSecBufferDesc
, ULONG
));
52 typedef struct winSsh_gss_ctx
{
53 unsigned long maj_stat
;
54 unsigned long min_stat
;
55 CredHandle cred_handle
;
57 PCtxtHandle context_handle
;
62 const Ssh_gss_buf gss_mech_krb5
={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
64 const char *gsslogmsg
= NULL
;
66 static void ssh_sspi_bind_fns(struct ssh_gss_library
*lib
);
68 struct ssh_gss_liblist
*ssh_gss_setup(const Config
*cfg
)
72 struct ssh_gss_liblist
*list
= snew(struct ssh_gss_liblist
);
74 list
->libraries
= snewn(3, struct ssh_gss_library
);
77 /* MIT Kerberos GSSAPI implementation */
78 /* TODO: For 64-bit builds, check for gssapi64.dll */
80 if (RegOpenKey(HKEY_LOCAL_MACHINE
, "SOFTWARE\\MIT\\Kerberos", ®key
)
86 /* Find out the string length */
87 ret
= RegQueryValueEx(regkey
, "InstallDir", NULL
, &type
, NULL
, &size
);
89 if (ret
== ERROR_SUCCESS
&& type
== REG_SZ
) {
90 buffer
= snewn(size
+ 20, char);
91 ret
= RegQueryValueEx(regkey
, "InstallDir", NULL
,
92 &type
, buffer
, &size
);
93 if (ret
== ERROR_SUCCESS
&& type
== REG_SZ
) {
94 strcat(buffer
, "\\bin\\gssapi32.dll");
95 module
= LoadLibrary(buffer
);
102 struct ssh_gss_library
*lib
=
103 &list
->libraries
[list
->nlibraries
++];
106 lib
->gsslogmsg
= "Using GSSAPI from GSSAPI32.DLL";
107 lib
->handle
= (void *)module
;
109 #define BIND_GSS_FN(name) \
110 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
112 BIND_GSS_FN(delete_sec_context
);
113 BIND_GSS_FN(display_status
);
114 BIND_GSS_FN(get_mic
);
115 BIND_GSS_FN(import_name
);
116 BIND_GSS_FN(init_sec_context
);
117 BIND_GSS_FN(release_buffer
);
118 BIND_GSS_FN(release_cred
);
119 BIND_GSS_FN(release_name
);
123 ssh_gssapi_bind_fns(lib
);
126 /* Microsoft SSPI Implementation */
127 module
= load_system32_dll("secur32.dll");
129 struct ssh_gss_library
*lib
=
130 &list
->libraries
[list
->nlibraries
++];
133 lib
->gsslogmsg
= "Using SSPI from SECUR32.DLL";
134 lib
->handle
= (void *)module
;
136 GET_WINDOWS_FUNCTION(module
, AcquireCredentialsHandleA
);
137 GET_WINDOWS_FUNCTION(module
, InitializeSecurityContextA
);
138 GET_WINDOWS_FUNCTION(module
, FreeContextBuffer
);
139 GET_WINDOWS_FUNCTION(module
, FreeCredentialsHandle
);
140 GET_WINDOWS_FUNCTION(module
, DeleteSecurityContext
);
141 GET_WINDOWS_FUNCTION(module
, QueryContextAttributesA
);
142 GET_WINDOWS_FUNCTION(module
, MakeSignature
);
144 ssh_sspi_bind_fns(lib
);
151 if (cfg
->ssh_gss_custom
.path
[0]) {
152 module
= LoadLibrary(cfg
->ssh_gss_custom
.path
);
155 struct ssh_gss_library
*lib
=
156 &list
->libraries
[list
->nlibraries
++];
159 lib
->gsslogmsg
= dupprintf("Using GSSAPI from user-specified"
160 " library '%s'", cfg
->ssh_gss_custom
.path
);
161 lib
->handle
= (void *)module
;
163 #define BIND_GSS_FN(name) \
164 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
166 BIND_GSS_FN(delete_sec_context
);
167 BIND_GSS_FN(display_status
);
168 BIND_GSS_FN(get_mic
);
169 BIND_GSS_FN(import_name
);
170 BIND_GSS_FN(init_sec_context
);
171 BIND_GSS_FN(release_buffer
);
172 BIND_GSS_FN(release_cred
);
173 BIND_GSS_FN(release_name
);
177 ssh_gssapi_bind_fns(lib
);
184 void ssh_gss_cleanup(struct ssh_gss_liblist
*list
)
189 * LoadLibrary and FreeLibrary are defined to employ reference
190 * counting in the case where the same library is repeatedly
191 * loaded, so even in a multiple-sessions-per-process context
192 * (not that we currently expect ever to have such a thing on
193 * Windows) it's safe to naively FreeLibrary everything here
194 * without worrying about destroying it under the feet of
195 * another SSH instance still using it.
197 for (i
= 0; i
< list
->nlibraries
; i
++) {
198 FreeLibrary((HMODULE
)list
->libraries
[i
].handle
);
199 if (list
->libraries
[i
].id
== 2) {
200 /* The 'custom' id involves a dynamically allocated message.
201 * Note that we must cast away the 'const' to free it. */
202 sfree((char *)list
->libraries
[i
].gsslogmsg
);
205 sfree(list
->libraries
);
209 static Ssh_gss_stat
ssh_sspi_indicate_mech(struct ssh_gss_library
*lib
,
212 *mech
= gss_mech_krb5
;
217 static Ssh_gss_stat
ssh_sspi_import_name(struct ssh_gss_library
*lib
,
218 char *host
, Ssh_gss_name
*srv_name
)
223 if (host
== NULL
) return SSH_GSS_FAILURE
;
225 /* copy it into form host/FQDN */
226 pStr
= dupcat("host/", host
, NULL
);
228 *srv_name
= (Ssh_gss_name
) pStr
;
233 static Ssh_gss_stat
ssh_sspi_acquire_cred(struct ssh_gss_library
*lib
,
236 winSsh_gss_ctx
*winctx
= snew(winSsh_gss_ctx
);
237 memset(winctx
, 0, sizeof(winSsh_gss_ctx
));
239 /* prepare our "wrapper" structure */
240 winctx
->maj_stat
= winctx
->min_stat
= SEC_E_OK
;
241 winctx
->context_handle
= NULL
;
243 /* Specifying no principal name here means use the credentials of
244 the current logged-in user */
246 winctx
->maj_stat
= p_AcquireCredentialsHandleA(NULL
,
248 SECPKG_CRED_OUTBOUND
,
253 &winctx
->cred_handle
,
256 if (winctx
->maj_stat
!= SEC_E_OK
) return SSH_GSS_FAILURE
;
258 *ctx
= (Ssh_gss_ctx
) winctx
;
263 static Ssh_gss_stat
ssh_sspi_init_sec_context(struct ssh_gss_library
*lib
,
265 Ssh_gss_name srv_name
,
267 Ssh_gss_buf
*recv_tok
,
268 Ssh_gss_buf
*send_tok
)
270 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
271 SecBuffer wsend_tok
= {send_tok
->length
,SECBUFFER_TOKEN
,send_tok
->value
};
272 SecBuffer wrecv_tok
= {recv_tok
->length
,SECBUFFER_TOKEN
,recv_tok
->value
};
273 SecBufferDesc output_desc
={SECBUFFER_VERSION
,1,&wsend_tok
};
274 SecBufferDesc input_desc
={SECBUFFER_VERSION
,1,&wrecv_tok
};
275 unsigned long flags
=ISC_REQ_MUTUAL_AUTH
|ISC_REQ_REPLAY_DETECT
|
276 ISC_REQ_CONFIDENTIALITY
|ISC_REQ_ALLOCATE_MEMORY
;
277 unsigned long ret_flags
=0;
279 /* check if we have to delegate ... */
280 if (to_deleg
) flags
|= ISC_REQ_DELEGATE
;
281 winctx
->maj_stat
= p_InitializeSecurityContextA(&winctx
->cred_handle
,
282 winctx
->context_handle
,
286 SECURITY_NATIVE_DREP
,
294 /* prepare for the next round */
295 winctx
->context_handle
= &winctx
->context
;
296 send_tok
->value
= wsend_tok
.pvBuffer
;
297 send_tok
->length
= wsend_tok
.cbBuffer
;
299 /* check & return our status */
300 if (winctx
->maj_stat
==SEC_E_OK
) return SSH_GSS_S_COMPLETE
;
301 if (winctx
->maj_stat
==SEC_I_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
303 return SSH_GSS_FAILURE
;
306 static Ssh_gss_stat
ssh_sspi_free_tok(struct ssh_gss_library
*lib
,
307 Ssh_gss_buf
*send_tok
)
310 if (send_tok
== NULL
) return SSH_GSS_FAILURE
;
312 /* free Windows buffer */
313 p_FreeContextBuffer(send_tok
->value
);
314 SSH_GSS_CLEAR_BUF(send_tok
);
319 static Ssh_gss_stat
ssh_sspi_release_cred(struct ssh_gss_library
*lib
,
322 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
325 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
327 /* free Windows data */
328 p_FreeCredentialsHandle(&winctx
->cred_handle
);
329 p_DeleteSecurityContext(&winctx
->context
);
331 /* delete our "wrapper" structure */
333 *ctx
= (Ssh_gss_ctx
) NULL
;
339 static Ssh_gss_stat
ssh_sspi_release_name(struct ssh_gss_library
*lib
,
340 Ssh_gss_name
*srv_name
)
342 char *pStr
= (char *) *srv_name
;
344 if (pStr
== NULL
) return SSH_GSS_FAILURE
;
346 *srv_name
= (Ssh_gss_name
) NULL
;
351 static Ssh_gss_stat
ssh_sspi_display_status(struct ssh_gss_library
*lib
,
352 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
)
354 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
357 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
359 /* decode the error code */
360 switch (winctx
->maj_stat
) {
361 case SEC_E_OK
: msg
="SSPI status OK"; break;
362 case SEC_E_INVALID_HANDLE
: msg
="The handle passed to the function"
365 case SEC_E_TARGET_UNKNOWN
: msg
="The target was not recognized."; break;
366 case SEC_E_LOGON_DENIED
: msg
="The logon failed."; break;
367 case SEC_E_INTERNAL_ERROR
: msg
="The Local Security Authority cannot"
370 case SEC_E_NO_CREDENTIALS
: msg
="No credentials are available in the"
371 " security package.";
373 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
374 msg
="No authority could be contacted for authentication."
375 "The domain name of the authenticating party could be wrong,"
376 " the domain could be unreachable, or there might have been"
377 " a trust relationship failure.";
379 case SEC_E_INSUFFICIENT_MEMORY
:
380 msg
="One or more of the SecBufferDesc structures passed as"
381 " an OUT parameter has a buffer that is too small.";
383 case SEC_E_INVALID_TOKEN
:
384 msg
="The error is due to a malformed input token, such as a"
385 " token corrupted in transit, a token"
386 " of incorrect size, or a token passed into the wrong"
387 " security package. Passing a token to"
388 " the wrong package can happen if client and server did not"
389 " negotiate the proper security package.";
392 msg
= "Internal SSPI error";
396 buf
->value
= dupstr(msg
);
397 buf
->length
= strlen(buf
->value
);
402 static Ssh_gss_stat
ssh_sspi_get_mic(struct ssh_gss_library
*lib
,
403 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
406 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
407 SecPkgContext_Sizes ContextSizes
;
408 SecBufferDesc InputBufferDescriptor
;
409 SecBuffer InputSecurityToken
[2];
411 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
413 winctx
->maj_stat
= 0;
415 memset(&ContextSizes
, 0, sizeof(ContextSizes
));
417 winctx
->maj_stat
= p_QueryContextAttributesA(&winctx
->context
,
421 if (winctx
->maj_stat
!= SEC_E_OK
||
422 ContextSizes
.cbMaxSignature
== 0)
423 return winctx
->maj_stat
;
425 InputBufferDescriptor
.cBuffers
= 2;
426 InputBufferDescriptor
.pBuffers
= InputSecurityToken
;
427 InputBufferDescriptor
.ulVersion
= SECBUFFER_VERSION
;
428 InputSecurityToken
[0].BufferType
= SECBUFFER_DATA
;
429 InputSecurityToken
[0].cbBuffer
= buf
->length
;
430 InputSecurityToken
[0].pvBuffer
= buf
->value
;
431 InputSecurityToken
[1].BufferType
= SECBUFFER_TOKEN
;
432 InputSecurityToken
[1].cbBuffer
= ContextSizes
.cbMaxSignature
;
433 InputSecurityToken
[1].pvBuffer
= snewn(ContextSizes
.cbMaxSignature
, char);
435 winctx
->maj_stat
= p_MakeSignature(&winctx
->context
,
437 &InputBufferDescriptor
,
440 if (winctx
->maj_stat
== SEC_E_OK
) {
441 hash
->length
= InputSecurityToken
[1].cbBuffer
;
442 hash
->value
= InputSecurityToken
[1].pvBuffer
;
445 return winctx
->maj_stat
;
448 static Ssh_gss_stat
ssh_sspi_free_mic(struct ssh_gss_library
*lib
,
455 static void ssh_sspi_bind_fns(struct ssh_gss_library
*lib
)
457 lib
->indicate_mech
= ssh_sspi_indicate_mech
;
458 lib
->import_name
= ssh_sspi_import_name
;
459 lib
->release_name
= ssh_sspi_release_name
;
460 lib
->init_sec_context
= ssh_sspi_init_sec_context
;
461 lib
->free_tok
= ssh_sspi_free_tok
;
462 lib
->acquire_cred
= ssh_sspi_acquire_cred
;
463 lib
->release_cred
= ssh_sspi_release_cred
;
464 lib
->get_mic
= ssh_sspi_get_mic
;
465 lib
->free_mic
= ssh_sspi_free_mic
;
466 lib
->display_status
= ssh_sspi_display_status
;
471 /* Dummy function so this source file defines something if NO_GSSAPI
474 void ssh_gss_init(void)