14 /* Windows code to set up the GSSAPI library list. */
16 const int ngsslibs = 3;
17 const char *const gsslibnames[3] = {
18 "MIT Kerberos GSSAPI32.DLL",
19 "Microsoft SSPI SECUR32.DLL",
20 "User-specified GSSAPI DLL",
22 const struct keyvalwhere gsslibkeywords[] = {
23 { "gssapi32", 0, -1, -1 },
24 { "sspi", 1, -1, -1 },
25 { "custom", 2, -1, -1 },
28 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
29 AcquireCredentialsHandleA,
30 (SEC_CHAR *, SEC_CHAR *, ULONG, PLUID,
31 PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp));
32 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
33 InitializeSecurityContextA,
34 (PCredHandle, PCtxtHandle, SEC_CHAR *, ULONG, ULONG,
35 ULONG, PSecBufferDesc, ULONG, PCtxtHandle,
36 PSecBufferDesc, PULONG, PTimeStamp));
37 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
40 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
41 FreeCredentialsHandle,
43 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
44 DeleteSecurityContext,
46 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
47 QueryContextAttributesA,
48 (PCtxtHandle, ULONG, PVOID));
49 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
51 (PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
53 typedef struct winSsh_gss_ctx {
54 unsigned long maj_stat;
55 unsigned long min_stat;
56 CredHandle cred_handle;
58 PCtxtHandle context_handle;
63 const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
65 const char *gsslogmsg = NULL;
67 static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
69 struct ssh_gss_liblist *ssh_gss_setup(Conf *conf)
73 struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist);
76 list->libraries = snewn(3, struct ssh_gss_library);
79 /* MIT Kerberos GSSAPI implementation */
80 /* TODO: For 64-bit builds, check for gssapi64.dll */
82 if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", ®key)
88 /* Find out the string length, in bytes, for a wchar_t */
89 ret = RegQueryValueExW(regkey, L"InstallDir", NULL, &type, NULL, &size);
90 if (ret == ERROR_SUCCESS && type == REG_SZ) {
91 buffer = snewn(size + 20, char);
92 ret = RegQueryValueExW(regkey, L"InstallDir", NULL,
93 &type, (LPBYTE)buffer, &size);
94 if (ret == ERROR_SUCCESS && type == REG_SZ) {
95 wcscat(buffer, L"\\bin\\");
96 dll_hijacking_protection_add_path(buffer);
98 module = LoadLibrary("gssapi32.dll");
100 /* module = LoadLibrary("gssapi64.dll"); */
108 struct ssh_gss_library *lib =
109 &list->libraries[list->nlibraries++];
112 lib->gsslogmsg = "Using GSSAPI from GSSAPI32.DLL";
113 lib->handle = (void *)module;
115 #define BIND_GSS_FN(name) \
116 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
118 BIND_GSS_FN(delete_sec_context);
119 BIND_GSS_FN(display_status);
120 BIND_GSS_FN(get_mic);
121 BIND_GSS_FN(import_name);
122 BIND_GSS_FN(init_sec_context);
123 BIND_GSS_FN(release_buffer);
124 BIND_GSS_FN(release_cred);
125 BIND_GSS_FN(release_name);
129 ssh_gssapi_bind_fns(lib);
132 /* Microsoft SSPI Implementation */
133 module = load_system32_dll("secur32.dll");
135 struct ssh_gss_library *lib =
136 &list->libraries[list->nlibraries++];
139 lib->gsslogmsg = "Using SSPI from SECUR32.DLL";
140 lib->handle = (void *)module;
142 GET_WINDOWS_FUNCTION(module, AcquireCredentialsHandleA);
143 GET_WINDOWS_FUNCTION(module, InitializeSecurityContextA);
144 GET_WINDOWS_FUNCTION(module, FreeContextBuffer);
145 GET_WINDOWS_FUNCTION(module, FreeCredentialsHandle);
146 GET_WINDOWS_FUNCTION(module, DeleteSecurityContext);
147 GET_WINDOWS_FUNCTION(module, QueryContextAttributesA);
148 GET_WINDOWS_FUNCTION(module, MakeSignature);
150 ssh_sspi_bind_fns(lib);
157 path = conf_get_filename(conf, CONF_ssh_gss_custom)->path;
159 module = LoadLibrary(path);
162 struct ssh_gss_library *lib =
163 &list->libraries[list->nlibraries++];
166 lib->gsslogmsg = dupprintf("Using GSSAPI from user-specified"
167 " library '%s'", path);
168 lib->handle = (void *)module;
170 #define BIND_GSS_FN(name) \
171 lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
173 BIND_GSS_FN(delete_sec_context);
174 BIND_GSS_FN(display_status);
175 BIND_GSS_FN(get_mic);
176 BIND_GSS_FN(import_name);
177 BIND_GSS_FN(init_sec_context);
178 BIND_GSS_FN(release_buffer);
179 BIND_GSS_FN(release_cred);
180 BIND_GSS_FN(release_name);
184 ssh_gssapi_bind_fns(lib);
191 void ssh_gss_cleanup(struct ssh_gss_liblist *list)
196 * LoadLibrary and FreeLibrary are defined to employ reference
197 * counting in the case where the same library is repeatedly
198 * loaded, so even in a multiple-sessions-per-process context
199 * (not that we currently expect ever to have such a thing on
200 * Windows) it's safe to naively FreeLibrary everything here
201 * without worrying about destroying it under the feet of
202 * another SSH instance still using it.
204 for (i = 0; i < list->nlibraries; i++) {
205 FreeLibrary((HMODULE)list->libraries[i].handle);
206 if (list->libraries[i].id == 2) {
207 /* The 'custom' id involves a dynamically allocated message.
208 * Note that we must cast away the 'const' to free it. */
209 sfree((char *)list->libraries[i].gsslogmsg);
212 sfree(list->libraries);
216 static Ssh_gss_stat ssh_sspi_indicate_mech(struct ssh_gss_library *lib,
219 *mech = gss_mech_krb5;
224 static Ssh_gss_stat ssh_sspi_import_name(struct ssh_gss_library *lib,
225 char *host, Ssh_gss_name *srv_name)
230 if (host == NULL) return SSH_GSS_FAILURE;
232 /* copy it into form host/FQDN */
233 pStr = dupcat("host/", host, NULL);
235 *srv_name = (Ssh_gss_name) pStr;
240 static Ssh_gss_stat ssh_sspi_acquire_cred(struct ssh_gss_library *lib,
243 winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
244 memset(winctx, 0, sizeof(winSsh_gss_ctx));
246 /* prepare our "wrapper" structure */
247 winctx->maj_stat = winctx->min_stat = SEC_E_OK;
248 winctx->context_handle = NULL;
250 /* Specifying no principal name here means use the credentials of
251 the current logged-in user */
253 winctx->maj_stat = p_AcquireCredentialsHandleA(NULL,
255 SECPKG_CRED_OUTBOUND,
260 &winctx->cred_handle,
263 if (winctx->maj_stat != SEC_E_OK) return SSH_GSS_FAILURE;
265 *ctx = (Ssh_gss_ctx) winctx;
270 static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
272 Ssh_gss_name srv_name,
274 Ssh_gss_buf *recv_tok,
275 Ssh_gss_buf *send_tok)
277 winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
278 SecBuffer wsend_tok = {send_tok->length,SECBUFFER_TOKEN,send_tok->value};
279 SecBuffer wrecv_tok = {recv_tok->length,SECBUFFER_TOKEN,recv_tok->value};
280 SecBufferDesc output_desc={SECBUFFER_VERSION,1,&wsend_tok};
281 SecBufferDesc input_desc ={SECBUFFER_VERSION,1,&wrecv_tok};
282 unsigned long flags=ISC_REQ_MUTUAL_AUTH|ISC_REQ_REPLAY_DETECT|
283 ISC_REQ_CONFIDENTIALITY|ISC_REQ_ALLOCATE_MEMORY;
284 unsigned long ret_flags=0;
286 /* check if we have to delegate ... */
287 if (to_deleg) flags |= ISC_REQ_DELEGATE;
288 winctx->maj_stat = p_InitializeSecurityContextA(&winctx->cred_handle,
289 winctx->context_handle,
293 SECURITY_NATIVE_DREP,
301 /* prepare for the next round */
302 winctx->context_handle = &winctx->context;
303 send_tok->value = wsend_tok.pvBuffer;
304 send_tok->length = wsend_tok.cbBuffer;
306 /* check & return our status */
307 if (winctx->maj_stat==SEC_E_OK) return SSH_GSS_S_COMPLETE;
308 if (winctx->maj_stat==SEC_I_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED;
310 return SSH_GSS_FAILURE;
313 static Ssh_gss_stat ssh_sspi_free_tok(struct ssh_gss_library *lib,
314 Ssh_gss_buf *send_tok)
317 if (send_tok == NULL) return SSH_GSS_FAILURE;
319 /* free Windows buffer */
320 p_FreeContextBuffer(send_tok->value);
321 SSH_GSS_CLEAR_BUF(send_tok);
326 static Ssh_gss_stat ssh_sspi_release_cred(struct ssh_gss_library *lib,
329 winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) *ctx;
332 if (winctx == NULL) return SSH_GSS_FAILURE;
334 /* free Windows data */
335 p_FreeCredentialsHandle(&winctx->cred_handle);
336 p_DeleteSecurityContext(&winctx->context);
338 /* delete our "wrapper" structure */
340 *ctx = (Ssh_gss_ctx) NULL;
346 static Ssh_gss_stat ssh_sspi_release_name(struct ssh_gss_library *lib,
347 Ssh_gss_name *srv_name)
349 char *pStr= (char *) *srv_name;
351 if (pStr == NULL) return SSH_GSS_FAILURE;
353 *srv_name = (Ssh_gss_name) NULL;
358 static Ssh_gss_stat ssh_sspi_display_status(struct ssh_gss_library *lib,
359 Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
361 winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) ctx;
364 if (winctx == NULL) return SSH_GSS_FAILURE;
366 /* decode the error code */
367 switch (winctx->maj_stat) {
368 case SEC_E_OK: msg="SSPI status OK"; break;
369 case SEC_E_INVALID_HANDLE: msg="The handle passed to the function"
372 case SEC_E_TARGET_UNKNOWN: msg="The target was not recognized."; break;
373 case SEC_E_LOGON_DENIED: msg="The logon failed."; break;
374 case SEC_E_INTERNAL_ERROR: msg="The Local Security Authority cannot"
377 case SEC_E_NO_CREDENTIALS: msg="No credentials are available in the"
378 " security package.";
380 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
381 msg="No authority could be contacted for authentication."
382 "The domain name of the authenticating party could be wrong,"
383 " the domain could be unreachable, or there might have been"
384 " a trust relationship failure.";
386 case SEC_E_INSUFFICIENT_MEMORY:
387 msg="One or more of the SecBufferDesc structures passed as"
388 " an OUT parameter has a buffer that is too small.";
390 case SEC_E_INVALID_TOKEN:
391 msg="The error is due to a malformed input token, such as a"
392 " token corrupted in transit, a token"
393 " of incorrect size, or a token passed into the wrong"
394 " security package. Passing a token to"
395 " the wrong package can happen if client and server did not"
396 " negotiate the proper security package.";
399 msg = "Internal SSPI error";
403 buf->value = dupstr(msg);
404 buf->length = strlen(buf->value);
409 static Ssh_gss_stat ssh_sspi_get_mic(struct ssh_gss_library *lib,
410 Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
413 winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
414 SecPkgContext_Sizes ContextSizes;
415 SecBufferDesc InputBufferDescriptor;
416 SecBuffer InputSecurityToken[2];
418 if (winctx == NULL) return SSH_GSS_FAILURE;
420 winctx->maj_stat = 0;
422 memset(&ContextSizes, 0, sizeof(ContextSizes));
424 winctx->maj_stat = p_QueryContextAttributesA(&winctx->context,
428 if (winctx->maj_stat != SEC_E_OK ||
429 ContextSizes.cbMaxSignature == 0)
430 return winctx->maj_stat;
432 InputBufferDescriptor.cBuffers = 2;
433 InputBufferDescriptor.pBuffers = InputSecurityToken;
434 InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
435 InputSecurityToken[0].BufferType = SECBUFFER_DATA;
436 InputSecurityToken[0].cbBuffer = buf->length;
437 InputSecurityToken[0].pvBuffer = buf->value;
438 InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
439 InputSecurityToken[1].cbBuffer = ContextSizes.cbMaxSignature;
440 InputSecurityToken[1].pvBuffer = snewn(ContextSizes.cbMaxSignature, char);
442 winctx->maj_stat = p_MakeSignature(&winctx->context,
444 &InputBufferDescriptor,
447 if (winctx->maj_stat == SEC_E_OK) {
448 hash->length = InputSecurityToken[1].cbBuffer;
449 hash->value = InputSecurityToken[1].pvBuffer;
452 return winctx->maj_stat;
455 static Ssh_gss_stat ssh_sspi_free_mic(struct ssh_gss_library *lib,
462 static void ssh_sspi_bind_fns(struct ssh_gss_library *lib)
464 lib->indicate_mech = ssh_sspi_indicate_mech;
465 lib->import_name = ssh_sspi_import_name;
466 lib->release_name = ssh_sspi_release_name;
467 lib->init_sec_context = ssh_sspi_init_sec_context;
468 lib->free_tok = ssh_sspi_free_tok;
469 lib->acquire_cred = ssh_sspi_acquire_cred;
470 lib->release_cred = ssh_sspi_release_cred;
471 lib->get_mic = ssh_sspi_get_mic;
472 lib->free_mic = ssh_sspi_free_mic;
473 lib->display_status = ssh_sspi_display_status;
478 /* Dummy function so this source file defines something if NO_GSSAPI
481 void ssh_gss_init(void)