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 keyvalwhere gsslibkeywords
[] = {
22 { "gssapi32", 0, -1, -1 },
23 { "sspi", 1, -1, -1 },
24 { "custom", 2, -1, -1 },
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(Conf
*conf
)
72 struct ssh_gss_liblist
*list
= snew(struct ssh_gss_liblist
);
75 list
->libraries
= snewn(3, struct ssh_gss_library
);
78 /* MIT Kerberos GSSAPI implementation */
79 /* TODO: For 64-bit builds, check for gssapi64.dll */
81 if (RegOpenKey(HKEY_LOCAL_MACHINE
, "SOFTWARE\\MIT\\Kerberos", ®key
)
87 /* Find out the string length */
88 ret
= RegQueryValueEx(regkey
, "InstallDir", NULL
, &type
, NULL
, &size
);
90 if (ret
== ERROR_SUCCESS
&& type
== REG_SZ
) {
91 buffer
= snewn(size
+ 20, char);
92 ret
= RegQueryValueEx(regkey
, "InstallDir", NULL
,
93 &type
, buffer
, &size
);
94 if (ret
== ERROR_SUCCESS
&& type
== REG_SZ
) {
95 strcat(buffer
, "\\bin\\gssapi32.dll");
96 module
= LoadLibrary(buffer
);
103 struct ssh_gss_library
*lib
=
104 &list
->libraries
[list
->nlibraries
++];
107 lib
->gsslogmsg
= "Using GSSAPI from GSSAPI32.DLL";
108 lib
->handle
= (void *)module
;
110 #define BIND_GSS_FN(name) \
111 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
113 BIND_GSS_FN(delete_sec_context
);
114 BIND_GSS_FN(display_status
);
115 BIND_GSS_FN(get_mic
);
116 BIND_GSS_FN(import_name
);
117 BIND_GSS_FN(init_sec_context
);
118 BIND_GSS_FN(release_buffer
);
119 BIND_GSS_FN(release_cred
);
120 BIND_GSS_FN(release_name
);
124 ssh_gssapi_bind_fns(lib
);
127 /* Microsoft SSPI Implementation */
128 module
= load_system32_dll("secur32.dll");
130 struct ssh_gss_library
*lib
=
131 &list
->libraries
[list
->nlibraries
++];
134 lib
->gsslogmsg
= "Using SSPI from SECUR32.DLL";
135 lib
->handle
= (void *)module
;
137 GET_WINDOWS_FUNCTION(module
, AcquireCredentialsHandleA
);
138 GET_WINDOWS_FUNCTION(module
, InitializeSecurityContextA
);
139 GET_WINDOWS_FUNCTION(module
, FreeContextBuffer
);
140 GET_WINDOWS_FUNCTION(module
, FreeCredentialsHandle
);
141 GET_WINDOWS_FUNCTION(module
, DeleteSecurityContext
);
142 GET_WINDOWS_FUNCTION(module
, QueryContextAttributesA
);
143 GET_WINDOWS_FUNCTION(module
, MakeSignature
);
145 ssh_sspi_bind_fns(lib
);
152 path
= conf_get_filename(conf
, CONF_ssh_gss_custom
)->path
;
154 module
= LoadLibrary(path
);
157 struct ssh_gss_library
*lib
=
158 &list
->libraries
[list
->nlibraries
++];
161 lib
->gsslogmsg
= dupprintf("Using GSSAPI from user-specified"
162 " library '%s'", path
);
163 lib
->handle
= (void *)module
;
165 #define BIND_GSS_FN(name) \
166 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
168 BIND_GSS_FN(delete_sec_context
);
169 BIND_GSS_FN(display_status
);
170 BIND_GSS_FN(get_mic
);
171 BIND_GSS_FN(import_name
);
172 BIND_GSS_FN(init_sec_context
);
173 BIND_GSS_FN(release_buffer
);
174 BIND_GSS_FN(release_cred
);
175 BIND_GSS_FN(release_name
);
179 ssh_gssapi_bind_fns(lib
);
186 void ssh_gss_cleanup(struct ssh_gss_liblist
*list
)
191 * LoadLibrary and FreeLibrary are defined to employ reference
192 * counting in the case where the same library is repeatedly
193 * loaded, so even in a multiple-sessions-per-process context
194 * (not that we currently expect ever to have such a thing on
195 * Windows) it's safe to naively FreeLibrary everything here
196 * without worrying about destroying it under the feet of
197 * another SSH instance still using it.
199 for (i
= 0; i
< list
->nlibraries
; i
++) {
200 FreeLibrary((HMODULE
)list
->libraries
[i
].handle
);
201 if (list
->libraries
[i
].id
== 2) {
202 /* The 'custom' id involves a dynamically allocated message.
203 * Note that we must cast away the 'const' to free it. */
204 sfree((char *)list
->libraries
[i
].gsslogmsg
);
207 sfree(list
->libraries
);
211 static Ssh_gss_stat
ssh_sspi_indicate_mech(struct ssh_gss_library
*lib
,
214 *mech
= gss_mech_krb5
;
219 static Ssh_gss_stat
ssh_sspi_import_name(struct ssh_gss_library
*lib
,
220 char *host
, Ssh_gss_name
*srv_name
)
225 if (host
== NULL
) return SSH_GSS_FAILURE
;
227 /* copy it into form host/FQDN */
228 pStr
= dupcat("host/", host
, NULL
);
230 *srv_name
= (Ssh_gss_name
) pStr
;
235 static Ssh_gss_stat
ssh_sspi_acquire_cred(struct ssh_gss_library
*lib
,
238 winSsh_gss_ctx
*winctx
= snew(winSsh_gss_ctx
);
239 memset(winctx
, 0, sizeof(winSsh_gss_ctx
));
241 /* prepare our "wrapper" structure */
242 winctx
->maj_stat
= winctx
->min_stat
= SEC_E_OK
;
243 winctx
->context_handle
= NULL
;
245 /* Specifying no principal name here means use the credentials of
246 the current logged-in user */
248 winctx
->maj_stat
= p_AcquireCredentialsHandleA(NULL
,
250 SECPKG_CRED_OUTBOUND
,
255 &winctx
->cred_handle
,
258 if (winctx
->maj_stat
!= SEC_E_OK
) return SSH_GSS_FAILURE
;
260 *ctx
= (Ssh_gss_ctx
) winctx
;
265 static Ssh_gss_stat
ssh_sspi_init_sec_context(struct ssh_gss_library
*lib
,
267 Ssh_gss_name srv_name
,
269 Ssh_gss_buf
*recv_tok
,
270 Ssh_gss_buf
*send_tok
)
272 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
273 SecBuffer wsend_tok
= {send_tok
->length
,SECBUFFER_TOKEN
,send_tok
->value
};
274 SecBuffer wrecv_tok
= {recv_tok
->length
,SECBUFFER_TOKEN
,recv_tok
->value
};
275 SecBufferDesc output_desc
={SECBUFFER_VERSION
,1,&wsend_tok
};
276 SecBufferDesc input_desc
={SECBUFFER_VERSION
,1,&wrecv_tok
};
277 unsigned long flags
=ISC_REQ_MUTUAL_AUTH
|ISC_REQ_REPLAY_DETECT
|
278 ISC_REQ_CONFIDENTIALITY
|ISC_REQ_ALLOCATE_MEMORY
;
279 unsigned long ret_flags
=0;
281 /* check if we have to delegate ... */
282 if (to_deleg
) flags
|= ISC_REQ_DELEGATE
;
283 winctx
->maj_stat
= p_InitializeSecurityContextA(&winctx
->cred_handle
,
284 winctx
->context_handle
,
288 SECURITY_NATIVE_DREP
,
296 /* prepare for the next round */
297 winctx
->context_handle
= &winctx
->context
;
298 send_tok
->value
= wsend_tok
.pvBuffer
;
299 send_tok
->length
= wsend_tok
.cbBuffer
;
301 /* check & return our status */
302 if (winctx
->maj_stat
==SEC_E_OK
) return SSH_GSS_S_COMPLETE
;
303 if (winctx
->maj_stat
==SEC_I_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
305 return SSH_GSS_FAILURE
;
308 static Ssh_gss_stat
ssh_sspi_free_tok(struct ssh_gss_library
*lib
,
309 Ssh_gss_buf
*send_tok
)
312 if (send_tok
== NULL
) return SSH_GSS_FAILURE
;
314 /* free Windows buffer */
315 p_FreeContextBuffer(send_tok
->value
);
316 SSH_GSS_CLEAR_BUF(send_tok
);
321 static Ssh_gss_stat
ssh_sspi_release_cred(struct ssh_gss_library
*lib
,
324 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
327 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
329 /* free Windows data */
330 p_FreeCredentialsHandle(&winctx
->cred_handle
);
331 p_DeleteSecurityContext(&winctx
->context
);
333 /* delete our "wrapper" structure */
335 *ctx
= (Ssh_gss_ctx
) NULL
;
341 static Ssh_gss_stat
ssh_sspi_release_name(struct ssh_gss_library
*lib
,
342 Ssh_gss_name
*srv_name
)
344 char *pStr
= (char *) *srv_name
;
346 if (pStr
== NULL
) return SSH_GSS_FAILURE
;
348 *srv_name
= (Ssh_gss_name
) NULL
;
353 static Ssh_gss_stat
ssh_sspi_display_status(struct ssh_gss_library
*lib
,
354 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
)
356 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
359 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
361 /* decode the error code */
362 switch (winctx
->maj_stat
) {
363 case SEC_E_OK
: msg
="SSPI status OK"; break;
364 case SEC_E_INVALID_HANDLE
: msg
="The handle passed to the function"
367 case SEC_E_TARGET_UNKNOWN
: msg
="The target was not recognized."; break;
368 case SEC_E_LOGON_DENIED
: msg
="The logon failed."; break;
369 case SEC_E_INTERNAL_ERROR
: msg
="The Local Security Authority cannot"
372 case SEC_E_NO_CREDENTIALS
: msg
="No credentials are available in the"
373 " security package.";
375 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
376 msg
="No authority could be contacted for authentication."
377 "The domain name of the authenticating party could be wrong,"
378 " the domain could be unreachable, or there might have been"
379 " a trust relationship failure.";
381 case SEC_E_INSUFFICIENT_MEMORY
:
382 msg
="One or more of the SecBufferDesc structures passed as"
383 " an OUT parameter has a buffer that is too small.";
385 case SEC_E_INVALID_TOKEN
:
386 msg
="The error is due to a malformed input token, such as a"
387 " token corrupted in transit, a token"
388 " of incorrect size, or a token passed into the wrong"
389 " security package. Passing a token to"
390 " the wrong package can happen if client and server did not"
391 " negotiate the proper security package.";
394 msg
= "Internal SSPI error";
398 buf
->value
= dupstr(msg
);
399 buf
->length
= strlen(buf
->value
);
404 static Ssh_gss_stat
ssh_sspi_get_mic(struct ssh_gss_library
*lib
,
405 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
408 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
409 SecPkgContext_Sizes ContextSizes
;
410 SecBufferDesc InputBufferDescriptor
;
411 SecBuffer InputSecurityToken
[2];
413 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
415 winctx
->maj_stat
= 0;
417 memset(&ContextSizes
, 0, sizeof(ContextSizes
));
419 winctx
->maj_stat
= p_QueryContextAttributesA(&winctx
->context
,
423 if (winctx
->maj_stat
!= SEC_E_OK
||
424 ContextSizes
.cbMaxSignature
== 0)
425 return winctx
->maj_stat
;
427 InputBufferDescriptor
.cBuffers
= 2;
428 InputBufferDescriptor
.pBuffers
= InputSecurityToken
;
429 InputBufferDescriptor
.ulVersion
= SECBUFFER_VERSION
;
430 InputSecurityToken
[0].BufferType
= SECBUFFER_DATA
;
431 InputSecurityToken
[0].cbBuffer
= buf
->length
;
432 InputSecurityToken
[0].pvBuffer
= buf
->value
;
433 InputSecurityToken
[1].BufferType
= SECBUFFER_TOKEN
;
434 InputSecurityToken
[1].cbBuffer
= ContextSizes
.cbMaxSignature
;
435 InputSecurityToken
[1].pvBuffer
= snewn(ContextSizes
.cbMaxSignature
, char);
437 winctx
->maj_stat
= p_MakeSignature(&winctx
->context
,
439 &InputBufferDescriptor
,
442 if (winctx
->maj_stat
== SEC_E_OK
) {
443 hash
->length
= InputSecurityToken
[1].cbBuffer
;
444 hash
->value
= InputSecurityToken
[1].pvBuffer
;
447 return winctx
->maj_stat
;
450 static Ssh_gss_stat
ssh_sspi_free_mic(struct ssh_gss_library
*lib
,
457 static void ssh_sspi_bind_fns(struct ssh_gss_library
*lib
)
459 lib
->indicate_mech
= ssh_sspi_indicate_mech
;
460 lib
->import_name
= ssh_sspi_import_name
;
461 lib
->release_name
= ssh_sspi_release_name
;
462 lib
->init_sec_context
= ssh_sspi_init_sec_context
;
463 lib
->free_tok
= ssh_sspi_free_tok
;
464 lib
->acquire_cred
= ssh_sspi_acquire_cred
;
465 lib
->release_cred
= ssh_sspi_release_cred
;
466 lib
->get_mic
= ssh_sspi_get_mic
;
467 lib
->free_mic
= ssh_sspi_free_mic
;
468 lib
->display_status
= ssh_sspi_display_status
;
473 /* Dummy function so this source file defines something if NO_GSSAPI
476 void ssh_gss_init(void)